简体   繁体   English

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

[英]Python and OpenCV. How do I detect all (filled)circles/round objects in an image?

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.Circle函数在检测到的圆上绘制圆圈。

My question is: How do I get the coordinates/radii of the circles detected in an image using cv.HoughCircles() ? 我的问题是:如何使用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). 使用这个页面,我发现了如何检测圆圈(这花了我很多时间才发现,因为我不理解像阈值这样的术语,而Python的OpenCV文档真的很差,几乎没有)。 Unfortunately, on that page it didn't show how to extract the information of each circle detected from the CvMat created. 不幸的是,在该页面上它没有显示如何提取从创建的CvMat检测到的每个圆的信息。 How do I extract that information/is there some other way(eg. with MemoryStorage() ) ? 如何提取该信息/是否有其他方式(例如,使用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) ? 另外, HoughCircles的最后两个参数需要具有什么值才能检测出真正的小圆圈(如屏幕上的3mm)?

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() . 最后两个参数是什么似乎要传递给cv.Canny()这意味着cv.Canny()是从内部被称为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. 至于尺寸,似乎接下来的两个参数(在200, 100)之后200, 100)默认为0 ,这可能意味着检测到所有尺寸。

From the C++ example's source, I can also guess that you don't need to do a Canny edge detection: 从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;
}

You're trying to convert this C++ code into Python, I assume? 你想把这个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 );
}

As far as I can tell, CvMat objects are iterable, just like a list: 据我所知, CvMat对象是可迭代的,就像一个列表:

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

Have a look at my answer to this question for some working source code (it's C but I used a C++ compiler cause it's more lenient). 看看对这个问题的答案是否有一些有用的源代码(它是C但是我使用的是C ++编译器,因为它更宽松)。

First, I cropped your image (to get something convenient to work with) and applied a threshold to your image to separate the foreground from the background: 首先,我裁剪你的图像(为了方便使用)并对你的图像应用一个阈值,将前景与背景分开:

在此输入图像描述

Then I directly applied the source code to the thresholded image. 然后我直接将源代码应用于阈值图像。 Here is the text output: 这是文本输出:

center x: 330 y: 507 A: 13 B: 4
center x: 78 y: 507 A: 22 B: 4
center x: 270 y: 503 A: 8 B: 8
center x: 222 y: 493 A: 21 B: 17
center x: 140 y: 484 A: 17 B: 18
center x: 394 y: 478 A: 17 B: 15
center x: 311 y: 468 A: 8 B: 8
center x: 107 y: 472 A: 12 B: 12
center x: 7 y: 472 A: 6 B: 19
center x: 337 y: 442 A: 10 B: 9
center x: 98 y: 432 A: 10 B: 10
center x: 357 y: 421 A: 7 B: 7
center x: 488 y: 429 A: 22 B: 23
center x: 411 y: 400 A: 13 B: 12
center x: 42 y: 400 A: 11 B: 12
center x: 365 y: 391 A: 14 B: 13
center x: 141 y: 396 A: 19 B: 19
center x: 9 y: 379 A: 8 B: 18
center x: 192 y: 365 A: 10 B: 9
center x: 347 y: 340 A: 20 B: 20
center x: 8 y: 305 A: 7 B: 13
center x: 95 y: 308 A: 23 B: 24
center x: 318 y: 297 A: 15 B: 15
center x: 159 y: 285 A: 10 B: 10
center x: 412 y: 291 A: 26 B: 27
center x: 504 y: 278 A: 6 B: 16
center x: 233 y: 277 A: 20 B: 20
center x: 459 y: 256 A: 15 B: 15
center x: 7 y: 239 A: 6 B: 9
center x: 377 y: 239 A: 14 B: 14
center x: 197 y: 228 A: 12 B: 12
center x: 302 y: 237 A: 12 B: 22
center x: 98 y: 224 A: 24 B: 23
center x: 265 y: 203 A: 18 B: 18
center x: 359 y: 202 A: 22 B: 22
center x: 149 y: 201 A: 20 B: 21
center x: 219 y: 169 A: 7 B: 9
center x: 458 y: 172 A: 20 B: 20
center x: 497 y: 157 A: 13 B: 21
center x: 151 y: 125 A: 18 B: 17
center x: 39 y: 109 A: 9 B: 10
center x: 81 y: 116 A: 20 B: 19
center x: 249 y: 104 A: 14 B: 13
center x: 429 y: 76 A: 23 B: 24
center x: 493 y: 33 A: 11 B: 10
center x: 334 y: 26 A: 12 B: 14

And here is the output image: 这是输出图像:

在此输入图像描述

The main problem is that circles that have merged together have not been detected at all. 主要问题是没有检测到合并在一起的圆圈。 The code was originally written for detecting filled ellipses only, so you can probably deal with this issue by tweaking the code. 该代码最初是为检测填充省略号而编写的,因此您可以通过调整代码来处理此问题。

A similar solution in python. python中的类似解决方案。 Originally I tried to run a contour detection described here , but it doesn't worked well. 最初我试图运行这里描述的轮廓检测,但它不能很好地工作。 So first some thresholding was necessary. 所以首先需要一些阈值处理。 The code for threshold is here: 阈值代码在这里:

    fimg = misc.imread("boubles.jpg")
    gimg = color.colorconv.rgb2grey(fimg)
    vimg = []
    for l in gimg:
        l2 = sign(l - 0.50) / 2 + 0.5
        vimg.append(l2)

    img = array(vimg)
    imshow(img)

With this I get an image like this: 有了这个我得到这样的图像:

阈值图像

And after edge detection described in the link above I got this: 在上面链接中描述的边缘检测后,我得到了这个:

找到轮廓

If you check the code, you will find that's really easy to count the objects. 如果检查代码,您会发现计算对象非常容易。 The only problem is, that some of the bubbles are counted twice. 唯一的问题是,一些气泡被计算两次。 And I guess the thresholding function can be improved as well. 我猜测阈值函数也可以改进。 But I suggest to use skimage it's easy to use and has good samples on their web page. 但我建议使用skimage,它易于使用,并且在他们的网页上有很好的样本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何检测哪些圆圈被填充+ OpenCV + Python - How to detect which circles are filled + OpenCV + Python 使用 Python OpenCV 检测图像中的所有圆圈(光学标记识别) - Detect All Circles in an image (Optical Mark Recognition) using Python OpenCV 如何检测实心圆网格? - How can I detect a grid of filled circles? 尝试在 openCV (python) 中使用 HoughCircles 检测所有圆圈 - Trying to detect all the circles with HoughCircles in openCV (python) 如何使用 python 操作霍夫圆以检测给定图像中的所有圆? - How to manipulate hough circles to detect all circles in the given image using python? 使用OpenCV和Python检测图像上不同种类的圆形和椭圆形 - Detect different kinds of circles and ovals on the image using OpenCV and Python 试图检测所有实心圆并获得它们的价值? OpenCV Python - Trying to detect all the filled circle and get their value? OpenCV Python 如何使用 OpenCV Python 准确检测空心圆(环)的位置? - How to accurately detect the positions of hollow circles (rings) with OpenCV Python? 如何使用OpenCV查找图像中所有圆的所有接触点 - How to find all contact points of all the circles in a image by using opencv Opencv Python:如何检测图片上的填充矩形 - Opencv Python: How to detect filled, rectangular shapes on picture
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM