简体   繁体   English

OpenCV:将单个圆拟合到图像(在 Python 中)

[英]OpenCV: Fitting a single circle to an image (in Python)

I have an image like this:我有这样的图像:

在此处输入图片说明

I need to fit an ellipse to the dark area (note: must be an ellipse, not a circle).我需要在黑暗区域拟合一个椭圆(注意:必须是椭圆,而不是圆)。 What is the best way to do this in OpenCV?在 OpenCV 中执行此操作的最佳方法是什么? My first step so far has been to apply an adaptive (Otsu) threshold to it, which results in:到目前为止,我的第一步是对其应用自适应 (Otsu) 阈值,结果是:

在此处输入图片说明

But I'm not sure where to go from there.但我不确定从那里去哪里。 I'm writing the app in Python, but it's more the algorithm design I'm looking for.我正在用 Python 编写应用程序,但更多的是我正在寻找的算法设计。

EDIT based on response/comment:基于响应/评论的编辑:

OK, so I have already tried the morphology.好的,所以我已经尝试了形态学。 Based on the OpenCV documentation , I did a 3-iteration "close" operation on it (dilation, then erosion) to remove the small particles, which results in:根据OpenCV 文档,我对其进行了 3 次迭代“关闭”操作(扩张,然后侵蚀)以去除小颗粒,结果:

在此处输入图片说明

Then, to expand it back out to closerto the original shape, I did a 3-iteration "open" operation (erosion, then dilation), which results in:然后,为了将其扩展回更接近原始形状,我进行了 3 次迭代“打开”操作(腐蚀,然后膨胀),结果:

在此处输入图片说明

From here, I did Canny edge detection, which resulted in:从这里开始,我做了 Canny 边缘检测,结果是:

在此处输入图片说明

Now, I used findContours on it, but ran into an issue.现在,我在其上使用了findContours ,但遇到了问题。 It found dozens of contours along the edge, each one a short segment along the circumference.它沿着边缘发现了几十个轮廓,每一个都是沿着圆周的一小段。 Which means, even if I take the maximum size contour, it might only represent 10% of the circumference, which is insufficient to accurately fit an ellipse.这意味着,即使我采用最大尺寸的轮廓,它也可能只代表周长的 10%,这不足以准确拟合椭圆。 This is why the other questions that @Demi-Lune suggested didn't work for me;这就是@Demi-Lune 建议的其他问题对我不起作用的原因; they all have very clean, sharp edges and findContours finds a nice single contour that covers the entire perimiter of each shape, but that doesn't happen for my messier image.它们都有非常干净、锐利的边缘, findContours找到了一个很好的单一轮廓,覆盖了每个形状的整个边界,但对于我的凌乱图像来说,这不会发生。 So, what's the best way to fit the ellipse from here?那么,从这里拟合椭圆的最佳方法是什么?

why don't you do thing like "close" then "open" to clear all the mess. 为什么不做“关闭”然后“打开”清除所有混乱的事情。

Raw image : 原始图片:

原始图像

Otsu : 大津:

大津

Close + open ; 关闭+打开; both with 7x7 kernel ; 都是7x7内核; The binary image is beauty and clean now. 二进制图像现在美观整洁。

关闭+打开

Only one contour is detect : 只检测到一个轮廓:

一个轮廓

The ellipse is as : (please not that your image is circle so ellipse should be in circle shape) 椭圆如下:(请注意,您的图像是圆形,因此椭圆应为圆形)

椭圆

If the object has circle shape, then use cv2.minEnclosingCircle is good. 如果对象有圆形,那么使用cv2.minEnclosingCircle是好的。 Or else, you can use cv2.fitEllipse to find the most fitted ellipse around the object. 或者,您可以使用cv2.fitEllipse查找对象周围最合适的椭圆。 Remember to do find contour with white object in black background. 记得在黑色背景中找到与白色物体的轮廓。

import cv2
import numpy as np

img = cv2.imread("1.jpg")

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_,thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
thresh = cv2.bitwise_not(thresh)

element = cv2.getStructuringElement(shape=cv2.MORPH_RECT, ksize=(5, 5))

morph_img = thresh.copy()
cv2.morphologyEx(src=thresh, op=cv2.MORPH_CLOSE, kernel=element, dst=morph_img)

contours,_ = cv2.findContours(morph_img,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

areas = [cv2.contourArea(c) for c in contours]
sorted_areas = np.sort(areas)

#bounding box (red)
cnt=contours[areas.index(sorted_areas[-1])] #the biggest contour
r = cv2.boundingRect(cnt)
cv2.rectangle(img,(r[0],r[1]),(r[0]+r[2],r[1]+r[3]),(0,0,255),2)

#min circle (green)
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv2.circle(img,center,radius,(0,255,0),2)

#fit ellipse (blue)
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img,ellipse,(255,0,0),2)


cv2.imshow("morph_img",morph_img)
cv2.imshow("img", img)
cv2.waitKey()

在此输入图像描述 在此输入图像描述

After applying an adaptive threshold to the image, you can use morphological operations to smooth your image with cv2.erode() and cv2.dilate() . 在对图像应用自适应阈值后,您可以使用形态学操作来使用cv2.erode()cv2.dilate()来平滑图像。 By doing these operations, you will be able to isolate your main circle image and remove small particles of noise. 通过这些操作,您将能够隔离主圆图像并去除小颗粒噪声。 Next, you can locate the circle in the image by using cv2.findContours() and filtering for the maximum size contour. 接下来,您可以使用cv2.findContours()并过滤最大尺寸轮廓来定位图像中的圆。 This will give you bounding box coordinates where you can find the center of the circle. 这将为您提供边界框坐标,您可以在其中找到圆的中心。 Once you have the center coordinates, you can then fit your eclipse. 一旦你有了中心坐标,你就可以适应你的日食。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM