I'm trying to write an OpenCV program in Java that takes a photo of a marker with a phone and finds circular contours on the marker. I have gotten it working in the Android emulator (where the photo has perfect lighting conditions), but can't get it to work with the phone itself. This is the marker I'm trying to capture:
After using the combination of transforming to grayscale, a Gaussian blur and a Canny edge detector, I get this output:
If I then try to find the contours on the image, the number of contours returned is really high (over 1000), but they aren't closed (because the edges seem to be too weak. The contours drawn over the original image:
This is the code I use for the segmentation:
Mat processed = new Mat(original.height(), original.width(), original.type());
Imgproc.cvtColor(original, processed, Imgproc.COLOR_RGB2GRAY);
Imgproc.GaussianBlur(processed, processed, new Size(7, 7), 0.1);
Imgproc.Canny(processed, processed, 50, 50*3, 3, false);
I have tried tweaking the different parameters (thresholds etc.), but feel like that isn't the ideal solution. I'm thinking there has to be a way to enhance the edges returned by the canny detector, but I haven't found anything myself.
Any help is appreciated!
CodePudding user response:
You can look into dilation operation in opencv to enhance the edges.
Noise is usually present - it can be reduced - you can distinguish the circles with adaptiveThreshold and then find the circles using the method I described below. The point is, the real-world image you get from the camera may contain a whole bunch of other circles - so it might be best to find all the circles. Compare them all in size. Find the 4 circles that are most similar to your marker in terms of color, size and placement.
A quick python code to distinguish the circles:
# Make a gray version
gry = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# Thresh
ada = cv2.adaptiveThreshold(
gry, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2
)
# Remove noises
out = cv2.medianBlur(ada, 7)
# Invert colors (Not needed)
out = ~out
I tested the Python code and it works; you can find an equivalent for Java or C . I tried to explain the Java code but I wrote it on the fly and did not test it. The Java code I wrote probably has errors, but it does get the point. With a bit change will probably work. I also wrote the code that should find the circles as the last block. Working with it is tricky and requires adjusting the parameters.
Java:
...
Imgproc.cvtColor(im, gry, Imgproc.COLOR_RGBA2GRAY);
Imgproc.adaptiveThreshold(gry, ada, 255,
Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 11, 2);
Imgproc.medianBlur(ada, out, 7);
...
and for finding circles:
Java:
...
SimpleBlobDetector_Params params = new SimpleBlobDetector_Params();
params.set_filterByCircularity(true);
params.set_minCircularity(0.01f);
params.set_maxArea(50000);//important
SimpleBlobDetector detector = SimpleBlobDetector.create(params);
// List of detected points
MatOfKeyPoint keyPoints = new MatOfKeyPoint();
detector.detect(ada, keyPoints);
// Draw circles on final image
Scalar color = new Scalar(127, 0, 255);
for (KeyPoint key: keyPoints.toList()) {
Imgproc.circle(im, key.pt, (int) (key.size / 2.0f), color, 3/*Thickness*/);
}
...




