8

I'm trying to detect the center of black/white dot targets, like in this picture. I've tried to use the cv2.HoughCircles method but 1, am only able to detect 2 to 3 targets, and 2, when I plot the found circles back onto the image, they're always offset slightly.

Am I using the wrong method? Should I be using the findContours or something completely different?

Here is my code:

import cv2
from cv2 import cv
import os
import numpy as np

def showme(pic):
    cv2.imshow('window',pic)
    cv2.waitKey()
    cv2.destroyAllWindows()


im=cv2.imread('small_test.jpg')

gray=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)

#I've tried blur,bw,tr...  all give me poor results.

blur = cv2.GaussianBlur(gray,(3,3),0)
n,bw = cv2.threshold(blur,120,255,cv2.THRESH_BINARY)
tr=cv2.adaptiveThreshold(blur,255,0,1,11,2)

circles = cv2.HoughCircles(gray, cv.CV_HOUGH_GRADIENT, 3, 100, None, 200, 100, 5, 16)

try:
    n = np.shape(circles)
    circles=np.reshape(circles,(n[1],n[2]))
    print circles
    for circle in circles:
        cv2.circle(im,(circle[0],circle[1]),circle[2],(0,0,255))
    showme(im)
except:
    print "no cicles found"

And this is my current output:

karlphillip
  • 92,053
  • 36
  • 243
  • 426
hokiebird
  • 280
  • 1
  • 5
  • 15
  • Would love to see your current output. You might be interest to check this thread: http://stackoverflow.com/q/10313602/176769 – karlphillip May 02 '12 at 01:14
  • here is the output for the code above. ![results of my code][1] [1]: http://i.stack.imgur.com/nd2Hr.jpg – hokiebird May 02 '12 at 04:31
  • Maybe it's time to review your other questions and accept the answers that solved them (if there are any). There's a little checkbox near each answer, click on it to select the official answer to your question. – karlphillip May 02 '12 at 16:31

3 Answers3

8

Playing the code I wrote in another post, I was able to achieve a slightly better result:

It's all about the parameters. It always is.

There are 3 important functions that are called in this program that you should experiment with: cvSmooth(), cvCanny(), and cvHoughCircles(). Each of them has the potential to change the result drastically.

And here is the C code:

IplImage* img = NULL;
if ((img = cvLoadImage(argv[1]))== 0)
{
    printf("cvLoadImage failed\n");
}

IplImage* gray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
CvMemStorage* storage = cvCreateMemStorage(0);

cvCvtColor(img, gray, CV_BGR2GRAY);

// This is done so as to prevent a lot of false circles from being detected
cvSmooth(gray, gray, CV_GAUSSIAN, 7, 9);

IplImage* canny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
IplImage* rgbcanny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
cvCanny(gray, canny, 40, 240, 3);

CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 2, gray->height/8, 120, 10, 2, 25);
cvCvtColor(canny, rgbcanny, CV_GRAY2BGR);

for (size_t i = 0; i < circles->total; i++)
{
     // round the floats to an int
     float* p = (float*)cvGetSeqElem(circles, i);
     cv::Point center(cvRound(p[0]), cvRound(p[1]));
     int radius = cvRound(p[2]);

     // draw the circle center
     cvCircle(rgbcanny, center, 3, CV_RGB(0,255,0), -1, 8, 0 );

     // draw the circle outline
     cvCircle(rgbcanny, center, radius+1, CV_RGB(0,0,255), 2, 8, 0 );

     printf("x: %d y: %d r: %d\n",center.x,center.y, radius);
}

cvNamedWindow("circles", 1);
cvShowImage("circles", rgbcanny);

cvSaveImage("out.png", rgbcanny);
cvWaitKey(0);

I trust you have the skills to port this to Python.

Community
  • 1
  • 1
karlphillip
  • 92,053
  • 36
  • 243
  • 426
  • thanks for the help. I'll work on porting it over the Python. I'm going to use these targets (I already know there 3d positions, using a TRITOP sytem [link]http://www.capture3d.com/products-TRITOP.html ) to calculate position/orientation of the part. After I use this method to find the circles, is there another method you would recommend that will very accurately calculate the centers of the targets? Thanks again – hokiebird May 02 '12 at 16:23
  • This entire program could become a single function that is executed a couple of times (with different parameters), and after each iteration you compare the circles found to a previous iteration to make sure that all the circles are good. This approach could possibly tell you that the largest circle to the right is not a good circle. – karlphillip May 02 '12 at 16:29
  • are you using `canny` and `rgbcanny` at all in your circle detection? it seems like not but I want to make sure – mga Jul 12 '13 at 15:16
  • The circle detection part is done by `cvHoughCircles()`. Check which parameters it takes and you'll have your answer. The rest of the code simply draw circles on a copy (rgbcanny) of the original image. Feel free to upvote my answer. – karlphillip Jul 12 '13 at 17:07
  • Thank You @karlphillip . Surprisingly the code is very fast and works on a live video feed as well (Even when implemented in python). What advice would you give for a video? I am using this to analyze the video feed on a camera mounted on my toy dron. So that problem I'm facing is that it suddenly detects like 100 circles ina few frames and boom, they disappear in the next frame. This is going to be hazardous for any controller I implement. – shahensha Apr 24 '14 at 07:28
0

Since that circle pattern is fixed and well distinguished from the object, simple template matching should work reasonably well, check out cvMatchTemplate. For a more complex conditions (warping due to object shape or view geometry), you may try more robust features like SIFT or SURF (cvExtractSURF).

jeff7
  • 2,172
  • 14
  • 9
0

Most Detect Circles using Python Code

import cv2
import numpy as np

img = cv2.imread('coin.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(7,9),6)
cimg = cv2.cvtColor(blur,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(blur,cv2.HOUGH_GRADIENT,1,50,
                            param1=120,param2=10,minRadius=2,maxRadius=30)


circles = np.uint16(np.around(circles))
for i in circles[0,:]:
    # draw the outer circle
    cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)

cv2.imshow('detected circles',cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
Manivannan Murugavel
  • 1,476
  • 17
  • 14