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

Cal*_*lin 18 python geometry opencv image-processing detect

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

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

使用这个页面,我发现了如何检测圆圈(这花了我很多时间才发现,因为我不理解像阈值这样的术语,而Python的OpenCV文档真的很差,几乎没有).不幸的是,在该页面上没有显示如何提取从CvMat创建的每个圆圈中获取的信息.如何提取该信息/是否有其他方式(例如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()
Run Code Online (Sandbox Code Playgroud)

另外,HoughCircles为了让我能够检测出真正的小圆圈(如屏幕上的3mm),最后两个参数需要具有什么值?

谢谢大家的时间和精力来帮助我!

我正在使用的图像是这样的:在此输入图像描述

Ble*_*der 4

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

至于尺寸,似乎是接下来的两个参数(200, 100)默认为后0,这可能意味着检测到所有尺寸。

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

#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;
}
Run Code Online (Sandbox Code Playgroud)

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

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 );
}
Run Code Online (Sandbox Code Playgroud)

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

for circle in storage:
  radius = circle[2]
  center = (circle[0], circle[1])

  cv.Circle(im, center, radius, (0, 0, 255), 3, 8, 0)
Run Code Online (Sandbox Code Playgroud)

我没有任何测试图像,所以不要相信我说这有效。您的完整代码可能是:

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()
Run Code Online (Sandbox Code Playgroud)