3
votes

I'm implementing a function in order to detect circles in an image. I am using OpenCV for Java to identify the circles. The gray scale images do show a circle.

Here's my code:

Mat gray = new Mat();
Imgproc.cvtColor(img, gray, Imgproc.COLOR_BGR2GRAY);
Imgproc.blur(gray, gray, new Size(3, 3));

Mat edges = new Mat();
int lowThreshold = 100;
int ratio = 3;
Imgproc.Canny(gray, edges, lowThreshold, lowThreshold * ratio);

Mat circles = new Mat();
Vector<Mat> circlesList = new Vector<Mat>();

Imgproc.HoughCircles(edges, circles, Imgproc.CV_HOUGH_GRADIENT, 1, 60, 200, 20, 30, 0);

Imshow grayIM = new Imshow("grayscale");
grayIM.showImage(edges);

Any idea why this may be the case?

1
Can you post the source image and the image being passed to HoughCircle? Also the intermediate images if possible. - balmy
Houghcircles should be used on tge gray image, not the edge image - Miki

1 Answers

2
votes

First, as Miki pointed out HughCircles should be applied directly on the greyscale, it has an internal Canny Edge detector of its own.

Second the parameters of HughCircles should be tuned to your specific type of images. There isn't a one setting fits all formula.

Based on your code this worked for me on some generated circles:

public static void main(String[] args) {
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    Mat img = Highgui.imread("circle-in.jpg", Highgui.CV_LOAD_IMAGE_ANYCOLOR);

    Mat gray = new Mat();
    Imgproc.cvtColor(img, gray, Imgproc.COLOR_BGR2GRAY);
    Imgproc.blur(gray, gray, new Size(3, 3));

    Mat circles = new Mat();
    double minDist = 60;
    // higher threshold of Canny Edge detector, lower threshold is twice smaller
    double p1UpperThreshold = 200;
    // the smaller it is, the more false circles may be detected
    double p2AccumulatorThreshold = 20;
    int minRadius = 30;
    int maxRadius = 0;
    // use gray image, not edge detected
    Imgproc.HoughCircles(gray, circles, Imgproc.CV_HOUGH_GRADIENT, 1, minDist, p1UpperThreshold, p2AccumulatorThreshold, minRadius, maxRadius);

    // draw the detected circles
    Mat detected = img.clone();
    for (int x = 0; x < circles.cols(); x++) {
        double[] c1xyr = circles.get(0, x);
        Point xy = new Point(Math.round(c1xyr[0]), Math.round(c1xyr[1]));
        int radius = (int) Math.round(c1xyr[2]);
        Core.circle(detected, xy, radius, new Scalar(0, 0, 255), 3);
    }

    Highgui.imwrite("circle-out.jpg", detected);
}

Input image with circles:

Input image with circles

Detected circles are colored red:

Detected circles are colored red

Note how in the output image the white circle on the left was not detected being very close to white. It will be if you set p1UpperThreshold=20.