converting images between opencv and wxwidgets - c++

I have got a big problem. After searching through the internet, I didn't find a good solution. I read in images from files via opencv (2.3) and manipulate them. Afterwards I want to present the result in my application written in wxwidgets (2.9.3). The main problem is, that my images are grayscale and so I just have got a single data pointer, but wxwidgets just use RGB. just a small example:
cv::imread(filename,CV_LOAD_IMAGE_GRAYSCALE).convertTo(pictureMatrix,CV_32F,(float)(1/2.0f),0);
// here are some more floating point calculations
cv::Mat output;
pictureMatrix.convertTo(output,CV_8U);
wxImage test(output.rows, output.cols, output.data, true);
wxInitAllImageHandlers();
// saving the picture is just for testing, if it works
test.SaveFile("test.png", wxBITMAP_TYPE_PNG);

All you need to to do is to convert from grayscale to RGB (actually, to BGR, if you're on Windows).
cv::Mat grayOutput, rgbOutput;
pictureMatrix.convertTo(grayOutput,CV_8U);
cvtColor(grayOutput, rgbOutput, CV_GRAY2BGR); // note the BGR here.
//If on Linux, set as RGB
wxImage test(rgbOutput.cols, rgbOutput.rows, rgbOutput.data, true);
...

You can always set R=G=B=<your grayscale value> for every pixel. If the format of the image pixels doesn't match up, you can allocate a new array in the format expected by wxImage and fill it with those RGB values.
You can also take a look at this link. It looks similar to what you need to do.

Related

Save exr/pfm to bitmap CImg

I am trying to convert some bitmap files into custom images (exr, pfm, whatever), and after that, back to bitmap:
CImg<float> image(_T("D:\\Temp\\test.bmp"));
image.normalize(0.0, 1.0);
image.save_exr(_T("D:\\Temp\\test.exr"));
and goes fine (same for .pfm file), I mean the exr file is ok, same for pfm file.
But when this exr, or pfm file I trying to convert back to bitmap:
CImg<float> image;
image.load_exr(_T("D:\\Temp\\test.exr")); // image.load_pfm(_T("D:\\Tempx\\test.pfm"));
image.save_bmp(_T("D:\\Temp\\test2.bmp"));
the result, test2.bmp is black. Complete. Why ? What I am doing wrong ?
Some image formats support saving as float, but most formats save as unsigned 8 bit integer (or uint8), meaning normal image values are from 0 to 255. If you try to save an array that is made up of floats from 0 to 1 into a format that does not support floats, your values will most likely be converted to integers. When you display your image with most image-viewing software, it'll appear entirely black since 0 is black and 1 is almost black.
Most likely when you save your image to bitmap it is trying to convert the values to uint8 but not scaling properly. You can fix this by multiplying normalized values between 0 and 1 by 255. img = int(img*255) or using numpy img = (img*255).astype(np.uint8).
It is also possible that somehow your save function is able to preserve floating point values in the bitmap format. However your image viewing software might not know how to view/display a float image. Perhaps use some imshow function (matplotlib.pyplot can easily display floating point grayscale arrays) between each line of code to check if the arrays are consistent with what you expect them to be.

imwrite in opencv gives a black/white image

I wrote a code for watershed segmentation in C API. Now I am converting all those into C++. so, cvsaveimage becomes imwrite. But when I use imwrite ,all i get is a black image.
this is the code:-
Mat img8bit;
Mat img0;
img0 = imread("source.png", 1);
Mat wshed(img0.size(), CV_32S);
wshed.setTo(cv::Scalar::all(0));
////after performing watershed segmentation and
// displaying the watershed image from wshed//
wshed.convertTo(img8bit, CV_32FC3, 255.0);
imwrite("Watershed.png", img8bit);
The original image that I want to save is in wshed. I saw suggestions from the net that we need to convert it to 16 bit or higher so that the imwrite saves it right. Like you see,I tried that. But the wshed image is being displayed correctly when using imshow.The img0 is grey image/black and white while the wshed image is coloured. any help on this?
Edit- I changed the 4th line to
Mat wshed(img0.size(), CV_32FC3);
When calling Mat::convertTo() with a scalar (255 in your case), the values of every matrix item will be multiplied by this scalar value. This will cause all most every result pixel values exceed 255 (i.e. white pixels) except those of 0s where they remain 0 (i.e. black pixels). This is why you will get the black-white pixel in the end.
To make it work, simply change it to:
wshed.convertTo(img8bit, CV_32FC3);
You said:
The original image that I want to save is in wshed. I saw suggestions
from the net that we need to convert it to 16 bit or higher so that
the imwrite saves it right.
If saving the image does not work you should keep in mind that the image data has to be either 8-Bits or 16-Bit unsigned when using the imwrite Function, not 16-Bits or higher.
This is stated in the documentation:
The function imwrite saves the image to the specified file. The image
format is chosen based on the filename extension (see imread() for the
list of extensions). Only 8-bit (or 16-bit unsigned (CV_16U) in case
of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with ‘BGR’
channel order) images can be saved using this function. If the format,
depth or channel order is different, use Mat::convertTo() , and
cvtColor() to convert it before saving. Or, use the universal
FileStorage I/O functions to save the image to XML or YAML format.

Is there a way to have both grayscale and rgb pixels on the same image opencv C++?

I need to be able to work with images where some regions are grayscale while others are kept on the RGB format. I don't want to convert an image into a grayscale since it will lose the channels and will become simply one channeled, is there a way to keep the RGB channels of some pixels on the picture and turn the others into a grayscale?
NO.
I see two solutions to this:
Have both a gray (Mat1b) and a rgb (Mat3b) image, and work on the image you need.
Have a single rgb (Mat3b) image, and set r,g,b channels to the same gray value where you need. In this way you can mimic to have a mixed gray/rgb image.

Taking a screenshot of a particular area

Looking for a way for taking a screenshot of a particular area on the screen in C++. (So not the whole screen) Then it should save it as .png .jpg whatever to use it with another function afterwards.
Also, I am going to use it, somehow, with openCV. Thought i'd mention that, maybe it's a helpful detail.
OpenCV cannot take screenshots from your computer directly. You will need a different framework/method to do this. #Ben is correct, this link would be worth investigating.
Once you have read this image in, you will need to store it into a cv:Mat so that you are able to perform OpenCV operations on it.
In order to crop an image in OpenCV the following code snippet would help.
CVMat * imagesource;
// Transform it into the C++ cv::Mat format
cv::Mat image(imagesource);
// Setup a rectangle to define your region of interest
cv::Rect myROI(10, 10, 100, 100);
// Crop the full image to that image contained by the rectangle myROI
// Note that this doesn't copy the data
cv::Mat croppedImage = image(myROI);

Converting opencv image to gdi bitmap doesn't work depends on image size

I have this code that converts an opencv image to a bitmap:
void processimage(MAT imageData)
{
Gdiplus::Bitmap bitmap(imageData.cols,imageData.rows,stride, PixelFormat24bppRGB,imageData.data);
// do some work with bitmap
}
It is working well when the size of image is 2748 X 3664. But I am tring to process an image wth size 1374 X 1832, it doesn't work.
The error is invalid parameter(2).
I checked and can confirm that:
in 2748 *3664:
cols=2748
rows=3664
stride= 8244
image is continues.
in 1374 X 1832
cols=1374
rows=1832
stride= 4122
image is continues.
So everything seems correct to me, but it generate error.
What is the problem and how can I fix it?
Edit
Based on answer which explained why I can not create bitmap. I finally implemented it in this way:
Mat newImage;
cvtColor(imageData, newImage, CV_BGR2BGRA);
Gdiplus::Bitmap bitmap(newImage.cols,newImage.rows,newImage.step1(), PixelFormat32bppRGB,newImage.data);
So effectively, I convert input image to a 4 byte per pixel and then use the convert it to bitmap.
All credits to Roger Rowland for his answer.
I think the problem is that a BMP format must have a stride that is a multiple of 4.
Your larger image has a stride of 8244, which is valid (8244/4 = 2061) but your smaller image has a stride of 4122, which is not (4122/4 = 1030.5).
As it says on MSDN for the stride parameter (with my emphasis):
Integer that specifies the byte offset between the beginning of one
scan line and the next. This is usually (but not necessarily) the
number of bytes in the pixel format (for example, 2 for 16 bits per
pixel) multiplied by the width of the bitmap. The value passed to this
parameter must be a multiple of four.
Assuming your stride is correct, I think you're only option is to copy it row by row. So, something like:
Great a Gdiplus::Bitmap of the required size and format
Use LockBits to get the bitmap pixel data.
Copy the OpenCV image one row at a time.
Call UnlockBits to release the bitmap data.
You can use my class CGdiPlus that implements all you need to convert from cv::Mat to Gdiplus::Bitmap and vice versa:
OpenCV / Tesseract: How to replace libpng, libtiff etc with GDI+ Bitmap (Load into cv::Mat via GDI+)