我有一个要处理的图像。我需要检测图像中的所有圆圈。这就是它。
这是我的代码。
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()
我尝试使用侵蚀和扩张将它们分成单个。但它不起作用。我的问题是如何将这些接触的圆分成单个,所以我可以检测它们。
根据@ Micka的想法,我尝试按照以下方式处理图像,这是我的代码。
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)
但是我没有像@ Micka那样得到同样的效果。我不知道哪一步是错的。
答案 0 :(得分:5)
改编@jochen的想法我来到了这个:
fullForeground
)cv::Laplacian
该拉普拉斯阈值化&gt; 50给出: cv::Laplacian(blurred, lap, 0, 5); // no delta
lapMask = lap > 50; // thresholding to values > 50
这一次扩张一次给出:
cv::dilate(lapMask, dilatedThresholdedLaplacian, cv::Mat()); // dilate the edge mask once
现在减法fullForeground - dilatedThresholdedLaplacian
(与此类蒙版的and_not运算符相同)给出:
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);
}
这是显示覆盖范围的另一张图片:
希望这会有所帮助
答案 1 :(得分:2)
我认为第一个错误是thesh
的价值。
在您的示例中,命令cv2.threshold
将所有白色区域转换为黑色,将其他所有区域转换为白色。我建议使用thesh
的较小值,以便将所有黑色像素转换为白色,并将所有白色或“彩色”像素(在圆圈内)转换为黑色或反之亦然。 thesh的值应该比最亮的黑色像素大一点
有关详细信息,请参阅opencv docu for threshold
然后我会在阈值图像中放置opencv find all contours并过滤它们以获得“有效”圆圈,例如按尺寸和形状。
如果那不够,你可以从图像的其余部分分割内圆:首先计算threasholdImageA,所有白色区域都是黑色的。然后计算threasholdImageB,所有黑色区域都是黑色。然后将threasholdImageA和threasholdImageB(例如,与numpy.logical_and
)结合起来,得到二进制图像,其中内圈为白色,其余为黑色。当然,必须明智地选择阈值以获得特定结果。
这样也可以分割内部直接接触背景的圆圈。