Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
213 views
in Technique[技术] by (71.8m points)

python - Opencv divide contacted circles into single

I have an image to process.I need detect all the circles in the image.Here is it. org image

And here is my code.

import cv2
import cv2.cv as cv
img = cv2.imread(imgpath)
cv2.imshow("imgorg",img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow("gray",gray)
ret,thresh = cv2.threshold(gray, 199, 255, cv.CV_THRESH_BINARY_INV)
cv2.imshow("thresh",thresh)
cv2.waitKey(0)
cv2.destrotAllWindows()

Then,I got a image like this. enter image description here

And I tried to use erode and dilate to divided them into single.But it doesnt work.My question is how to divide these contacted circles into single,so i can detect them.

According to @Micka's idea,I tried to process the image in following way,and here is my code.

import cv2
import cv2.cv as cv
import numpy as np

def findcircles(img,contours):
    minArea = 300;
    minCircleRatio = 0.5;
    for  contour  in contours:

        area = cv2.contourArea(contour)
        if area < minArea: 
            continue

        (x,y),radius = cv2.minEnclosingCircle(contour)
        center = (int(x),int(y))
        radius = int(radius)
        circleArea = radius*radius*cv.CV_PI;

        if area/circleArea < minCircleRatio:
             continue;
        cv2.circle(img, center, radius, (0, 255, 0), 2)
        cv2.imshow("imggg",img)

img = cv2.imread("a.png")
cv2.imshow("org",img)

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,threshold = cv2.threshold(gray, 199, 255,cv. CV_THRESH_BINARY_INV)
cv2.imshow("threshold",threshold)

blur = cv2.medianBlur(gray,5)
cv2.imshow("blur",blur)

laplacian=cv2.Laplacian(blur,-1,ksize = 5,delta = -50)
cv2.imshow("laplacian",laplacian)

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(7,7))
dilation = cv2.dilate(laplacian,kernel,iterations = 1)
cv2.imshow("dilation", dilation)

result= cv2.subtract(threshold,dilation) 
cv2.imshow("result",result)

contours, hierarchy = cv2.findContours(result,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
findcircles(gray,contours)

But I dont get the same effect as @Micka's.I dont know which step is wrong.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Adapting the idea of @jochen I came to this:

  1. extract the full circle mask as you've done (I called it fullForeground )

enter image description here

  1. from your colored image, compute grayscale, blur (median blur size 7) it and and extract edges, for example with cv::Laplacian This laplacian thresholded > 50 gives:

cv::Laplacian(blurred, lap, 0, 5); // no delta lapMask = lap > 50; // thresholding to values > 50

enter image description here

This one dilated once gives:

cv::dilate(lapMask, dilatedThresholdedLaplacian, cv::Mat()); // dilate the edge mask once

enter image description here

Now subtraction fullForeground - dilatedThresholdedLaplacian (same as and_not operator for this type of masks) gives:

enter image description here

from this you can compute contours. For each contour you can compute the area and compare it to the area of an enclosing circle, giving this code and result:

std::vector<std::vector<cv::Point> > contours;
cv::findContours(separated.clone(), contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);

double minArea = 500;
double minCircleRatio = 0.5;
for(unsigned int i=0; i<contours.size(); ++i)
{
    double cArea = cv::contourArea(contours[i]);
    if(cArea < minArea) continue;

    //filteredContours.push_back(contours[i]);
    //cv::drawContours(input, contours, i, cv::Scalar(0,255,0), 1);
    cv::Point2f center;
    float radius;
    cv::minEnclosingCircle(contours[i], center, radius);

    double circleArea = radius*radius*CV_PI;

    if(cArea/circleArea < minCircleRatio) continue;

    cv::circle(input, center, radius, cv::Scalar(0,0,255),2);
}

enter image description here

here is another image showing the coverage:

enter image description here

hope this helps


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...