I'm trying to translate the following Python function, that applies a mask to an image, into Java:
# Applies an image mask.
def region_of_interest(img, vertices):
#defining a blank mask to start with
mask = np.zeros_like(img)
#defining a 3 channel or 1 channel color to fill the mask with depending on the input image
if len(img.shape) > 2:
channel_count = img.shape[2] # i.e. 3 or 4 depending on your image
ignore_mask_color = (255,) * channel_count
else:
ignore_mask_color = 255
#filling pixels inside the polygon defined by "vertices" with the fill color
cv2.fillPoly(mask, vertices, ignore_mask_color)
#returning the image only where mask pixels are nonzero
masked_image = cv2.bitwise_and(img, mask)
return masked_image
So far, this is what I've got:
public static opencv_core.Mat applyMask(opencv_core.Mat image, opencv_core.MatVector vertices) {
opencv_core.Mat mask = opencv_core.Mat.zeros(image.size(), opencv_core.CV_8U).asMat();
opencv_core.Scalar color = new opencv_core.Scalar(image.channels()); // 3
double[] colors = new double[] {
255.0, 255.0, 255.0, 255.0,
255.0, 255.0, 255.0, 255.0,
255.0, 255.0, 255.0, 255.0};
color.put(colors, 0, colors.length);
opencv_imgproc.fillPoly(mask, vertices, color);
opencv_core.Mat dst = new opencv_core.Mat();
opencv_core.bitwise_and(image, mask, dst);
return dst;
}
But, it isn't working. When I try invoking this method like in the following example:
opencv_core.MatVector points = new opencv_core.MatVector(
new opencv_core.Mat(2, 3, opencv_core.CV_32F, new IntPointer(1, 2, 3, 4, 5, 6))
);
opencv_core.MatVector vertices = new opencv_core.MatVector(points);
opencv_core.Mat masked = LaneManager.applyMask(src, vertices);
(I'm assuming this is the right way to build a 2x3 matrix of three points with two coordinates each (1,2)
, (3, 4)
and (5,6)
)
I get an exception:
java.lang.RuntimeException: std::bad_alloc
at org.bytedeco.javacpp.opencv_imgproc.fillPoly(Native Method)
I'm using OpenCV as provided by org.bytedeco.javacpp-presets:opencv-platform:3.2.0-1.3
via Maven Central.
I must admit that I'm at a loss here: What's the idiomatic Java way of doing the same thing as the Python function above?
We then perform Erosion, Morphing, and Dilation techniques on the image to create the mask. Now, to invert the mask, we use bitwise_not the method of cv2 library to flip the pixel values (0 ->1 and 1 ->0). Finally, we display this inverted masked image.
Open an image editor that supports layers. Open the photo to which you want to apply a mask. Save the file with a new name as a duplicate so that you do not accidentally overwrite the original. Create a new layer and paint it solid white, and adjust the layer transparency so that you can see the underlying image.
Masking is a common technique to extract the Region of Interest (ROI). In openCV, it is possible to construct arbitrary masking shape using draw function and bitwise operation.
Maybe some whiz has the complete answers. Here is food for thought:
The error
std::bad_alloc
occurs when you fail to allocate required storage space. (http://answers.opencv.org/question/28959/cascade-training-killed-and-bad_alloc/)
void fillPoly(Mat& img, const Point** pts, const int* npts, int ncontours, const Scalar& color, int lineType=LINE_8, int shift=0, Point offset=Point() )
, andvoid fillPoly(InputOutputArray img, InputArrayOfArrays pts, const Scalar& color, int lineType=LINE_8, int shift=0, Point offset=Point() )
You don't need to convert from
Mat
toInputArray
, but you can (and should) just pass aMat
object where anInputArray
is requested (https://stackoverflow.com/a/32976883/1587329)
Alright, I finally figured it out. If you define your coordinates with:
int[] points = new int[] {x1, y1, x2, y2, ...};
Then you can simply apply a mask with the following code:
opencv_core.Mat mask = new opencv_core.Mat(image.size(), image.type());
// Array of polygons where each polygon is represented as an array of points
opencv_core.Point polygon = new opencv_core.Point();
polygon.put(points, 0, points.length);
opencv_imgproc.fillPoly(mask, polygon, new int[] {points.length / 2}, 1, new opencv_core.Scalar(255, 255, 255, 0));
opencv_core.Mat masked = new opencv_core.Mat(image.size(), image.type());
opencv_core.bitwise_and(image, mask, masked);
Where image
is the original image, and masked
is the masked result.
The problem was that the original list of points wasn't defined properly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With