Lets say I was given a boundingRect based on some points and stored it into a Rect object.
How can I use those points and create a mask in openCV? that is, everything outside the bounding rectangle is masked (or set white)
I've tried several different methods and was able to get it to work using a convexHull and fillign with a polygon but can't seem to get it to work with the boundingRect
You can call fillConvexPoly() by passing the four end points of the bounding Rect.
// assume all four end points are stored in "vector<Point> roi_vertices" already
// the order of the vertices don't matter
Mat mask = Mat(height, width, CV_8UC1, Scalar(0));
// Create Polygon from vertices
vector<Point> roi_poly;
approxPolyDP(roi_vertices, roi_poly, 1.0, true);
// Fill polygon white
fillConvexPoly(mask, &roi_poly[0], (int)roi_poly.size(), 255, 8, 0);
P.S.: the above method will also work for generating masks for any (convex) polygons.
Draw your rectangle with CV_FILLED option and invert it, like
Rect boundRect(x,y,W,H);
Mat mask(rows,cols,CV_8UC1,Scalar(0));
rectangle(mask,boundRect,Scalar(255),CV_FILLED,8,0);
bitwise_not(mask,mask);
or in another way without using invert, just create a white image and then draw rectangle using CV_FILLED option but with black color(Scalar(0)).
That is
Rect boundRect(x,y,W,H);
Mat mask(rows,cols,CV_8UC1,Scalar(255));
rectangle(mask,boundRect,Scalar(255),CV_FILLED,8,0);
Related
I've detected the triangular shape of the traffic sign I want to detect. To use this image for further processing, I'd like to create a mask to make the background white (or black, doesn't really matter).
To detect this shape I used:
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
Mat hierarchy = new Mat();
CvInvoke.FindContours(input.GetImage(), contours, hierarchy,Emgu.CV.CvEnum.RetrType.External,Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
With the DrawContours method, I can easily draw them, with the correct result: image of the contours.
How do I make a mask so that I can clear everything outside the contours?
You can use the contours you have and draw to another similar empty image if all what you want is the outline.
If you want to fill, you can use the fillPoly function to fill the contours directly with specified color, and then use the binary filter to make all pixels with that color while and others black.
Hi , I have attached the image below with an yellow bounding box. Is there any algorithm or (sequence of algorithms) in Opencv by which I can detect the yellow pixels and create a ROI mask (which will block out all the pixels outside of it).
You can do:
Find the yellow polygon
Fill the inside of the polygon
Copy only the inside of the polygon to a black-initialized image
Find the yellow polygon
Unfortunately, you used anti-aliasing to draw the yellow line, so the yellow color is not pure yellow, but has a wider range due to interpolation. This affects also the final results, since some not yellow pixels will be included in the result image. You can easily correct this by not using anti-aliasing.
So the best option is to convert the image in the HSV space (where it's easier to segment a single color) and keep only values in a range around the pure yellow.
If you don't use anti-aliasing, you don't even need to convert to HSV and simply keep points whose value is pure yellow.
Fill the inside of the polygon
You can use floodFill to fill the polygon. You need a starting point for that. Since we don't know if a point is inside the polygon (and taking the baricenter may not be safe since the polygon is not convex), we can safely assume that the point (0,0), i.e. the top-left corner of the image is outside the polygon. We can then fill the outside of the polygon, and then invert the result.
Copy only the inside of the polygon to a black-initialized image
Once you have the mask, simply use copyTo with that mask to copy on a black image the content under non-zero pixels in the mask.
Here the full code:
#include <opencv2\opencv.hpp>
using namespace cv;
int main()
{
Mat3b img = imread("path_to_image");
// Convert to HSV color space
Mat3b hsv;
cvtColor(img, hsv, COLOR_BGR2HSV);
// Get yellow pixels
Mat1b polyMask;
inRange(hsv, Scalar(29, 220, 220), Scalar(31, 255, 255), polyMask);
// Fill outside of polygon
floodFill(polyMask, Point(0, 0), Scalar(255));
// Invert (inside of polygon filled)
polyMask = ~polyMask;
// Create a black image
Mat3b res(img.size(), Vec3b(0,0,0));
// Copy only masked part
img.copyTo(res, polyMask);
imshow("Result", res);
waitKey();
return 0;
}
Result:
NOTES
Please note that there are almost yellow pixels in the result image. This is due to anti-aliasing, as explained above.
I am developing face features detection in my project.
Heretofore i have developed detecting the face, then finding the eyes within the face.
I want to crop the eyes which are in circular .
circle( mask, center, radius, cv::Scalar(255,255,255), -1, 8, 0 );
image.copyTo( dst, mask );
Here in the above code , I am able to Mask image with black color leaving eye region. now I am want to crop only the Eye region.
Can anybody help me out on this issue.Please check below image
Cropping, by definition, means cutting an axis aligned rectangle from a larger image, leaving a smaller image.
If you want to "crop" a non-axis-aligned rectangle, you will have to use a mask. The mask can be the size of the full image (this is sometimes convenient), or as small and the smallest bounding (axis-aligned) rectangle containing all the pixels you want to leave visible.
This mask can be binary, meaning that it indicates whether or not a pixel is visible, or it can be an alpha-mask which indicated the degree of transparency of any pixel within it, with 0 indicating a non-visible pixel and (for 8-bit mask image) 255 indicating full opacity.
In your example above you can get the sub-image ROI (Region-Of-Interest) like this:
cv::Mat eyeImg = image(cv::Rect(center.x - radius, // ROI x-offset, left coordinate
center.y - radius, // ROI y-offset, top coordinate
2*radius, // ROI width
2*radius)); // ROI height
Note that eyeImg is not a copy, but refers to the same pixels within image. If you want a copy, add a .clone() at the end.
I have specified the histogram as
MatND skinCrCbHist =Mat::zeros(Size(256,256),CV_8UC1);
ellipse(skinCrCbHist, Point(113, 155.6), Size(283.4, 159.2), 43.0, 0.0, 360.0, Scalar(255), -1); // Using a really big ellipse to find any sort of back projection in CrCb domain.
cvtColor(src, ycrcb, CV_BGR2YCrCb); //src is input, image of a person
float crrange[]={0,255};
float cbrange[]={0,255};
const float* ranges[]={crrange,cbrange};
int channelsy[]={1,2};
calcBackProject( &ycrcb, 1, channelsy, skinCrCbHist, backproj, ranges, 255, true );
imshow("bp",backproj);
The problem i face is that backproj shows a completely black image.
When I used a normal histogram created with calcHist on a natural image, i do get some sort of backprojection. But how do i use a histogram, i create artificially, by specifying an ellipse, to get a backprojection.
If I understood your problem correctly, you could use mask with the original calcHist function.
You didn't specified which version of OpenCV you are using, so I will assume the latest 2.4.6.0. The method prototype is following (omitting defaults, and types):
calcHist(images, nimages, channels, mask, hist, dims, histSize, ranges)
The third parameter is mask. The mask means, that the function will ignore all pixels which matches zero pixels in mask. In program the mask is another image correctly setup.
Here is pseudo-code for you problem:
1) get input image
2) create matrix of same size as input of type CV_8UC1 filled with zeros
3) draw white (value 255) ellipse on the new image
4) call caclHist with the new image as mask
http://docs.opencv.org/modules/imgproc/doc/histograms.html
My application requires mapping one quadrilateral to another quadrilateral. Neither of these are rectangles.
However, the result I get from warpPerspective() is always a rectangle. I have tried setting the "outlier" flag to different values to prevent pixels from outside the warped quad from appearing in the destination image but nothing seems to work. What I want is a warped quad with the pixels outside the warped quad set to transparency.
How do I achieve this?
Alternatively, is there a straightforward way to mask the region outside a quadrilateral in OpenCV so that I can copy just the quad to another image?
In case it is relevant, I am using the Python binding to OpenCV.
Here is my current code:
def warpImage(image, corners, target, width, height):
mat = cv2.getPerspectiveTransform(corners, target)
out = numpy.zeros(shape=(width, height), dtype="uint8")
out = cv2.warpPerspective(image, mat, (width,height), out, cv2.INTER_CUBIC)
return out
corners and target are both non-rectangular quads. The output is a full widthxheight rectangle, however. None of the pixels are black or transparent. Instead they are pixels from the image both inside and outside the corners quad. I only want the ones inside.
The best option I have found is to cycle through the pixels and copy the ones in the warped quad to a remap array using the matplotlib pnpoly() function, as so:
import matplotlib.nxutils as nx
def warpImage(image, corners, target, width, height, x0, y0, remap):
mat = cv2.getPerspectiveTransform(corners, target)
out = cv2.warpPerspective(image, mat, (width,height), flags=cv2.INTER_CUBIC)
for x in range(0,width):
for y in range(0,height):
if nx.pnpoly(x,y,target) == 1:
for i in range(0,3):
remap[y+y0,x+x0,i] = out[y,x,i]
return remap
I loop through all the quads in image and accumulate transformed versions in remap.
Having to access each pixel is not very efficient but fortunately this is a one time transformation.