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

后端 未结 3 1895
鱼传尺愫
鱼传尺愫 2020-12-23 15:19

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 dr

相关标签:
3条回答
  • 2020-12-23 15:46

    A similar solution in 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:

    thresholded image

    And after edge detection described in the link above I got this:

    find contours

    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.

    0 讨论(0)
  • 2020-12-23 15:48

    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()
    
    0 讨论(0)
  • 2020-12-23 15:48

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

    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:

    enter image description here

    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:

    enter image description here

    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.

    0 讨论(0)
提交回复
热议问题