Demosaicing with opencv - c++

I am stuck trying to figure out how to use the opencv demosaicing function. I have OpenCV 4.4.0 installed with CUDA support compiled in, and so far what I think I need to do is:
Read in the raw image data
Load in raw image data to a Mat object
Upload the Mat data to a GpuMat (host to device upload)
Demosaic
Download the GpuMat data (device to host download) to a Mat object
Display or write out the result
Here is a snippet of the code I have.
ifstream ifs("image.raw", ios_base::binary);
ifs.read(buffer, length);
// snip ...buffer contains the entire file...
Mat src_host(6464, 4860, CV_16UC1, buffer);
GpuMat dst, src;
src.upload(src_host);
// Debayer here
cv::cuda::demosaicing(src, dst, COLOR_BayerRG2BGR);
// have a look
Mat result_host;
dst.download(result_host);
namedWindow("Debayered Image", WINDOW_KEEPRATIO);
resizeWindow("Debayered Image", 6464/5, 4860/5);
imshow("Debayered Image", result_host);
waitKey(0);
I have raw frames from cameras that have 12 bits per pixel, RGGB, dimensions 6464 x 4860. I'm uncertain of how to specify this for OpenCV in terms of width and height, what CV_TYPE to give it, whether I am reading in and uploading the data properly for demosaicing, what COLOR_code to give it for demosaicing, and how to download the result for display and saving to file (preferably a high level routine to write a png or similar).
Does anyone know whether I'm on the right track or not?
Thanks! James

Yes, I'm on the right track. The rows and columns are accidentally swapped, so the corrected code is:
ifstream ifs("image.raw", ios_base::binary);
ifs.read(buffer, length);
// snip ...buffer contains the entire file...
Mat src_host(4860, 6464, CV_16UC1, buffer);
GpuMat dst, src;
src.upload(src_host);
// Debayer here
cv::cuda::demosaicing(src, dst, COLOR_BayerRG2BGR);
// have a look
Mat result_host;
dst.download(result_host);
namedWindow("Debayered Image", WINDOW_KEEPRATIO);
resizeWindow("Debayered Image", 4860/2, 6464/2);
imshow("Debayered Image", result_host);
waitKey(0);
While the sensor data is 12 bit, each 12 bits sits inside 16 bits, which makes it a lot easier to deal with.

Related

How can I encode and decode the depth image with opencv? I use the following code to get a depth image in webots, but fail. Thanks a lot

// `s` is the webots's rangefinder
auto buffer = (float*)s->getRangeImage();
cv::Mat img(cv::Size(width, height), CV_32FC1, buffer); // image data is float*
// check and success.
// imshow("pic", img);
// cvWaitKey(0);
// encode:
std::vector<uchar> newBuffer;
cv::imencode(".jpg", img, newBuffer);
// decode
auto img_decode = cv::imdecode(newBuffer, cv::IMREAD_UNCHANGED);
// fail and get a black image
imshow("pic", img_decode);
cvWaitKey(0);
I have try to use other params in function cv::imdecode like cv::IMREAD_ANYDEPTH but fail. I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this.
If your data is real, i.e. floating point, and single channel, you could try writing to a PFM or TIFF format image which will support that data type.
As #wohlstad mentions in the comments, JPEG is uint8 so only supports integers in the range 0..255.

Opencv C++ grayscale image black pixeled result (when replacing image values)

I'm new in opencv and I had this problem...
Given the following Mat type (globally declarated)
Mat src_gray;
Mat dst;
I have dst being a zero grayscale Mat with this initialization
dst=Mat::zeros(src_gray.size(), CV_BGR2GRAY);
It seems I can't edit the pixels on the dst image (when I use imwrite, it gives me a black image as if I hadn't done anything).
This is the code I currently have:
for(int i=0;i<=dst.cols;i++)
for(int j=0;j<=dst.rows;j++)
{
dst.at<uchar>(j,i)=255;
}
imwrite( "img_res.png", dst );
The result Image has the dimensions it's supposed to have, but it is a black pixeled picture, shouldn't it be a white pixeled Image?
I don't know if it is relevant if I mention that I have 3 global Mats
Mat image;
Mat src_gray;
Mat dst;
Which are initialized this way:
image = imread( argv[1], 1 );
cvtColor( image, src_gray, CV_BGR2GRAY );
Then, I release them as:
image.release();
dst.release();
src_gray.release();
The other problem I get is that when I release the Mats (during execution), I get the "Segmentation fault (core dumped)" error. (I code from Linux Ubuntu distri)
Try:
dst=Mat::zeros(src_gray.size(), CV_8UC1);
When you use CV_BGR2GRAY, you are creating a Mat with 3 color channels, then, it's not possible to assign a number when you have an array of numbers (B,G,R).
With CV_8UC1, you create a Mat with 1 color channel of uchar then it should works with:
dst.at<uchar>(j,i)=255;

How to display PGM image using OpenCV

I'm trying to load and display a .PGM image using OpenCV(2.4.0) for C++.
void open(char* location, int flag, int windowFlag)
{
Mat image = imread(location, flag);
namedWindow("Image window", windowFlag);
imshow("Image window", image);
waitKey(0);
}
I'm calling open like this:
open("./img_00245_c1.pgm", IMREAD_UNCHANGED, CV_WINDOW_AUTOSIZE);
The problem is that the image shown when the window is opened is darker than if I'm opening the file with IrfanView.
Also if I'm trying to write this image to another file like this:
Mat imgWrite;
imgWrite = image;
imwrite("newImage.pgm", imgWrite)
I will get a different file content than the original one and IrfanView will display this as my function displays with imshow.
Is there a different flag in imread for .PGM files such that I can get the original file to be displayed and saved ?
EDIT: Image pgm file
EDIT 2 : Remarked that: IrfanView normalizes the image to a maximum pixel value of 255 .
In order to see the image clearly using OpenCV I should normalize the image also when loading in Mat. Is this possible directly with OpenCV functions without iterating through pixels and modifying their values ?
The problem is not in the way data are loaded, but in the way they are displayed.
Your image is a CV_16UC1, and both imshow and imwrite normalize the values from original range [0, 65535] to the range [0, 255] to fit the range of the type CV_8U.
Since your PGM image has max_value of 4096:
P2
1176 640 // width height
4096 // max_value
it should be normalized from range [0, 4096] instead of [0, 65535].
You can do this with:
Mat img = imread("path_to_image", IMREAD_UNCHANGED);
img.convertTo(img, CV_8U, 255.0 / 4096.0);
imshow("Image", img);
waitKey();
Please note that the values range in your image doesn't correspond to [0, 4096], but:
double minv, maxv;
minMaxLoc(img, &minv, &maxv);
// minv = 198
// maxv = 2414
So the straightforward normalization in [0,255] like:
normalize(img, img, 0, 255, NORM_MINMAX);
img.convertTo(img, CV_8U);
won't work, as it will produce an image brighter than it should be.
This means that to properly show your image you need to know the max_value (here 4096). If it changes every time, you can retrieve it parsing the .pgm file.
Again, it's just a problem with visualization. Data are correct.

Open CV image saving in smaller size without compressions

The question i have is the following:
I have a camera( with resolution Resolution : 640 x 480 px) and I get an image from that camera (I get an 8 bit/ pixel grayscale image) after the image acquisition I save the image in a bmp format. My code is the followig :
Mat img2(640,480,CV_8UC1,0);
cap.read(img2);
bool succes = imwrite("D:\\TestImage3.bmp",img2);
if(!succes){
cout << "Failed to save the image";
return -1;
}
namedWindow("myWindow",CV_WINDOW_AUTOSIZE);
imshow("myWindow",img2);
The saved image is very large almost 1 MB and i want a smaller image without losing any information (without compresing the image)???
The second question on this topic is:
even if the image is gray some times I still get some rgb noise, its like I would have set a 3 channel setting instead of 1 channel setting for my image
If anyone knows the answer please let me know, I would be very grateful
Thanks for your time!
You can save your image as PNG which is an lossless image compression format.
bool succes = imwrite("D:\\TestImage3.png",img2);
With the cv::imwrite function you can pass additional parameters depending on the image format.
PNG is a lossless image format but you can still chose the level of compression for example :
Mat img2;
cap.read(img2);
cvtColor(img2, img2, CV_BGR2GRAY); // Convert to single channel
vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
compression_params.push_back(9);
bool succes = imwrite("D:\\TestImage3.bmp", img2, compression_params);
if(!succes)
{
cout << "Failed to save the image"; return -1;
}
imshow("myWindow",img2);
waitKey(0);
Just use the default constructor for Mat with no params.
Mat img2;
cap.read(img2);
cvtColor(img2, img2, CV_BGR2GRAY); // Convert to single channel
bool succes = imwrite("D:\\TestImage3.bmp", img2);
if(!succes)
{
cout << "Failed to save the image"; return -1;
}
imshow("myWindow",img2);
waitKey(0);
Also, bmp is known for its large uncompressed size. Use .png instead.

C++ and OpenCV: Issue Converting Image to grayscale

Here is my code. It's pretty simple.
Mat image = imread("filename.png");
imshow("image", image);
waitKey();
//Image looks great.
Mat image_gray;
image.convertTo(image_gray, CV_RGB2GRAY);
imshow("image", image_gray);
waitKey();
But when I call the image.convertTo(image_gray, CV_RGB2GRAY); line, I get the following error message:
OpenCV Error: Assertion failed (func != 0) in unknown function, file ..\..\..\sr
c\opencv\modules\core\src\convert.cpp, line 1020
Using OpenCV 2.4.3
The method convertTo does not do color conversion.
If you want to convert from BGR to GRAY you can use the function cvtColor:
Mat image_gray;
cvtColor(image, image_gray, CV_BGR2GRAY);
The function cv::Mat::convertTo is not for color conversion. It is for type conversion. The destination image should have same size and number of channels as the source image.
To convert from RGB to Gray, use the function cv::cvtColor.
cv::cvtColor(image,image_gray,CV_RGB2GRAY);
If you need to acquire video (e.g. from a webcam) in Grayscale, you can also set the saturation of the video feed to zero. (Ex. in Python syntax)
capture = cv.CaptureFromCAM(camera_index)
...
cv.SetCaptureProperty(capture, cv.CV_CAP_PROP_SATURATION,0)
image.convertTo(image_gray, CV_RGB2GRAY);
This's wrong.Correct one is,
Mat gray_image;
cvtColor(image, gray_image, CV_BGR2GRAY);
Try this.