我正在尝试检测图像中包含一个圆点的圆,但是很遗憾,我无法这样做。我正在使用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无法在此图像中检测到圆圈?它似乎正在处理其他更简单的图像,例如电路板。
最佳答案
我有确切的问题,找到了解决方案
关键在于对HoughCircles的操作有足够的直觉,因此您可以构建一个程序,该程序针对要在其中查找圆的所有各种图像自动调整超参数。
核心问题,一些直觉
尽管HoughCircles建议使用“最小半径”和“最大半径”参数,但它并不能独立运行,您需要运行数百或数千次迭代才能在正确的设置中自动调整和自动拨号。然后,完成后,您需要进行后处理验证步骤,以100%确保圆是您想要的。问题是您试图通过猜测和检查将输入参数手动调整到HoughCircles。那根本行不通。让计算机为您自动调整这些参数。
什么时候可以对HoughCircles进行手动调整?
如果要手工对参数进行硬编码,则绝对需要的一件事是将圆的精确半径控制在一两个像素以内。您可以猜测dp分辨率并设置累加器阵列的投票阈值,然后可能就可以了。但是,如果您不知道半径,则HoughCircles输出将无用,因为它会在任何地方或任何地方都找不到圆。并假设您确实找到了可以接受的手动调整,并向其显示了一个像素相差几个像素的图像,并且您的HoughCircles出现了怪异现象,并在图像中找到了200个圆。不值钱
有希望:
希望来自于HoughCircles即使在大图像上也非常快的事实。您可以为HoughCircles编写程序以完美地自动调整设置。如果您不知道半径,并且半径可能很小或很大,那么您将从一个大的“最小距离参数”,一个非常好的dp分辨率和一个非常高的投票阈值开始。因此,当您开始进行迭代时,HoughCircles可能会拒绝找到任何圈子,因为设置过于激进并且投票无法清除阈值。但是,循环会不断迭代并逐步爬升至最佳设置,让最佳设置成为表示您完成操作的避雷针。您发现的第一个圆圈将是图像中像素完美的最大和最佳圆圈,并且HoughCircles会给您留下深刻的印象,它将正确的像素递给您。只是您必须运行它五千次。
示例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.cv.CV_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分辨率将需要更高,而投票阈值将需要探索更低的范围。