How to apply a non-binary mask on an image in OpenCV? - c++

I'm using OpenCV and I have a gray-scale image that is the result of a smoothing operation on a binary mask:
I would like to apply this mask to a given RGB image, but using the copyTo method with the mask option takes into account all the non-zero pixels of the mask. However, what I'm interested in is to obtain an output image whose RGB pixel values are the input values 'scaled' pixel-wise by the factor given by the gray-scale mask.
I have the feeling that this is possible by using the built-in functions of OpenCV, but so far I couldn't find any way to do what I want.
I would know how to do that from scratch in a brute force fashion, but I'd prefer - if possible - to use built-in functions.
Thank you in advance!

As #api55 pointed out, the solution to my problem is:
Normalize the mask through the function cv::normalize
Multiply the normalized mask with the input image through the function cv::multiply
In particular, the type of the normalized mask must be set to CV_32F (otherwise it won't work). As a consequence, the input image has to be converted as well (e.g., with convertTo).
Example code:
cv::normalize(mask,mask,0.,1.,cv::NORM_MINMAX,CV_32F);
image.convertTo(image,CV_32F);
cv::multiply(image,mask,image);
image.convertTo(image,CV_8U); // Convert back the input image to the original type

Related

OpenCV color histogram calcHist considering only specific pixels (and not full image)

I want to calculate the color histogram of an image but only taking into account specific pixels (whose 2D coordinates I know).
Is it possible to use calcHist specifying that only these concrete pixels should be taken into consideration (instead of the whole cv::Mat and all the pixels in it)? If not, is it possible to create a new Mat including only those specific pixels at known positions, and how? (Considering that for a histogram the pixel coordinates do not matter, could they be added to a (1 x number_of_specific_pixels)-dim Mat keeping the original type of the Mat?)
Thanks a lot in advance!
The third parameter of clalHist is called Mask.
So, you create a new single channel 8 bit cv::Mat that has the same size of your input image. It should contain 255's where you want to calculate the histogram and 0's where you do not. Then, pass it as Mask.

Applying adaptive thresholding to inrange function opencv c++

I want to take a video and create a binary from it, I want it so that if the pixel is within a certain range it will be included within the binary. In other words I want an upper and lower bound like in the inRange() function as opposed to a simple cutoff point like in the threshold() function.
I also want to use adaptive thresholding to account for differences in lighting in my video. Is there a way to do this? I know there is inRange() that does the former and adaptiveThreshold() that does the latter, but I don't know if there is a way to do both.
Apply adaptiveThreshold() to the whole original image, then apply inRange() to the original image and use the result of inRange() as a mask:
adaptiveThreshold(original_image, dst_image ... );
inRange(original_image, minArray, maxArray, mask);
Mat output = dst_image.mul(mask);

OpenCV convertTo()

I came across this code:
image.convertTo(temp_image,CV_16SC3);
I saw the description of the convertTo() function from here, but what confuses me is image. How can we read the above code? What would be the relation between image and temp_image?
Thanks.
The other answers here are correct, but lack some details. Let me try.
image.convertTo(temp_image,CV_16SC3);
You have a source image image, and a destination image temp_image. You didn't specify the type of image, but probably is CV_8UC3 or CV_32FC3, i.e. a 3 channel image (since convertTo doesn't change the number of channels), where each channel has depth 8 bit (unsigned char, CV_8UC3) or 32 bit (float, CV_32FC3).
This line of code will change the depth of each channel, so that temp_image has each channel of depth 16 bit (short). Specifically it's a signed short, since the type specifier has the S: CV_16SC3.
Note that if you are narrowing down the depth, as in the case from float to signed short, then saturate_cast will make sure that all the values in temp_image will be in the correct range, i.e. in [–32768, 32767] for signed short.
Why you need to change the depth of an image?
Some OpenCV functions require input images with a specific depth.
You need a matrix to contain a different range of values. E.g. if you need to sum (or subtract) some images CV_8UC3 (tipically BGR images), you'd better store the result in a CV_16SC3 or you'll probably get wrong results due to saturations, since the range for CV_8U images is in [0,255]
You read with imread, or want to store with imwrite images with 16bit depth. This are usually used (AFAIK) in medical or graphics application to allow a wider range of colors. However, most monitors do not support 16bit image visualization.
There may be other cases, let me know if I miss the one important to you.
An image is a matrix of pixel information (i.e. a 1080p image will be a 1,920 × 1,080 matrix where each entry contains rbg values for that pixel). All you are doing is reformatting that matrix (each pixel entry, iteratively) into a new type (CV_16SC3) so it can be read by different programs.
The temp_image is a new matrix of pixel information based off of image formatted into CV_16SC3.
The first one is a source, the second one - destination. So, it takes image, converts it into type CV_16SC3 and stores in temp_image.

How to get grayscale value of pixels from grayscale image in xCode

I was wondering how to determine the equivalent of RGB values for a grayscale image. The original image is grayscale and everything I have found online is converting an RGB image pixel values to the grayscale pixel values. I already can read in the image. Ideally, this would be for xCode.
I was wondering if there was a class which would do this for me. If so, and you could point me to it, that would be great. I will read on it.
Any help is greatly appreciated.
NOTE: I am a beginner in C++ and do not have time to learn everything formally; I have to learn all of my programming on the fly.
You need more information to transform from a simple Greyscale to RGB, when you do reverse operation, the color information is "lost", as the three channels are set to same value(depending on the algorithm each channel will have a different/same weight in the final color computation).
Digital cameras, usually store more information per pixel, 12 bits per channel in 35mm and 14 bits per channel in medium format (those bits number are the average, some products offer less or even more quality).
Thanks to those additional bits per channel, the camera can compute the "real" color, or what it thinks is the real color based on some parameters.
TL;DR: You can't without more data from your source, in this case the image.
You can convert a gray value to RGB by setting each component of the RGB value to the gray value:
ColorRGB myColorRGB = ColorRGBMake(myGrayValue, myGrayValue, myGrayValue);

Opencv: save a double matrix with imwrite

I have a matrix (Mat) constituted by double, in the range [0,1].
When I save it by means of command imwrite, the resulting image is totally black.
I suppose the problem is a casting problem, but I don't know how to solve it.
Thanks
The only way for OpenCV to store array of doubles without converting them to other formats (and losing information) is by using FileStorage. imwrite is restricted to arrays of 'char' or 'short'.
You get the totally black image is because all images pixels are within range [0,1] (actually either 0 or 1 when saving to image), which is approaching total black (either for gray-scale image or color image).
To save the matrix to the image with normal color, you need first to transform the double matrix to range [0, 255] by multiplying each value by 255. Remember to transform back if you later load the matrix from this image by dividing each value by 255.