C ++-使用opencv编写鲁棒的(颜色和尺寸不变)圆检测(基于霍夫变换或其他功能)

我编写了以下非常简单的python代码以在图像中查找圆:

import cv
import numpy as np

WAITKEY_DELAY_MS = 10
STOP_KEY = 'q'

cv.NamedWindow("image - press 'q' to quit", cv.CV_WINDOW_AUTOSIZE);
cv.NamedWindow("post-process", cv.CV_WINDOW_AUTOSIZE);

key_pressed = False
while key_pressed != STOP_KEY:

    # grab image
    orig = cv.LoadImage('circles3.jpg')

    # create tmp images
    grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
    processed = cv.CreateImage(cv.GetSize(orig), 8, 1)


    cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)

    cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)

    # do some processing on the grey scale image
    cv.Erode(grey_scale, processed, None, 10)
    cv.Dilate(processed, processed, None, 10)
    cv.Canny(processed, processed, 5, 70, 3)
    cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)

    storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)

    # these parameters need to be adjusted for every single image
    HIGH = 50
    LOW = 140

    try: 
        # extract circles
        cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, HIGH, LOW)

        for i in range(0, len(np.asarray(storage))):
            print "circle #%d" %i
            Radius = int(np.asarray(storage)[i][0][2])
            x = int(np.asarray(storage)[i][0][0])
            y = int(np.asarray(storage)[i][0][1])
            center = (x, y)

            # green dot on center and red circle around
            cv.Circle(orig, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
            cv.Circle(orig, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

            cv.Circle(processed, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
            cv.Circle(processed, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

    except:
        print "nothing found"
        pass

    # show images
    cv.ShowImage("image - press 'q' to quit", orig)
    cv.ShowImage("post-process", processed)

    cv_key = cv.WaitKey(WAITKEY_DELAY_MS)
    key_pressed = chr(cv_key & 255)

从下面的两个示例中可以看出,“寻圆质量”变化很大:

情况1:

input1 detection1 post-processed1

案例2:

input2 detection2 post-processed2

Case1和Case2基本是同一张图片,但是算法仍然可以检测到不同的圆圈。 如果我向算法显示大小不同的圆圈的图像,则圆圈检测甚至可能完全失败。 这主要是由于HIGHLOW参数需要针对每个新图片分别进行调整。

因此,我的问题是:使该算法更强大的各种可能性是什么? 它应该是大小和颜色不变的,以便检测到具有不同颜色和大小的不同圆圈。 也许使用霍夫变换不是做事的最佳方法? 有更好的方法吗?

memyself asked 2020-02-29T14:27:08Z
6个解决方案
36 votes

以下是基于我作为视觉研究者的经验。 从您的问题出发,您似乎对可能的算法和方法感兴趣,而不只是对一段有效的代码感兴趣。 首先,我为您的示例图像提供了一个快速而肮脏的Python脚本,并显示了一些结果证明它可以解决您的问题。 解决这些问题之后,我会尝试回答您有关健壮检测算法的问题。

快速结果

带有检测到的圆的一些示例图像(除您之外的所有图像均已从flickr.com下载并获得CC许可)(无需更改/调整任何参数,正是使用以下代码在所有图像中提取圆):detected blobs in the sample image 1 detected blobs in the sample image 2 lots of circles blobs in the flickr image 1

代码(基于MSER Blob检测器)

这是代码:

import cv2
import math
import numpy as np

d_red = cv2.cv.RGB(150, 55, 65)
l_red = cv2.cv.RGB(250, 200, 200)

orig = cv2.imread("c.jpg")
img = orig.copy()
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

detector = cv2.FeatureDetector_create('MSER')
fs = detector.detect(img2)
fs.sort(key = lambda x: -x.size)

def supress(x):
        for f in fs:
                distx = f.pt[0] - x.pt[0]
                disty = f.pt[1] - x.pt[1]
                dist = math.sqrt(distx*distx + disty*disty)
                if (f.size > x.size) and (dist<f.size/2):
                        return True

sfs = [x for x in fs if not supress(x)]

for f in sfs:
        cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), d_red, 2, cv2.CV_AA)
        cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), l_red, 1, cv2.CV_AA)

h, w = orig.shape[:2]
vis = np.zeros((h, w*2+5), np.uint8)
vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
vis[:h, :w] = orig
vis[:h, w+5:w*2+5] = img

cv2.imshow("image", vis)
cv2.imwrite("c_o.jpg", vis)
cv2.waitKey()
cv2.destroyAllWindows()

如您所见,它基于MSER斑点检测器。 除了简单映射到灰度之外,该代码不会对图像进行预处理。 因此,预期会丢失图像中的那些模糊的黄色斑点。

理论

简而言之:除了只给出两个示例图像而没有描述之外,您不会告诉我们您对该问题有什么了解。 在这里,我解释了为什么我谦虚地认为,在询问什么有效的方法来解决问题之前,有关于该问题的更多信息很重要。

回到主要问题:解决此问题的最佳方法是什么?让我们将其视为搜索问题。 为了简化讨论,假设我们正在寻找具有给定大小/半径的圆。 因此,问题归结为寻找中心。 每个像素都是一个候选中心,因此,搜索空间包含所有像素。

P = {p1, ..., pn} 
P: search space
p1...pn: pixels

要解决此搜索问题,应定义其他两个功能:

E(P) : enumerates the search space
V(p) : checks whether the item/pixel has the desirable properties, the items passing the check are added to the output list

假设算法的复杂性无关紧要,则可以使用穷举搜索或蛮力搜索,其中E占用每个像素并传递给V。在实时应用中,重要的是减小搜索空间并优化V的计算效率 。

我们正在接近主要问题。我们如何定义V,以更精确地确定应聘者的哪些属性应作为度量,以及应如何解决将其分为理想和不理想的二分法问题。最常见的方法是找到一些属性,这些属性可用于基于属性的度量来定义简单的决策规则。这是您反复尝试所做的事情。您正在通过学​​习正面和负面的例子来对分类器进行编程。这是因为您使用的方法不知道您想做什么。您必须调整/调整决策规则的参数和/或对数据进行预处理,以减少用于二分法问题的方法所使用的(所需候选)属性的变化。您可以使用机器学习算法来查找给定示例集合的最佳参数值。有很多学习算法,从决策树到基因编程,都可以用于解决此问题。您还可以使用一种学习算法来找到几种圆检测算法的最佳参数值,并查看哪种算法具有更高的精度。这给您只需要收集样本图像的学习算法带来了主要负担。

经常被忽略的另一种提高鲁棒性的方法是利用额外的随时可用信息。 如果您几乎不费吹灰之力就知道圆圈的颜色,则可以大大提高检测器的精度。 如果您知道圆在平面上的位置,并且想要检测成像的圆,则应该记住这两组位置之间的转换由2D单应性描述。 单应可以仅使用四个点来估计。 然后,您可以提高鲁棒性以拥有坚如磐石的方法。 通常会低估特定领域知识的价值。 以这种方式来看,在第一种方法中,我们尝试基于有限数量的样本来近似一些决策规则。 在第二种方法中,我们知道决策规则,只需要找到一种在算法中有效利用决策规则的方法。

摘要

总而言之,有两种方法可以提高解决方案的准确性/稳健性:

  1. 基于工具:查找更易于使用的算法/减少参数数量/调整算法/使用机器学习算法自动执行此过程
  2. 基于信息的:您是否正在使用所有容易获得的信息? 在问题中,您不会提及您对问题的了解。

对于您共享的这两个图像,我将使用斑点检测器而不是HT方法。 对于背景减法,我建议尝试估算背景的颜色,因为在两幅图像中背景的颜色没有变化,而圆圈的颜色却有所变化。 并且大部分区域是裸露的。

fireant answered 2020-02-29T14:28:41Z
28 votes

这是一个很大的建模问题。 我有以下建议/想法:

  1. 将图像分割为RGB,然后进行处理。
  2. 预处理。
  3. 动态参数搜索。
  4. 添加约束。
  5. 确保您要检测的内容。

更详细地:

1:如其他答案所述,直接转换为灰度会丢弃太多信息-亮度与背景相似的任何圆圈都会丢失。 更好地考虑隔离或在不同色彩空间中使用色彩通道。 这里有两种方法:分别在每个预处理通道上执行AdaptiveThresholding,然后组合结果,或者处理通道,然后组合它们,然后操作param2。在下面的尝试中,我尝试了第二种 方法,拆分为RGB通道,进行处理,然后合并。 为避免合并时图像过饱和,我使用param2来避免此问题(在此阶段,我的圈子始终是白色背景上的黑色环/光盘)。

2:预处理非常棘手,通常最好配合使用。 我使用了AdaptiveThresholding,它是一种非常强大的卷积方法,可以通过基于像素的局部平均值对像素进行阈值处理来增强图像中的边缘(类似的过程也发生在哺乳动物视觉系统的早期路径中)。 这也很有用,因为它可以减少一些噪音。 我只用了一次就使用了param2。 我保留了其他参数的设置方式。 似乎在HoughCircles之前使用param2确实对找到“实心圆”有很大帮助,因此最好将其保留。这种预处理非常繁重,并且可能导致带有更多“毛圈”的误报,但在我们的情况下 这也许是可取的?

3:正如您已经注意到的那样,实际上需要从文档中为每个图像调整HoughCircles参数AdaptiveThresholding(您的参数param2)以获得最佳解决方案:

它越小,可以检测到的假圆圈越多。

麻烦的是,每个图像的最佳位置都会有所不同。 我认为最好的方法是设置一个条件,并搜索不同的AdaptiveThresholding值,直到满足此条件为止。 您的图像显示了不重叠的圆,当param2太低时,我们通常会得到重叠圆的负载。 所以我建议搜索:

不重叠且不包含圆圈的最大数量

因此,我们将继续调用具有不同值AdaptiveThresholding的HoughCircles,直到满足此要求为止。 我在下面的示例中这样做,只是增加param2,直到达到阈值假设。 如果执行二进制搜索来查找何时满足,它将更快(并且相当容易做到),但是您需要谨慎对待异常处理,因为opencv经常会为param2的无辜外观值抛出错误(至少在 我的安装)。 我们非常有用的另一种匹配条件是圈数。

4:我们可以在模型中添加更多约束吗? 我们可以告诉模型更多的内容,这可以使我们轻松完成检测圆环的任务。 例如,我们是否知道:

  • 圈数。 -甚至上限或下限也是有帮助的。
  • 圆圈,背景或“非圆圈”的可能颜色。
  • 他们的大小。
  • 它们可以在图像中的位置。

5:图像中的某些斑点只能被简单地称为圆圈! 考虑一下第二个图像中的两个“非圆形斑点”,我的代码找不到它们(好!),但是...如果我“ photoshop”它们,使其更加圆形,我的代码可以找到它们... 也许如果您要检测不是圆形的事物,则最好使用其他方法,例如AdaptiveThresholding

问题

通过进行大量的预处理AdaptiveThresholding和'Canny',图像中的要素可能会变形很多,这可能会导致错误的圆形检测或错误的半径报告。 例如,处理后的大型实心圆盘可能会出现一个环,因此HughesCircles可能会找到内环。 此外,甚至文档都指出:

...通常该功能可以很好地检测圆的中心,但是可能无法找到正确的半径。

如果您需要更精确的半径检测,建议使用以下方法(未实现):

  • 在原始图像上,从扩大的十字形中报告的圆心开始的光线轨迹(4线:上/下/左/右)
  • 在每个RGB通道中分别执行此操作
  • 以明智的方式(例如,根据需要翻转,偏移,缩放等)将每个射线的每个通道的此信息组合起来
  • 取每条光线的前几个像素的平均值,用它来检测光线发生明显偏离的位置。
  • 这4个点是圆周上点的估计。
  • 使用这四个估计来确定更准确的半径和中心位置(!)。
  • 这可以通过使用扩展环而不是四射线来概括。

结果

最后的代码在很多时候都做得很好,这些示例是通过如下代码完成的:

检测第一张图片中的所有圈子:enter image description here

在应用Canny滤镜之前,预处理后的图像的外观(不同的色环非常明显):enter image description here

检测第二张图像中除了两个(斑点)以外的所有图像:enter image description here

更改后的第二张图像(斑点呈圆形,大椭圆形变得更圆,从而改善了检测),所有检测到:enter image description here

在这幅康定斯基画中的检测中心上做得很好(由于边界条件,我找不到同心环)。enter image description here

码:

import cv
import numpy as np

output = cv.LoadImage('case1.jpg')
orig = cv.LoadImage('case1.jpg')

# create tmp images
rrr=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
ggg=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
bbb=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
processed = cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)

def channel_processing(channel):
    pass
    cv.AdaptiveThreshold(channel, channel, 255, adaptive_method=cv.CV_ADAPTIVE_THRESH_MEAN_C, thresholdType=cv.CV_THRESH_BINARY, blockSize=55, param1=7)
    #mop up the dirt
    cv.Dilate(channel, channel, None, 1)
    cv.Erode(channel, channel, None, 1)

def inter_centre_distance(x1,y1,x2,y2):
    return ((x1-x2)**2 + (y1-y2)**2)**0.5

def colliding_circles(circles):
    for index1, circle1 in enumerate(circles):
        for circle2 in circles[index1+1:]:
            x1, y1, Radius1 = circle1[0]
            x2, y2, Radius2 = circle2[0]
            #collision or containment:
            if inter_centre_distance(x1,y1,x2,y2) < Radius1 + Radius2:
                return True

def find_circles(processed, storage, LOW):
    try:
        cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, 30, LOW)#, 0, 100) great to add circle constraint sizes.
    except:
        LOW += 1
        print 'try'
        find_circles(processed, storage, LOW)
    circles = np.asarray(storage)
    print 'number of circles:', len(circles)
    if colliding_circles(circles):
        LOW += 1
        storage = find_circles(processed, storage, LOW)
    print 'c', LOW
    return storage

def draw_circles(storage, output):
    circles = np.asarray(storage)
    print len(circles), 'circles found'
    for circle in circles:
        Radius, x, y = int(circle[0][2]), int(circle[0][0]), int(circle[0][1])
        cv.Circle(output, (x, y), 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
        cv.Circle(output, (x, y), Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

#split image into RGB components
cv.Split(orig,rrr,ggg,bbb,None)
#process each component
channel_processing(rrr)
channel_processing(ggg)
channel_processing(bbb)
#combine images using logical 'And' to avoid saturation
cv.And(rrr, ggg, rrr)
cv.And(rrr, bbb, processed)
cv.ShowImage('before canny', processed)
# cv.SaveImage('case3_processed.jpg',processed)
#use canny, as HoughCircles seems to prefer ring like circles to filled ones.
cv.Canny(processed, processed, 5, 70, 3)
#smooth to reduce noise a bit more
cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 7, 7)
cv.ShowImage('processed', processed)
#find circles, with parameter search
storage = find_circles(processed, storage, 100)
draw_circles(storage, output)
# show images
cv.ShowImage("original with circles", output)
cv.SaveImage('case1.jpg',output)

cv.WaitKey(0)
fraxel answered 2020-02-29T14:31:57Z
12 votes

嗯,是的。。。圆问题的旧颜色/尺寸不变式(又叫霍夫变换太具体且不够鲁棒)...

过去,我更多地依赖于OpenCV的结构和形状分析功能。 您可以从“示例”文件夹中获得一个非常好的主意-尤其是fitellipse.pysquares.py

为了便于说明,我根据您的原始资料提供了这些示例的混合版本。 检测到的轮廓为绿色,拟合的椭圆为红色。

enter image description here

还不存在:

  • 预处理步骤需要进行一些调整以检测更微弱的圆圈。
  • 您可以进一步测试轮廓以确定其是否为圆形...

祝好运!

import cv
import numpy as np

# grab image
orig = cv.LoadImage('circles3.jpg')

# create tmp images
grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
processed = cv.CreateImage(cv.GetSize(orig), 8, 1)

cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)

cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)

# do some processing on the grey scale image
cv.Erode(grey_scale, processed, None, 10)
cv.Dilate(processed, processed, None, 10)
cv.Canny(processed, processed, 5, 70, 3)
cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)

#storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)
storage = cv.CreateMemStorage(0)

contours = cv.FindContours(processed, storage, cv.CV_RETR_EXTERNAL)
# N.B. 'processed' image is modified by this!

#contours = cv.ApproxPoly (contours, storage, cv.CV_POLY_APPROX_DP, 3, 1) 
# If you wanted to reduce the number of points...

cv.DrawContours (orig, contours, cv.RGB(0,255,0), cv.RGB(255,0,0), 2, 3, cv.CV_AA, (0, 0)) 

def contour_iterator(contour):
  while contour:
    yield contour
    contour = contour.h_next()

for c in contour_iterator(contours):
  # Number of points must be more than or equal to 6 for cv.FitEllipse2
  if len(c) >= 6:
    # Copy the contour into an array of (x,y)s
    PointArray2D32f = cv.CreateMat(1, len(c), cv.CV_32FC2)

    for (i, (x, y)) in enumerate(c):
      PointArray2D32f[0, i] = (x, y)

    # Fits ellipse to current contour.
    (center, size, angle) = cv.FitEllipse2(PointArray2D32f)

    # Convert ellipse data from float to integer representation.
    center = (cv.Round(center[0]), cv.Round(center[1]))
    size = (cv.Round(size[0] * 0.5), cv.Round(size[1] * 0.5))

    # Draw ellipse
    cv.Ellipse(orig, center, size, angle, 0, 360, cv.RGB(255,0,0), 2,cv.CV_AA, 0)

# show images
cv.ShowImage("image - press 'q' to quit", orig)
#cv.ShowImage("post-process", processed)
cv.WaitKey(-1)

编辑:

只是更新而已,我相信所有这些答案的主要主题是,还有许多进一步的假设和约束条件可以应用于您寻求承认为通函的内容。 我自己的回答对此毫无用处-无论是低级预处理还是高级几何拟合。 由于绘制方式或图像的非仿射/投影变换,以及渲染/捕获方式的其他属性(颜色,噪声,光照, 边缘厚度)-所有这些都会在一张图像内产生任意数量的可能候选圆。

有更复杂的技术。 但是他们会花费你的。 我个人喜欢@fraxel使用自适应阈值的想法。 那是快速,可靠和合理的健壮性。 然后,您可以通过椭圆轴的简单比率测试来进一步测试最终轮廓(例如使用Hu矩)或拟合-例如 如果((min(size)/ max(size))> 0.7)。

像“计算机视觉”一样,实用主义,原则和言语之间也存在着张力。 正如我喜欢告诉那些认为CV很简单的人一样,这并非易事-实际上,这是AI完整的问题。 在大多数情况下,您通常可以期望的最好的东西就是它在大多数情况下都有效。

tiluki answered 2020-02-29T14:33:06Z
9 votes

查看您的代码,发现以下内容:

  • 灰度转换。 我了解您为什么这样做,但意识到您正在扔那里的信息。 如您在“后期处理”图像中看到的,您的黄色圆圈是与背景强度相同,只是颜色不同。

  • 去除噪声后的边缘检测(消除/扩张)。 这不是必须的。 坎尼应该照顾这个。

  • 坎尼边缘检测。 您的“开放”圆有两个边缘,一个内边缘和一个外边缘。 由于它们非常接近,因此Canny高斯滤镜可能会将它们加在一起。 如果不是这样,您将有两个边缘并拢。 即 在Canny之前,您有很多开放的圈子。 然后,您分别具有0/2和1个边。 由于Hough再次调用Canny,因此在第一种情况下,两个边缘可能会平滑在一起(取决于初始宽度),这就是为什么核心Hough算法可以将空心圆和实心圆视为相同的原因。

因此,我的第一个建议是更改灰度映射。 不要使用强度,而要使用色相/饱和度/值。 另外,使用差分方法-您正在寻找边缘。 因此,计算HSV转换,平滑副本,然后求出原始副本和平滑副本之间的差。 这将为您获得每个点的dH, dS, dV值(色相,饱和度,值的局部变化)。 平方并加法得到一维图像,所有边缘(内部和外部)附近都有峰。

我的第二个建议是局部规范化,但是我不确定这是否有必要。 这个想法是,您不必太在意所得到的边缘信号的确切值,无论如何,它实际上应该是二进制的(是否为边缘)。 因此,您可以通过除以局部平均值(其中local等于边缘大小的数量级)来归一化每个值。

MSalters answered 2020-02-29T14:33:53Z
6 votes

如您所知,霍夫变换使用“模型”在(通常)边缘检测的图像中找到某些特征。 在param2的情况下,该模型是一个完美的圆。 这意味着可能不存在参数的组合,这将使其检测图片中更偏斜和椭圆形的圆圈,而不会增加误报的数量。 另一方面,由于潜在的投票机制,未封闭的完美圆圈或带有“凹痕”的完美圆圈可能会不断出现。 因此,根据您的预期输出,您可能会或可能不想使用此方法。

就是说,我发现有些事情可以帮助您使用此功能:

  1. param2在内部调用LOW,所以我想您可以忽略该调用。
  2. param2(您称为LOW)通常是围绕值2769065216209060060866进行初始化的。它用作对Canny867:cv.Canny(processed, cannied, HIGH, HIGH/2)的内部调用的参数。这样可能有助于自己运行2769065216209060060869,以了解设置HIGH如何影响正在工作的图像 通过霍夫变换。
  3. param2(您称为LOW)通常在值2769065216209060060866周围初始化。这是霍夫变换累加器的投票阈值。 设置较高意味着更多的假阴性,减少更多的假阳性。 我相信这是您要开始摆弄的第一个。

参考:[http://docs.opencv.org/3.0-beta/modules/imgproc/doc/feature_detection.html#houghcircles]

更新关于:填充的圆:使用霍夫变换找到圆形之后,可以通过对边界颜色进行采样并将其与假定的圆形内的一个或多个点进行比较来测试它们是否被填充。 或者,您可以将假定圆内的一个或多个点与给定的背景色进行比较。 如果先前的比较成功,则填充圆圈,如果替代的比较失败,则填充圆圈。

Eric answered 2020-02-29T14:34:43Z
2 votes

好的,看看图像。 我建议使用**Active Contours**

  • 活动轮廓关于活动轮廓的好处是,它们几乎可以完美地适合任何给定的形状。 无论是正方形还是三角形,对于您来说,它们都是理想的选择。
  • 如果您能够提取圆心,那就太好了。 主动轮廓始终需要一个起点,可以从该起点开始增长或缩小以适合。 中心不必始终与中心对齐。 稍微偏移仍可以。
  • 在您的情况下,如果让轮廓从中心向外扩展,则它们应位于圆弧边界处。
  • 请注意,增长或缩小的活动轮廓会使用气球能量,这意味着您可以向内或向外设置轮廓的方向。
  • 您可能需要使用灰度的渐变图像。 但是您仍然可以尝试颜色。 如果可行!
  • 而且,如果您不提供中心,请插入许多活动轮廓,然后进行缩放。 保留下来的轮廓,丢弃未解决的轮廓。 这是蛮力的方法。 将占用大量CPU资源。 但是将需要更仔细的工作,以确保您保留正确的轮廓并扔掉不良轮廓。

我希望这样可以解决问题。

answered 2020-02-29T14:35:35Z
translate from https://stackoverflow.com:/questions/9860667/writing-robust-color-and-size-invariant-circle-detection-with-opencv-based-on