2

I am using cvHoughCircles to find the two white ovals in the following image:

enter image description here

I first used thresholding for locating the white regions and then used Hough Transforms. But the output is not coming correct as shown below:

enter image description here

I am not able to understand what is happening? Why it is detecting 3 circles and why only one is being detected correctly? Any suggestions?

Below is my code:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <math.h> 
#include <ctype.h>
#include <stdlib.h>
#include "opencv/cv.h"
#include "opencv/highgui.h"
#include<conio.h>
#include<malloc.h>



using namespace cv;
using namespace std;
int main( ) {
IplImage* image = cvLoadImage( 
"testing.bmp",
  CV_LOAD_IMAGE_GRAYSCALE
);

IplImage* src = cvLoadImage("testing.bmp");
CvMemStorage* storage = cvCreateMemStorage(0);


cvThreshold( src, src,  200, 255, CV_THRESH_BINARY );

CvSeq* results = cvHoughCircles( 
image, 
 storage, 
 CV_HOUGH_GRADIENT, 
 3, 
 image->width/10 
 ); 

 for( int i = 0; i < results->total; i++ ) 
 {
 float* p = (float*) cvGetSeqElem( results, i );
 CvPoint pt = cvPoint( cvRound( p[0] ), cvRound( p[1] ) );
 cvCircle( 
  src,
  pt, 
  cvRound( p[2] ),
  CV_RGB(0xff,0,0) 
);
}
cvNamedWindow( "HoughCircles", 1 );
cvShowImage( "HoughCircles", src);
cvWaitKey(0);
} 

Edit:

Since I am not get satisfactory results with Hough Transform, I am willing to go for some other way. I can assume that each white blob in the figure is of equal size (size is known)and also the distance between the blob is known. Is there a non-trivial way I can find a vertical line (a tangent) touching the left side of left white blob? Once I know this tangent, I get an idea of the boundary location, then I will draw a circle at x=(this location + radius(which is known)), y= this location. Can I find such x and y coordinates using some non-trivial ways?

Solved, by changing as per below:

cvThreshold(image, image,  220, 255, CV_THRESH_BINARY );

cvCanny(image, image, 255, 255, 3);


cvNamedWindow( "edge", 1 );
cvShowImage( "edge", image);
cvWaitKey(0);

CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* results = cvHoughCircles( 
             image, 
             storage, 
             CV_HOUGH_GRADIENT, 
             4, 
             image->width/4, 100,100,0,50); 

Here is the output:

enter image description here

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
gpuguy
  • 4,607
  • 17
  • 67
  • 125
  • 1
    Perhaps I am not familiar with OpenCv, but shouldn't you use the edge image, not the thresholded as input to Hough algorithm? – Andrey Rubshtein May 21 '12 at 14:53
  • using Canny edge detection, followed by Hough Transformed worked! But when I take another image with more no. of white blobs, the same algo failed. – gpuguy May 22 '12 at 07:56
  • @Andrey, do you think for Oval shape detection the same procedure should be used? (Because in my case actually the shapes are oval and not circular) – gpuguy May 22 '12 at 08:04
  • Actually edges are detected perfectly when the thresholding is done before canny. But I guess internally Canny would involve thresholding also. So there might be some issues in parameters. Anyway your answer worked for me for some other images as well. Thanks – gpuguy May 22 '12 at 08:25

2 Answers2

3

It's all about the parameters:

IplImage* src = cvLoadImage(argv[1]);
if (!src)
{
    cout << "Failed: unable to load image " << argv[1] << endl;
    return -1;
}

//IplImage* image = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
IplImage* image = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
cvCvtColor(src, image, CV_RGB2GRAY);

cvThreshold(image, image,  220, 255, CV_THRESH_BINARY );
//  cvNamedWindow( "thres", 1 );
//  cvShowImage( "thres", image);
//  cvWaitKey(0);

CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* results = cvHoughCircles( 
                 image, 
                 storage, 
                 CV_HOUGH_GRADIENT, 
                 4, 
                 image->width/3); 

std::cout << "> " << results->total << std::endl;

for( int i = 0; i < results->total; i++ ) 
{
    float* p = (float*) cvGetSeqElem( results, i );
    CvPoint pt = cvPoint( cvRound( p[0] ), cvRound( p[1] ) );
    cvCircle(src,
             pt, 
             cvRound( p[2] ),
             CV_RGB(0xff,0,0));
}

cvNamedWindow( "HoughCircles", 1 );
cvShowImage( "HoughCircles", src);
cvWaitKey(0);

If you've done a little bit more experimentation you would have eventually found out that with different parameters you get different results:

Community
  • 1
  • 1
karlphillip
  • 92,053
  • 36
  • 243
  • 426
  • Tried my best , used your's as well as these parameters: CvSeq* results = cvHoughCircles( image, storage, CV_HOUGH_GRADIENT, 2,1 ); But did not work, no circle being detected, return >0 – gpuguy May 21 '12 at 12:14
  • The code above produced the image I shared. I used OpenCV 2.3.1. I suggest you test this in another machine. – karlphillip May 21 '12 at 12:25
  • I am having libraries like opencv_core240.lib, so it means I am having opencv 2.4. Your values 4, image->width/3 corresponds to "dp = 1: The inverse ratio of resolution" and "Minimum distance between detected centers" Am I right? – gpuguy May 21 '12 at 12:35
  • I don't know by heart but you can find it out by looking at OpenCV 2.3 documentation. By the way, I just tested my code on a Windows box with OpenCV 2.3.1 and it also worked. – karlphillip May 21 '12 at 12:44
2

You should use edge detected image as input, not the thresholded. Secondly, Hough circles will not work for elipses, unless they are very close to circles. I recommend reading about Generalized Hough Transform and implementing it for ellipses.

Andrey Rubshtein
  • 20,795
  • 11
  • 69
  • 104
  • Thershoding should be done , and then edge and then hough Transforms. In my case for images with nearly circular shape the solutions worked , but oval shaped did not. So I guess Genralised Hough Transform may be a better solution. The application in hand is actually much simpler as I know size and many other parameter of the white blobs, so may be some trivial method also work in my case. – gpuguy May 22 '12 at 08:28