Ask Your Question

# Detect/Fitting Circles

Hi

If you look at this image:

It's easy to find by human eyes that there are 3 circles which share the same center.

How could I detect/fit these 3 circles ? I try cvFindContours() but the middle and inner circles are detected as a single contours. I also try cvHoughCircles(), it give me a lot of circles ... but not the 3 circles I expected.

What should I do for this kind of situation ? I'm new in computer vision, is this an easy question ? Or this is a known difficult problem ?

Regards KC

edit retag close merge delete

## 2 answers

Sort by ยป oldest newest most voted

Hough Circle Transform is the best option to detect circle in OpenCV. If you are getting expected circle with false circle using Hough Circle Transform you can easily filter out the true circle. For this first manually find out the radius of three circle you are expecting. Then find out the ratios between the three circle and these ratios will be constant even if you re-size your image. Then using Hough Circle Transform and find out the circles in the image. Then filter out co-centred circle from detected circle. For each co-centred circle(with next) check whether it's radius ratio comes in the range of your predefined value, if it comes so store it as true circle.

Hope this is helpful.

more

## Comments

Hi,

I did try different parameters' setup for cvHoughCircles() ... a lot of circles will be detected, but no one will fit the inner/empty circle :-( I need to know the center and radius correctly (this is a measurement application), and I do know the approximate center and radius ... any suggestion to handle this kind of "tooth" like circle ? Thanks a lot.

( 2012-12-15 10:24:00 -0600 )edit

You can easily detect the outer circle using Hough transform, from there you will get the centre.

1. Find the THRESH_BINARY_INV of the src image('thr') with a threshold say 100.
2. Create Mat of same size and and set all element to zero say 'add'.
3. In a loop start drawing circle on 'add' from centre towards outer with a value say 255.
4. On each step add=add+thr 5 Scan through each pixel of 'add' and check whether it's value is 255(means it touches whiter boarder) 6.If 255 exit loop and that will be the intermediate circle. 7.Else increase radius until you met the condition.

For intermediate circle Same step as above but instead of adding image minus it. radius=radius found out using hough transform- a constant 1. add=add-thr;
2. check if pixel value of add=155 if yes exit
3. else radius--

I am not sure does it work or not for other images but it is working fine for the image you provided with your question. Below is the code I just made to test the above algorithm.

  #include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace cv;

/** @function main */
int main(int argc, char** argv)
{
Mat src, src_gray,thr,edge,add;

/// Read the image
src = imread( argv[1], 1 );
int t1=75;
int t2=100;
if( !src.data )
{ return -1; }

/// Convert it to gray
cvtColor( src, src_gray, CV_BGR2GRAY );
/// Reduce the noise so we avoid false circle detection
GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
threshold( src_gray, thr, t1, t2, THRESH_BINARY_INV );
threshold( src_gray, add, 0, 0, THRESH_BINARY_INV ); //Instaed of this step you can create an image of the same size and set all element to zero

imshow( "thr", thr );

Point cent; // centre for inner circle
int rad=55; //radius for inner circle
int radius; // centre for Hough circle
vector<Vec3f> circles;

/// Apply the Hough Transform to find the circles
HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, t1, t2, 0, 0 );

/// Draw the circles detected
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
radius = cvRound(circles[i][2]);
cent.x=center.x;
cent.y=center.y;

// circle center
circle( src, center, 3, Scalar(0,255,0), 5, 8, 0 );
// circle outline
circle( src, center, radius, Scalar(0,255,0), 1, 8, 0 );
}

/************ This block will findout the inner circle******************/

int flag=0;

while(flag==0){

threshold( src_gray, add, 0, 0, THRESH_BINARY_INV ); // instead of this can you can set all elemet to zero
circle( add, cent, rad, Scalar(155), 1, 8, 0 );
add=thr+add;
imshow( "add", add );
waitKey(33);

rad++;

//Scan whole mat and check whether the circle hit the white pixel
for(int i = 0; i < add.rows; i++)
{
for(int j = 0; j < add.cols; j++)
{
Vec3b bgrPixel = add.at<Vec3b>(i, j);
int p=bgrPixel.val[0];

if(p==255){ //Check whether the radius reaches white region from centre.
flag=1 ...
more

## Comments

Cool, this is what I expected !! I think I got the point, thanks a lot :-)

( 2012-12-17 02:40:03 -0600 )edit

Just another question. The HoughCircles() usually does not return a single circle. It usually return a lot of circle; sometime no circle at all ... what's the trick to turn the image or parameters to let HoughCircles() to return single circle ? Is the general rules existed ?

( 2012-12-17 03:20:21 -0600 )edit

I think the two parameters -upper and lower threshold values- control the number of circles returns. If you include more edges in your image it will return maximum number of circles and it depends on the high and low threshold values, also blur operation before the Hough transform reduces false circle return. Selecting the thresholds can be considered as the key point in Houch circle tranform and that can be varied according to your image brightness

( 2012-12-17 03:46:14 -0600 )edit

Hi, I was very excited when I see your code running without second thought. In fact, this is not what I wanted. Your approach assume the outer and inner circle share the same centre. But what I really need is find the outer/inner circle independently and check if they have the same centre.

Thanks anyway, your example is helpful.

KC

( 2012-12-17 10:04:13 -0600 )edit

Official site

GitHub

Wiki

Documentation

## Stats

Asked: 2012-12-14 11:02:20 -0600

Seen: 12,164 times

Last updated: Dec 17 '12