I am trying to make a program which opens an image, scans it for circles/round shapes and returns the coordinates so that I can use the cv.Circle
function to draw circles over the circle detected.
My question is: How do I get the coordinates/radii of the circles detected in an image using cv.HoughCircles()
?
Using this page, I found out how to detect the circles (which took me a lot of time to find out since I don't understand terms like threshold and the OpenCV documentation for Python is really poor, almost none). Unfortunately, on that page it didn't show how to extract the information of each circle detected from the CvMat
created. How do I extract that information/is there some other way(eg. with MemoryStorage()
) ?
This is my code so far:
import cv, opencv
def main():
im = cv.LoadImageM("Proba.jpg")
gray = cv.CreateImage(cv.GetSize(im), 8, 1)
edges = cv.CreateImage(cv.GetSize(im), 8, 1)
cv.CvtColor(im, gray, cv.CV_BGR2GRAY)
cv.Canny(gray, edges, 50, 200, 3)
cv.Smooth(gray, gray, cv.CV_GAUSSIAN, 9, 9)
storage = cv.CreateMat(im.rows, 1, cv.CV_32FC3)
cv.HoughCircles(edges, storage, cv.CV_HOUGH_GRADIENT, 2, gray.height/4, 200, 100)
# Now, supposing it found circles, how do I extract the information?
print storage.r
if __name__ == '__main__':
main()
Also, what value do the last two parameters of HoughCircles
need to have in order for me to detect really small circles (like 3mm on the screen) ?
Thank you all for your time and effort trying to help me!
The image I'm working with is this:
The last two parameters are what seem to be passed to cv.Canny()
, which implies that cv.Canny()
is called from within cv.HoughCircles()
. I'm not too sure about that.
As for the sizes, it seems like the next two parameters (after 200, 100)
default to 0
, which might mean that all sizes are detected.
From the C++ example's source, I can also guess that you don't need to do a Canny edge detection:
#include <cv.h>
#include <highgui.h>
#include <math.h>
using namespace cv;
int main(int argc, char** argv)
{
Mat img, gray;
if( argc != 2 && !(img=imread(argv[1], 1)).data)
return -1;
cvtColor(img, gray, CV_BGR2GRAY);
// smooth it, otherwise a lot of false circles may be detected
GaussianBlur( gray, gray, Size(9, 9), 2, 2 );
vector<Vec3f> circles;
HoughCircles(gray, circles, CV_HOUGH_GRADIENT,
2, gray->rows/4, 200, 100 );
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// draw the circle center
circle( img, center, 3, Scalar(0,255,0), -1, 8, 0 );
// draw the circle outline
circle( img, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
namedWindow( "circles", 1 );
imshow( "circles", img );
return 0;
}
You're trying to convert this C++ code into Python, I assume?
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// draw the circle center
circle( img, center, 3, Scalar(0,255,0), -1, 8, 0 );
// draw the circle outline
circle( img, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
As far as I can tell, CvMat
objects are iterable, just like a list:
for circle in storage:
radius = circle[2]
center = (circle[0], circle[1])
cv.Circle(im, center, radius, (0, 0, 255), 3, 8, 0)
I don't have any test images, so don't take my word that this works. Your complete code would might be:
import cv
def main():
im = cv.LoadImage('Proba.jpg')
gray = cv.CreateImage(cv.GetSize(im), 8, 1)
edges = cv.CreateImage(cv.GetSize(im), 8, 1)
cv.CvtColor(im, gray, cv.CV_BGR2GRAY)
#cv.Canny(gray, edges, 20, 55, 3)
storage = cv.CreateMat(im.width, 1, cv.CV_32FC3)
cv.HoughCircles(edges, storage, cv.CV_HOUGH_GRADIENT, 5, 25, 200, 10)
for i in xrange(storage.width - 1):
radius = storage[i, 2]
center = (storage[i, 0], storage[i, 1])
print (radius, center)
cv.Circle(im, center, radius, (0, 0, 255), 3, 8, 0)
cv.NamedWindow('Circles')
cv.ShowImage('Circles', im)
cv.WaitKey(0)
if __name__ == '__main__':
main()