Combine two images based on a black and white mask - c++

I want to create a mask operation...
I have two input images, of the same size (do they have to have the same depth/number of channels ? I'd like to be anything, likely 3 channels, CV_32FC3 or gray...) and I created a mask, of the same size (rows and cols)
cv::Mat mask = cv::Mat(image1.rows, image1.cols, CV_8UC1);
The mask is created with areas of black and white.
I would like to create a new cv::Mat, that will have image1 where mask has 1, and image2 where mask has 0.
I looked into cv::filter2D and copyTo... Also looked at addWeighted, but I don't want to blend them - the areas for each image should be completely separate. A roi would not help - the mask is likely to not contain a rectangle, but one or more polygons.
I can't find something that does what I want.
Is there any OpenCV function that combines my images based on the mask ? Or do I have to create my own, looping through rows and cols ?
Thank you.

Just use the bitwise_and() function and you're set. The references below include a full working example.
References:
How to "zero" everything within a masked part of an image in OpenCV
OpenCV bitwise_and + mask

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.

retain original color of the object after thresholding opencv

I am doing a project where i need to find a red laser dot. After changing to HSV color space model and thresholding individual H,S,V components and merging it , i found a laser dot with several noise as well , now i need to subtract all other image components except for the laser dot and the noise with their respective color so that i can process those frame for further processing like template matching to get only the laser dot reducing the noises. Hope you understand the question and Thank You, any similar help is appreciated.
What you're looking to do is apply a mask to an image. A mask is an image where any positive non-zero value acts as an indicator. What you want to do is use the mask to indicate which pixels in the original image you want.
The easiest way to apply a mask is to use the cv2.bitwise_and() function, with your thresholded image as the mask:
masked_img = cv2.bitwise_and(img, img, mask=thresholded_img)
As an example, if this is my image and this is my mask, then this would be the masked image.

OpenCV function to merge Mat's except for black/transparent pixels

I have a Mat containing text with a black background and a Mat containing a background. I want to merge the 2 Mat's so the text sits ontop of the background. Both Mats are BGR (CV_8UC3) and the same size (cols and rows).
Whats the OpenCV way of doing this?
I'm aware of a couple of functions but |= and += are changing the text colour and addWeighted() only works if I want one image to be slightly transparent. I just want to do a complete merge of the two (except not the black pixels in the text image). I'm looking for an OpenCV function rather than pixel editting myself, well a LUT would be good if thats an option.
Try this:
sourceText = yourTextImage;
sourceBackground = yourBackgroundImage;
cv::Mat textTransparent;
cv::inRange(sourceText, cv::Scalar(0,0,0), cv::Scalar(0,0,0), textTransparent);
cv::imshow("transparent pixel", textTransparent); // this should show all the transparent pixel as being white. If that's not the case, adjust the range.
std::cout << "is the transparency mask ok? Press any key with openCV window focus." << std::endl;
cv::Mat result = sourceBackground.clone();
sourceText.copyTo(sourceBackground, 255-textTransparent); // copy pixels, using the created mask.
instead you could copy the transparent pixels from the sourceBackground to the sourceText which is a bit faster because you don't need the 255-textTransparent...
Could not test the code, please tell me if there are bugs.

Transparent pixels in OpenCV C++ (when using GrabCut)

I am using OpenCV 's implementation of GrabCut in order to remove the background from images. But for now the new background is black. Is there any way to make it transparent?
For now this part of the code looks like this:
Mat binMask( image.size(), CV_8UC1 );
binMask = mask & 1;
image.copyTo( result, binMask );
Can I somehow fill the binMask with transparent pixels?
I've read some tutorials for overlaying images, but I don't need a transparent image in front of my picture but behind.
I hope someone could help.
Many thanks!
Since you are using a 8UC1 image type, it's not possible to have transparent pixels.
These are allowed only if you have an alpha channel, with alpha set to 0: you must use a 4-channel image (3 for colors, 1 for alpha channel). The alpha channel is supported in file formats such as PNG, but not in JPG.
In case of masking, you don't need by the way the usage of transparent pixels, since the black ones actually correspond to 0 and they don't influence the result when you're blending two images (addWeighted for example, or also in case of bitwise_or operation).

How to thin an image borders with specific pixel size? OpenCV

I'm trying to thin an image by making the border pixels of size 16x24 becoming 0. I'm not trying to get the skeletal image, I'm just trying to reduce the size of the white area. Any methods that I could use? Enlighten me please.
This is the sample image that i'm trying to thin. It is made of 16x24 white blocks
EDIT
I tried to use this
cv::Mat img=cv::imread("image.bmp", CV_LOAD_IMAGE_GRAYSCALE);//image is in binary
cv::Mat mask = img > 0;
Mat kernel = Mat::ones( 16, 24, CV_8U );
erode(mask,mask,kernel);
But the result i got was this
which is not exactly what i wanted. I want to maintain the exact same shape with just 16x24 pixels of white shaved off from the border. Any idea what went wrong?
You want to Erode your image.
Another Description
Late answer, but you should erode your image using a kernel which is twice the size you want to get rid of plus one, like:
Mat kernel = Mat::ones( 24*2+1, 16*2+1, CV_8U );
Notice I changed the places of the height and width of the block, I only know opencv from Python, but I am pretty sure the order is the same as in Python.