masking in openCV - c++

Mat mask = Mat::zeros(img1.rows, img1.cols, CV_8UC1)
this piece of code is supposed to create a mask, I think, by using C++. What is the equivalent to creating a mask in C, like this? also, can someone explain to me what this piece of code is actually doing please?

With the C API, we would call
IplImage *mask = cvCreateImage(cvGetSize(img1), IPL_DEPTH_8U, 1);
cvSetZero(mask);
The C API is easier to read IMO, and what it does is create an image with 8 bits per pixel, 1 channel (grayscale), of the same size as img1, and then setting all its pixel values to zero.

Related

Why does setTo not work (assertion failed)?

I am just learning OpenCV and, since I have some experience with Matlab's logical indexing, I was really interested to see the matrix method setTo. My initial attempt doesn't work though, and I can't work out why, so I'd be very grateful for your help!
I have a Mat containing image data, and want to set all values greater than 10 to zero. So, I did:
Mat not_relevant = abs(difference - frame2) > 10;
difference = difference.setTo(0, not_relevant);
This however gives me:
OpenCV Error: Assertion failed (mask.empty() || mask.type() == CV_8U) in
cv::Mat::setTo, file
C:\builds\2_4_PackSlave-win32-vc12-shared\opencv\modules\core\src\copy.cpp, line 347
I have tried converting not_relevant, difference and frame2 before doing this using, e.g.:
frame2.convertTo(frame2, CV_8UC1);
but that did not fix the error, so I'm not sure what else I could try. Does anyone have any idea what might be wrong?
Thank you for your help!
I think the error is pretty clear.type of your mask image should be CV_8U.
so you need to convert not_relevent to grayscale.
Mat not_relevant = abs(difference - frame2) > 10;
cv::cvtColor(not_relevant, not_relevant, CV_BGR2GRAY);
difference = difference.setTo(0, not_relevant);
Why convertTo does not work here ?
CV_8U(or CV_8UC1) is type of image with one channel of uchar values.
convertTo can not change number of channels in image.
So converting image with more than one channel to CV_8U using convertTo does not work .
check this answer for more detailed explanations.

Open CV: Acces pixels of grayscale image

I know this question can be wired for experts, but I want to access pixels of grayscale image in openCV. I am using the following code:
cv::Mat img1 = cv::imread("bauckhage.jpg", CV_LOAD_IMAGE_GRAYSCALE);
Now if I want to print any pixel(say at position 255,255) using img1.at<float>(255,255) I get 0, which is not actually black pixel. I thought the image has been read as 2d Matrix.
Actually I want to do some calculation on each pixel, for that I need to access each pixel explicitly.
Any help or suggestion will be appreciated.
You will have to do this
int x = (int)(img.at<uchar>(j,i))
This is because of the way the image is stored and the way img.at works. Grayscale image is stored in CV_8UC1 format and hence it is basically an array of uchar type. So the return value is a uchar which you typecast into an int to operate on it as ints.
Also, this is similar to your questions:
accessing pixel value of gray scale image in OpenCV
float is the wrong type here.
if you read an image like this:
cv::Mat img1 = cv::imread("bauckhage.jpg", CV_LOAD_IMAGE_GRAYSCALE);
then it's type will be CV_8U, (uchar, a single grayscale byte per pixel). so, to access it:
uchar &pixel = img1.at<uchar>(row,col);

How to use the OTSU Threshold in opencv - input source

I understand that this is the command to use otsu in opencv:
cvThreshold(src, dst, 128, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
However, I don't understand what that src and dst is, explained on the opencv website as:
input array (single-channel, 8-bit or 32-bit floating point).
What is an 8-bit or 32-bit floating point, single channel array?
http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#threshold
Single channel means graysclale. 8 bits means unsigned char (CV_8U in OpenCV). 32bit means float (CV_32F in OpenCV)
My issue was getting the image in the right format but I found at least two ways:
CvCapture* capture = cvCaptureFromFile("picture.png");
IplImage* frame = cvQueryFrame(capture);
2.
IplImage* frame = cvLoadImage("picture.png", CV_LOAD_IMAGE_GRAYSCALE);
I am also under the impression that the picture needs to be grey scaled first, not sure how to do that for the first option though. Anyway, for src and dst these work.

3 Channel image access using OpenCV

I'm having a 2D Vector called Mat with values from 0 to 255 that I'm assigning to an IPLIMAGE like what is follow:
IplImage *A=cvCreateImage(cvSize(640,480), IPL_DEPTH_8U, 1)
for (int i=0;i<640;i++)
{
for (j...)
{
A->imageData[i*640+j]=Mat[i][j]
}
}
But what about if i m having 3 2D vectors Mat1, Mat2, Mat3 and an IPLIMAGE whose number of channels is equal to 3:
IplImage *A=cvCreateImage(cvSize(640,480), IPL_DEPTH_8U, 3)
I thought that I could do it channel by channel and merge them all at the end, but I really believe it's not the optimal solution.
Any idea how to access to imageData of the 3 channels in that case?
First, note that you can avoid writing the first code if Mat is aligned, by directly assigning the imageData struct member of IplImage. You'll have to use cvCreateImageHeader instead of cvCreateImage to avoid allocating data for the image. More info about the struct can be found here.
Second, regarding your question - it is possible to do that by creating three images by the technique I mentioned earlier, and then using cvMerge to produce the final image. More information here.
In general, I recommend you to migrate to the C++ interface of OpenCV, which uses cv::Mat instead of the old IplImage interface.
If you look at OpenCV tutorial for C++ API, there is example for working with Mat.
http://docs.opencv.org/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html#the-iterator-safe-method
There are presented 3 ways to access 3 channel image.

Combine two images based on a black and white mask

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