HoughCircles 无法检测此图像上的圆圈

Posted

技术标签:

【中文标题】HoughCircles 无法检测此图像上的圆圈【英文标题】:HoughCircles can't detect circles on this image 【发布时间】:2016-06-27 07:34:30 【问题描述】:

我正在尝试检测图像中包含圆点的圆圈,但不幸的是我无法做到。我正在使用 opencv HoughTransform,但我找不到使这项工作的参数。

src = imread("encoded.jpg",1);
    /// Convert it to gray
    cvtColor(src, src_gray, CV_BGR2GRAY);

    vector<Vec3f> circles;

    /// Apply the Hough Transform to find the circles
    HoughCircles(src_gray, circles, CV_HOUGH_GRADIENT, 1, 10,
        100, 30, 1, 30 // change the last two parameters
        // (min_radius & max_radius) to detect larger circles
        );

    /// Draw the circles detected
    for (size_t i = 0; i < circles.size(); i++)
    
        cout << "Positive" << endl;
        Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
        int radius = cvRound(circles[i][2]);
        // circle center
        circle(src, center, 3, Scalar(0, 255, 0), -1, 8, 0);
        // circle outline
        circle(src, center, radius, Scalar(0, 0, 255), 3, 8, 0);
    

    /// Show your results
    namedWindow("Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE);
    imshow("Hough Circle Transform Demo", src_gray);
    waitKey(0);

我的图片在这里:

为什么 HoughCircles 无法检测到这张图片中的圆圈?它似乎正在处理其他更简单的图像,例如电路板。

【问题讨论】:

您可能想要:1/ 增加迭代次数,2/ 预处理点以将它们减少到一个点。 如果使用几次低通滤波器迭代来预处理图像会发生什么? @MohitJain 你能提供代码吗……可以解决这个问题,我是图像处理的初学者……我只想检测这张图像中的圆形 @Micka 谢谢我终于做到了.... 现在检测到所有圆圈。我增加了圆圈的大小,甚至调整了图像的大小。这成功了.....谢谢 @Micka 哦,谢谢刚刚做到了...... 【参考方案1】:

我遇到了您的确切问题并找到了解决方案

关键在于对 HoughCircles 所做的事情有足够的直觉,这样您就可以构建一个程序,为您想要在其中找到圆圈的所有各种图像自动调整超参数。

核心问题,一些直觉

HoughCircles 不是独立存在的,尽管它暗示它可能具有最小和最大半径参数,但您需要运行数百或数千次迭代才能在正确的设置中自动调整和自动拨号。然后在你完成后,你需要后处理验证步骤来 100% 确定圆圈是你想要的。问题是您正在尝试通过使用猜测和检查自己手动调整 HoughCircles 的输入参数。那根本行不通。让计算机为您自动调整这些参数。

HoughCircles 的手动调整何时可以令人满意?

如果您想手动硬编码参数,您绝对需要的一件事是将圆的精确半径控制在一到两个像素内。您可以猜测 dp 分辨率并设置累加器数组投票阈值,您可能会没事的。但是,如果您不知道半径,则 HoughCircles 输出将毫无用处,因为它要么在任何地方找到圆,要么在任何地方都找不到。假设你确实找到了一个可以接受的手动调整,你给它展示了一个有几个像素不同的图像,你的 HoughCircles 吓坏了,在图像中找到了 200 个圆圈。一文不值。

有希望:

希望来自这样一个事实,即 HoughCircles 即使在大图像上也非常快。您可以为 HoughCircles 编写一个程序来完美地自动调整设置。如果您不知道半径并且它可能很小或很大,那么您从一个很大的“最小距离参数”开始,一个非常好的 dp 分辨率和一个非常高的投票阈值。因此,当您开始迭代时,HoughCircles 可以预见地拒绝找到任何圈子,因为设置过于激进并且投票没有清除阈值。但是循环会不断迭代并逐渐上升到最佳设置,让最佳设置成为指示您完成的避雷针。您找到的第一个圆圈将是图像中像素完美的最大和最佳圆圈,您会对 HoughCircles 给您留下深刻印象的像素完美圆圈就在它应该在的位置。只是你必须运行它 5000 次。

示例 python 代码(抱歉不是 C++):

它的边缘仍然很粗糙,但您应该能够将其清理干净,以便在一秒钟内获得令人满意的像素完美效果。

import numpy as np
import argparse
import cv2
import signal

from functools import wraps
import errno
import os
import copy

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True, help = "Path to the image")
args = vars(ap.parse_args())

# load the image, clone it for output, and then convert it to grayscale
image = cv2.imread(args["image"])
orig_image = np.copy(image)
output = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

cv2.imshow("gray", gray)
cv2.waitKey(0)

circles = None

minimum_circle_size = 100      #this is the range of possible circle in pixels you want to find
maximum_circle_size = 150     #maximum possible circle size you're willing to find in pixels

guess_dp = 1.0

number_of_circles_expected = 1          #we expect to find just one circle
breakout = False

#hand tune this
max_guess_accumulator_array_threshold = 100     #minimum of 1, no maximum, (max 300?) the quantity of votes 
                                                #needed to qualify for a circle to be found.
circleLog = []

guess_accumulator_array_threshold = max_guess_accumulator_array_threshold

while guess_accumulator_array_threshold > 1 and breakout == False:
    #start out with smallest resolution possible, to find the most precise circle, then creep bigger if none found
    guess_dp = 1.0
    print("resetting guess_dp:" + str(guess_dp))
    while guess_dp < 9 and breakout == False:
        guess_radius = maximum_circle_size
        print("setting guess_radius: " + str(guess_radius))
        print(circles is None)
        while True:

            #HoughCircles algorithm isn't strong enough to stand on its own if you don't
            #know EXACTLY what radius the circle in the image is, (accurate to within 3 pixels) 
            #If you don't know radius, you need lots of guess and check and lots of post-processing 
            #verification.  Luckily HoughCircles is pretty quick so we can brute force.

            print("guessing radius: " + str(guess_radius) + 
                    " and dp: " + str(guess_dp) + " vote threshold: " + 
                    str(guess_accumulator_array_threshold))

            circles = cv2.HoughCircles(gray, 
                cv2.HOUGH_GRADIENT, 
                dp=guess_dp,               #resolution of accumulator array.
                minDist=100,                #number of pixels center of circles should be from each other, hardcode
                param1=50,
                param2=guess_accumulator_array_threshold,
                minRadius=(guess_radius-3),    #HoughCircles will look for circles at minimum this size
                maxRadius=(guess_radius+3)     #HoughCircles will look for circles at maximum this size
                )

            if circles is not None:
                if len(circles[0]) == number_of_circles_expected:
                    print("len of circles: " + str(len(circles)))
                    circleLog.append(copy.copy(circles))
                    print("k1")
                break
                circles = None
            guess_radius -= 5 
            if guess_radius < 40:
                break;

        guess_dp += 1.5

    guess_accumulator_array_threshold -= 2

#Return the circleLog with the highest accumulator threshold

# ensure at least some circles were found
for cir in circleLog:
    # convert the (x, y) coordinates and radius of the circles to integers
    output = np.copy(orig_image)

    if (len(cir) > 1):
        print("FAIL before")
        exit()

    print(cir[0, :])

    cir = np.round(cir[0, :]).astype("int")

    # loop over the (x, y) coordinates and radius of the circles
    if (len(cir) > 1):
        print("FAIL after")
        exit()

    for (x, y, r) in cir:
        # draw the circle in the output image, then draw a rectangle
        # corresponding to the center of the circle
        cv2.circle(output, (x, y), r, (0, 0, 255), 2)
        cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)

    # show the output image
    cv2.imshow("output", np.hstack([orig_image, output]))
    cv2.waitKey(0)

所以如果你运行它,它需要 5 秒,但它几乎是像素完美的(自动调谐器的进一步手动调整使其达到亚像素完美):

上面的代码转换了这个:

到这里:

使这项工作成功的秘诀在于您在开始之前掌握了多少信息。如果您知道半径到某个容差(例如 20 像素),那么这很完美,您就完成了。但是,如果你不这样做,你必须聪明地了解如何在小心接近决议和投票阈值的情况下爬上最大票数的半径。如果圆圈形状奇特,dp分辨率需要更高,投票阈值需要探索更低的范围。

【讨论】:

以上是关于HoughCircles 无法检测此图像上的圆圈的主要内容,如果未能解决你的问题,请参考以下文章

opencv中的HoughCircles函数可以检测圆圈内的圆圈吗?

在 OpenCV 中检测半圆

使用opencv和python进行HoughCircles圆检测-

如何检测填充圆圈的网格?

如何使用openCV准确检测这张图片上的棕色/黑色/灰色/白色

OpenCV:防止 HoughCircles 方法使用 Canny 检测