Python 和 OpenCV.如何检测图像中的所有(填充)圆形/圆形对象?

问题描述

我正在尝试制作一个程序,它可以打开图像,扫描它以查找圆形/圆形并返回坐标,以便我可以使用 cv.Circle 函数在检测到的圆上绘制圆.

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.

我的问题是:如何使用 cv.HoughCircles() 获取图像中检测到的圆的坐标/半径?

My question is: How do I get the coordinates/radii of the circles detected in an image using cv.HoughCircles() ?

使用 this 页面,我发现了如何检测圆圈(这花了我因为我不懂阈值之类的术语,而且 Python 的 OpenCV 文档真的很差,几乎没有),所以要花很多时间来找出答案.不幸的是,在该页面上,它没有显示如何提取从创建的 CvMat 中检测到的每个圆圈的信息.如何提取该信息/是否有其他方法(例如使用 MemoryStorage() )?

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() ) ?

这是我目前的代码:

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()

另外,HoughCircles 的最后两个参数需要什么值才能让我检测到非常小的圆圈(比如屏幕上的 3mm)?

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:


解决方案

最后两个参数似乎是传递给cv.Canny()的,这意味着cv.Canny() 从 within cv.HoughCircles() 调用.我不太确定.

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.

至于尺寸,后面的两个参数(在200, 100之后)似乎默认为0,这可能意味着all 检测大小.

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.

从 C++ 示例的源代码中,我也可以猜到您不需要进行 Canny 边缘检测:

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;
}

我想您是在尝试将此 C++ 代码转换为 Python 吗?

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 );
}

据我所知,CvMat 对象是可迭代的,就像一个列表:

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()

相关文章