imwrite in opencv gives a black/white image - c++

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.

Related

image export is returning grey scale image in opencv

I am using Network Optix Video management service. Using their application I am building a plugin. For my purpose I want to export frame as an image from a video. for that I used following code to convert to cv object and saving into my file.
cv::Mat img_color;
cv::Mat img(
videoFrame->height(),/*_rows*/
videoFrame->width(), /*_cols*/
CV_8UC1, //< BGR color space (default for OpenCV) /*_type*/
(void*) videoFrame->data(0), /*_data*/
(size_t) videoFrame->lineSize(0)); /*_step*/
cv::cvtColor(img, img_color, CV_GRAY2RGB);
m_lastVideoFrameTimestampUs = videoFrame->timestampUs();
std::string file_path = "/var/www/html/images/"+std::to_string(m_lastVideoFrameTimestampUs)+".jpg";
cv::imwrite(file_path,img_color);
below screenshot is what I am getting on Network Optix client application.
But, this is what I am getting as an image file on my machine.
cvtColor doesn't have any effect on the image
I think, CV_8UC1 argument should be modified so that I will get RGB image
EDIT - 1:
changes CV_8UC1 to CV_8UC3
Result turned into 3 segments of image
CV_8UC1 means that it is 8-bit single-channel array, you are getting a grayscale image at first and you can not except cvtColor to get it colorized again. cvtColor which you used will convert the image to BGR but all the channels will be in same value so it will continue to seem as grayscale.
In this case you can use CV_8UC3 which means that it is an 8-bit unsigned integer matrix/image with 3 channels(If your image in 3 channels)

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.

Reduce a 3 channel OpenCV Mat to a single-channel one using a LUT

I want to reduce the depth of an RGB image (24bit) to one byte by reducing the color space and using a color map where each 3-byte triple R/G/B is mapped to a one-byte color map value.
I am therefore looking for a performant way to create a a single-channel Mat (CV8UC1) out of a 3-channel Mat (CV8UC3) using a lookup table. This step is time-critical, as it is done for each frame of a video stream.
The LUT function would be great, but as far as I understand, the resulting Mat will contain was much channels as the input mat had.
Do you have any idea how this could be accomplished?

OpenCV imwrite a float image, which conversion to use?

I need to store a float image in OpenCV. Converting it to a CV8U image as suggested by #tomriddle_1234 still stores a black png.
reference.type() = 5
reference.channels() = 1
reference.depth() = 5
How can I convert the image to a 8bit or 16bit so that imwrite can store the image, while maintaining it's float property i.e: the stored image is not "washed out colours" due to conversion/loss of precision!
imshow("5t aligned Mean", reference); //Displays the correct image
//reference.convertTo(reference, CV_8U); //Convert image to 8Bit INCORRECT
reference.convertTo(reference, CV_8U, 255.0, 1/255.0); //Correct image
imwrite(subject.c_str(), reference); //Stores a completely black png
Any suggestions are much appreciated!
You can convert to 16bit by multiplying each float pixel by 2^16-1. Floating point images are stored with values between [0,1] which you want to map to the range [0,2^16-1]
opencv will save 16bit uncompressed in PNG and TIFF with the normal imwrite().
(It will also save them as JPEG although I've had less luck finding things that read 16bit jpeg)
normalize the image before converting between 0 and 255 using CV_NORM_MINMAX

converting images between opencv and wxwidgets

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.