Issue
I started by reading in this Mat
.
Then I converted it to Greyscale and applied Imgproc.canny()
to it, getting the following mask.
Then I used Imgproc.findContours()
to find the contours, Imgproc.drawContours()
, and Core.putText()
to label the contours with numbers:
Then I did Rect boundingRect = Imgproc.boundingRect(contours.get(0));
Mat submatrix = new Mat();
submatrix = originalMat.submat(boundingRect);
to get following submatrix
:
So far so good. The Problem starts hereafter:
NOW I NEEDED A MASK OF THE submatrix
. So I decided to use Imgproc.drawContours()
to get the mask:
Mat mask = new Mat(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1);
List<MatOfPoint> contourList = new ArrayList<>();
contourList.add(contours.get(0));
Imgproc.drawContours(mask, contourList, 0, new Scalar(255), -1);
I got the following mask:
WHAT I WAS EXPECTING was a filled (in white color) diamond shape on black background.
WHy am I getting this unexpected result?
EDIT:
When I replaced
Mat mask = new Mat(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1);
byMat mask = Mat.zeros(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1);
, the last mask with white colored garbage was replaced by an empty black mask withOUT any white color on it. I got the following submat and mask:I was getting the first contour in the list of contours (named
contours
) bycontours.get(0)
, and using this first contour to calculateImgproc.boundingRect()
as well as incontourList.add(contours.get(0));
later (wherecontourList
is the list of just one contour which will be used in the lastdrawContours()
).Then I went ahead to change
contours.get(0)
tocontours.get(1)
inImgproc.boundingRect()
as well as incontourList.add();
(just beforeImgproc.drawContours()
). That resulted in this submat and mask:Then I changed back to
contours.get(0)
inImgproc.boundingRect()
; and letcontourList.add(contours.get(1));
be there. Got the following submat and mask:
NOW I am completely Unable to Understand what is happening here.
Solution
I am not sure how this is handle in JAVA (I usually use OpenCV in c++ or python), but there is an error in your code...
The contours
list will have a list of list of points. This points will refer to the original image. So, this mean that if the figure one is in lets say, x=300, y= 300, width= 100, height=100
then when you get your submatrix it will try to draw those points in a smaller image... so when it tries to draw point (300,300)
in a 100 x 100 image, it will simply fail... probably throws an error or simply doesn't draw anything...
A solution for this is, do a for loop and substract to each point of the contour the initial point of the bounding rect (in my example (300,300)
).
As, why there is some garbage drawn... well you never initialize the matrix. Not sure in JAVA, but in c++ you have to set them to 0. I think it should be something like this:
Mat mask = new Mat(submatrix.rows(), submatrix.cols(), CvType.CV_8UC1, new Scalar(0));
I hope this helps :)
EDIT
I think I did not explain myself clearly before.
Your contours are an array of points (x,y). These are the coordinates of the points that represent each contour in the original image. This image has a size, and your submatrix has a smaller size. The points are outside of this small image boundaries....
you should do something like this to fix it:
for (int j = 0; j < contours[0].length; j++) {
contours[0][j].x -= boundingrect.x;
contours[0][j].y -= boundingrect.y;
}
and then you can draw the contours, since they will be in boundaries of the submat.
I think in java it is also possible to subtract the opencv points directly:
for (int j = 0; j < contours[0].length; j++) {
contours[0][j] -= boundingrect.tl();
}
but in this case I am not sure, since I have tried it in c++ only
boundingrect.tl()
-> gives you the top left point of the rect
Answered By - api55
Answer Checked By - Katrina (JavaFixing Volunteer)