I am creating a pattern detection algorithm to detect a square and get its corner. To test the algorithm I have fed in an image that has a square dead-centre, so i would expect the algorithm to return the correct corners. However, some points are a single pixel off the expected value. Here's the Java code:
Mat rgba = new Mat();
Mat gray = new Mat();
Mat mIntermediateMat = new Mat();
// Get camera frame and store in rgba
mCamera.retrieve(rgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGB);
// Flip rgba because it is a front-facing-camera
Core.flip(rgba, rgba, 1);
// Convert to greyscale for faster processing
Imgproc.cvtColor(rgba, gray, Imgproc.COLOR_RGB2GRAY);
// Apply thresholding
Imgproc.threshold(gray, mIntermediateMat, 80, 255, Imgproc.THRESH_BINARY);
// Find all the contours in the image
Imgproc.findContours(mIntermediateMat, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
// Filter out too small contours
/* ... */
// Find contours with 4 points
List<MatOfPoint> squareContours = new ArrayList<>();
MatOfPoint2f mMOP2f1 = new MatOfPoint2f();
MatOfPoint2f approx = new MatOfPoint2f();
for(int i = 0; i < contours.size(); i++){
// Convert MatOfPoint to MatOfPoint2f
contours.get(i).convertTo(mMOP2f1, CvType.CV_32FC2);
// Approximate contour with a the precision Epsilon
Imgproc.approxPolyDP(mMOP2f1, approx, Imgproc.arcLength(mMOP2f1, true) * 0.10, true);
if(approx.size().equals(new Size(1, 4))){
squareContours.add(new MatOfPoint(approx.toArray()));
}
}
// For simplicity, let's assume we have one MatOfPoint left
MatOfPoint ourMatrix = ...;
MatOfPoint2f mMOP2fOuter = new MatOfPoint2f();
ourMatrix.convertTo(mMOP2fOuter, CvType.CV_32FC2);
RotatedRect rotatedRect = Imgproc.minAreaRect(mMOP2fOuter);
Point pattern[] = rotatedRect.toArray();
I would expect the following coordinates:
(269.00, -289.00) (270.00, -289.00) (270.00, -190.00) (369.00, -190.00)
, but instead I get (270.00, -289.00) (270.00, -290.00) (269.00, -190.00) (369.00, -189.00)
.
The expected coordinates are this because the pattern in the image is 100x100 px, dead-center in a 640x480 image.
You can see this isn't a big difference, but there is one pixel off. The provided image however isn't slanted, and shouldn't be too compressed, because I saved it as a .png
and reopening it inn GIMP allowed me to still count the pixels without any pixels having an opacity other than black or white. Here is the image:
Am I making some mistake somewhere, or should I just allow this one pixel difference?