Python OpenCV:使用轮廓上的大多数点拟合椭圆(而不是最小二乘法)

Python OpenCV:使用轮廓上的大多数点拟合椭圆(而不是最小二乘法),python,c++,opencv,computer-vision,opencv3.0,Python,C++,Opencv,Computer Vision,Opencv3.0,我有一个二值化图像,我已经对其使用了打开/关闭形态学操作(这是我能得到的最干净的图像,相信我),看起来是这样的: 如你所见,有一个明显的椭圆,顶部有一些变形注意:我没有关于圆的大小的事先信息,这必须运行得非常快(我发现HoughCircles太慢)。我正在尝试找出如何将椭圆拟合到它,以便使拟合椭圆上与形状上的边对应的点数最大化。也就是说,我想要这样的结果: 然而,我似乎无法在OpenCV中找到这样做的方法。使用常用工具fitEllipse(蓝线)和minarealect(绿线),我得到以下结

我有一个二值化图像,我已经对其使用了打开/关闭形态学操作(这是我能得到的最干净的图像,相信我),看起来是这样的:

如你所见,有一个明显的椭圆,顶部有一些变形注意:我没有关于圆的大小的事先信息,这必须运行得非常快(我发现HoughCircles太慢)。我正在尝试找出如何将椭圆拟合到它,以便使拟合椭圆上与形状上的边对应的点数最大化。也就是说,我想要这样的结果:

然而,我似乎无法在OpenCV中找到这样做的方法。使用常用工具
fitEllipse
(蓝线)和
minarealect
(绿线),我得到以下结果:


这显然不代表我要检测的实际椭圆。有没有想过我该如何做到这一点?很高兴在Python或C++中看到例子。

< P> Hough Circle是完美的。如果你知道直径,你可以得到一个更好的解决方案。如果您只知道一个范围,这可能最适合:

编辑:这比拟合的椭圆效果更好的原因是:如果你正在寻找一个圆,你应该使用一个圆作为模型。这本书解释了这个美丽的想法

顺便说一句,你也可以通过打开和关闭来实现这一点。(考虑到你现在的圈子有多大)


鉴于所示的示例图像,我对以下说法非常怀疑:

我已经对其使用了打开/关闭形态学操作(这是我能得到的最干净的,相信我)

在阅读了你的评论之后

对于精度,我需要它在大约2像素的精度适合

我很确定,使用形态学运算可能会有很好的近似

请查看以下代码:

导入cv2
#加载图像(作为以后绘制圆的BGR)
image=cv2.imread('images/hvFJF.jpg',cv2.imread\u COLOR)
#转换为灰度
灰色=cv2.CVT颜色(图像,cv2.COLOR\u BGR2GRAY)
#摆脱可能的JPG工件(人们什么时候学会使用PNG?…)
_,gray=cv2.阈值(gray,128255,cv2.阈值_二进制)
#缩小图像(按系数4)以加快形态学运算
灰色=cv2。调整大小(灰色,dsize=(0,0),fx=0.25,fy=0.25)
#形态闭合:去掉这个洞
gray=cv2.morphologyEx(gray,cv2.MORPH_CLOSE,cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)))
#形态开口:去掉圆圈顶部的东西
gray=cv2.morphologyEx(gray,cv2.MORPH_OPEN,cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(121,121)))
#将图像大小调整为原始大小
gray=cv2.resize(gray,dsize=(image.shape[1],image.shape[0]))
#查找轮廓(仅最外部)
碳纳米管,碳纳米管=碳纳米管2.碳纳米管(灰色,碳纳米管2.碳纳米管外部,碳纳米管2.碳纳米管链约无)
#在输入图像中绘制找到的轮廓
图像=cv2。绘制轮廓(图像,CNT,-1,(0,0,255),2)
cv2.imwrite('images/intermediate.png',灰色)
cv2.imwrite('images/result.png',image)
中间图像如下所示:

最终结果如下所示:

因为你的形象相当大,我认为,缩小它不会有什么坏处。以下形态学操作(大幅)加速,这可能会引起您的设置兴趣

根据你的陈述:

注意:我没有关于圆圈大小的事先信息[…]

您可以从输入中找到上述内核大小的近似值。由于只给出了一个示例图像,我们无法知道该问题的可变性


希望有帮助

你能发布你目前使用的脚本吗?谢谢!我应该提到两点:(A)不幸的是,我不知道这个圆有多大。可以是图像宽度的10%到90%。(b) 这必须在嵌入式设备上近实时运行;我以前尝试过HoughCircles,但速度非常慢(这是OpenCV的HoughCircles函数,但性能可能与您建议的有所不同)。请问您使用的是哪种硬件,以及您需要的结果有多精确?对于嵌入式系统,您可以使用RANSAC。这可能不会为您提供最佳结果。但它是强大的。它将始终返回找到的最佳结果,并将始终花费相同的计算时间。硬件为四核@1.4GHz,可用内存约为400 MB。为了精确,我需要它的精度在2像素以内。嗯,这很紧。我的意思是有些算法可以达到亚像素精度。你能解释一下什么是实时吗?实时意味着任务需要在一定时间内执行,否则可能出现故障。你的硬件可能足够好,这取决于你需要多少时间来进行计算。我不应该用“实时”这个词,你是对的。我的意思是,在这个硬件上,它应该在大约300毫秒内完成。然而,霍夫圆的一个问题是,它并不总是一个精确的圆,长轴和短轴之间可能存在高达2%的差异(能够检测到这种差异很重要)。
import skimage
import matplotlib.pyplot as plt
import numpy as np
from skimage import data, color
from skimage.feature import canny
from skimage.draw import circle_perimeter
from skimage.util import img_as_ubyte
from skimage.transform import hough_circle, hough_circle_peaks


image = skimage.io.imread("hvFJF.jpg")

# Load picture and detect edges

edges = canny(image, sigma=3, low_threshold=10, high_threshold=50)


# Detect two radii
hough_radii = np.arange(250, 300, 10)
hough_res = hough_circle(edges, hough_radii)

# Select the most prominent 5 circles
accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii,
                                           total_num_peaks=3)

# Draw them
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(10, 4))
image = color.gray2rgb(image)
for center_y, center_x, radius in zip(cy, cx, radii):
    circy, circx = circle_perimeter(center_y, center_x, radius)
    image[circy, circx] = (220, 20, 20)

ax.imshow(image, cmap=plt.cm.gray)
plt.show()