Reputation: 137
I am trying to implement a demosaicing algorithm (interpolation) for a raw image with the Bayer pattern GRBG. The program logic was to use the neighboring pixels to assign the values to R,G and B channels(I have attached the code). I am having a problem for this logic at the border pixels. For example let i be the pixel at (0,0), I need the value of i-1 which is not present in the image. My question is there a possibility to work around this like masking i-1 and the others as 0 without adding an new border of zeros to my existing image.
Any suggestions will be helpful. thanks.
int rows = 256;
int cols = 512;
Mat raw_img(rows, cols, CV_8U); //////////////////////
Mat image(rows, cols, CV_8UC3); // BAYER PATTERN //
cvtColor(image, image, COLOR_BGR2RGB); // G R //
for (int i = 0; i < raw_img.rows; i++) { // B G //
for (int j = 0; j < raw_img.cols; j++) { //////////////////////
if ((i % 2 == 0) && (j % 2 == 0))//top green
{
image.at<Vec3b>(i, j)[0] = (raw_img.at<uchar>(i - 1, j) +
raw_img.at<uchar>(i + 1, j)) / 2; //red
image.at<Vec3b>(i, j)[1] = (raw_img.at<uchar>(i, j) * 2); //blue
image.at<Vec3b>(i, j)[2] = (raw_img.at<uchar>(i, j - 1) +
raw_img.at<uchar>(i, j + 1)) / 2; //green
}
else if ((i % 2 == 0) && (j % 2 == 1))//red
{
image.at<Vec3b>(i, j)[0] = (raw_img.at<uchar>(i, j)); //red
image.at<Vec3b>(i, j)[1] = (raw_img.at<uchar>(i - 1, j) +
raw_img.at<uchar>(i + 1, j) +
raw_img.at<uchar>(i, j - 1) +
raw_img.at<uchar>(i, j + 1)) / 2;//green
image.at<Vec3b>(i, j)[2] = (raw_img.at<uchar>(i + 1, j - 1) +
raw_img.at<uchar>(i - 1, j + 1) +
raw_img.at<uchar>(i + 1, j + 1) +
raw_img.at<uchar>(i - 1, j - 1)) / 4;//blue
}
else if ((i % 2 == 1) && (j % 2 == 0))//blue
{
image.at<Vec3b>(i, j)[0] = (raw_img.at<uchar>(i + 1, j - 1) +
raw_img.at<uchar>(i - 1, j + 1) +
raw_img.at<uchar>(i + 1, j + 1) +
raw_img.at<uchar>(i - 1, j - 1)) / 4;//red
image.at<Vec3b>(i, j)[1] = (raw_img.at<uchar>(i + 1, j) +
raw_img.at<uchar>(i, j + 1) +
raw_img.at<uchar>(i - 1, j) +
raw_img.at<uchar>(i, j + 1)) / 2;//green
image.at<Vec3b>(i, j)[0] = (raw_img.at<uchar>(i, j));//blue
}
else // bottom green
{
image.at<Vec3b>(i, j)[0] = (raw_img.at<uchar>(i, j - 1) +
raw_img.at<uchar>(i, j + 1)) / 2;//red
image.at<Vec3b>(i, j)[1] = (raw_img.at<uchar>(i, j) * 2);//blue
image.at<Vec3b>(i, j)[2] = (raw_img.at<uchar>(i - 1, j) +
raw_img.at<uchar>(i + 1, j)) / 2;//green
}
}
}
Upvotes: 1
Views: 418
Reputation: 137
The above stated answer works. But to prevent the hassle of using min,max
with each pixel. It can be done as shown below with an Opencv function:
int main(int argc, char** argv)
{
Mat img_rev = imread("C:/Users/20181217/Desktop/images/imgs/den_check.png");
//number of additional rows and columns
int top, left, right, bottom;
top = 1;
left = 1;
right = 1;
bottom = 1;
//define new image with additional borders
Mat img_clamp(img_rev.rows + 2, img_rev.cols + 2, CV_8UC3);
//if you want to pad the image with zero's
copyMakeBorder(img_rev, img_clamp, top, left, right, bottom, BORDER_CONSTANT);
//if you want to replicate the border of the image
copyMakeBorder(img_rev, img_clamp, top, left, right, bottom, BORDER_REPLICATE);
//Now you can access the image without having to worry about the borders as shown below
for(int i=1;i<img_clamp.rows-1;i++)
{
for(int j=1;i<img_clamp.cols-1;i++)
{
...
}
}
waitKey(100000);
return 0;
}
More operations can be found here:
Upvotes: 0
Reputation: 3323
You could do something like:
image.at<Vec3b>(i, j)[0] = (raw_img.at<uchar>(max(0,i - 1), j)
+ raw_img.at<uchar>(min(i + 1,raw_img.rows-1), j)) / 2; //red
For all you i +/- 1 , j +/-1: this way you "replicate" border values by simply sticking to the last value value in the X or Y dimension
As a side note, openCV includes different demosaic algorithm that will be hard to beat (for both quality and execution speed)
Upvotes: 1