avalagne
avalagne

Reputation: 359

Wrong arguments in method HoughCircles from Emgu CV

I'm trying to write an application that detects coins in the image. I found a piece of code that uses the HoughCircles of Emgu CV. I can't, however, set the parameters so that I returned each coin (circles). Do you have any experience with this problem? Thank you for your advice.

This is code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;

namespace INZO_Sem_Pr3_ST28605
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        Bitmap bitmap = new Bitmap(pictureBox1.Image);

        //Load the image from file
        Image<Bgr, Byte> img = new Image<Bgr, byte>(bitmap);

        //Get and sharpen gray image (don't remember where I found this code; prob here on SO)
        Image<Gray, Byte> graySoft = img.Convert<Gray, Byte>().PyrDown().PyrUp();
        Image<Gray, Byte> gray = graySoft.SmoothGaussian(3);
        gray = gray.AddWeighted(graySoft, 1.5, -0.5, 0);

        Image<Gray, Byte> bin = gray.ThresholdBinary(new Gray(70), new Gray(255));

        Gray cannyThreshold = new Gray(200);
        Gray cannyThresholdLinking = new Gray(100);
        Gray circleAccumulatorThreshold = new Gray(1000);

        Image<Gray, Byte> cannyEdges = bin.Canny(cannyThreshold.Intensity, cannyThresholdLinking.Intensity);

        pictureBox1.Image = cannyEdges.ToBitmap();

        //Circles
        CircleF[] circles = cannyEdges.HoughCircles(
            cannyThreshold,
            circleAccumulatorThreshold,
            1.0, //Resolution of the accumulator used to detect centers of the circles
            cannyEdges.Height / 8, //min distance 
            0, //min radius
            2000 //max radius
            )[0]; //Get the circles from the first channel

        //draw circles (on original image)
        foreach (CircleF circle in circles)
            img.Draw(circle, new Bgr(Color.Brown), 2);
    }
}
}

I read more explanations what these arguments mean, but i can't set good values. This is result after use edge detection: enter image description here

Upvotes: 1

Views: 3597

Answers (1)

plinth
plinth

Reputation: 49189

Let's talk about the Hough transform a bit. In its simplest form, the Hough transform is used to detect lines. This is done by taking every "set" pixel in an image and solving for all possible lines that intersect that point. The solution set itself is an equation for a line. Then given all these line equations, you solve for intersections between them and the location of the most common intersection represents a solution for a line that is most "prevalent".

In reality, this is done by drawing a subset of each solution line into an image such that when you set a target pixel, you add 1 to it. Then you scan the image and find the pixel with the brightest color and it is the most prevalent line. (and in reality, you work in polar coordinates, but that's another story)

For circles, it works similarly, but here we get sneaky. We fix a radius for circles that we're looking for and for every "set" pixel in the image, we solve for all circles that could intersect that point (which itself is the equation for a circle). Then you find all the intersection points of those circles and the most common intersection point is the most prevalent circle of the fixed radius in the image.

In reality, this is done by drawing a each solution circle onto an image in exactly the same way as the line example and the "brightest" point in the image is the center of the most prevalent circle in the image. And reality reality, OpenCV uses a gradient test to cut down computation.

Now, my take on this is that in the documentation, the call will do run a Canny Edge detection first. It looks like you are running HoughCircles on an image that has already been edge detected. Don't do that.

Next, let's look at the accumulator threshold. This basically is saying keep all circles for which there have been n or more hits. By setting it to 1000, you're saying you have to have at least 1000 solution sets for every circle. That's crazy. You should use some percentage of the circumference of the smallest radius circle you're expecting to find. The closer you are to 100% the more unbroken the circle needs to be.

The dp argument is used to determine how big the solution space should be. The more dp approaches 0, the more memory will be needed). As dp grows, the less accurate the result. I wouldn't use anything more than 2 unless my source image is huge.

The min dist is to allow circles to overlap and by how much.

Min and max radius do exactly what they say on the box, but going from 0 - 1000 is odd. 0 is a default for "I don't know", but I think you'd be better off with something like 6 or 7 (a 12 pixel diameter circle is about as small as can render a decent looking circle anyway). Then the max is going to be whatever you think is reasonable for your problem domain - like 100?

If you want more detail, I wrote a paper some time ago about ways to implement and make the Hough Transform faster.

Upvotes: 2

Related Questions