霍夫变换(Hough transformation)圆检测中[a,b]空间无法正确计算求助
我看你在实现霍夫变换圆检测时,[a,b](也就是圆心坐标空间)的累加计算出了问题,结合你给出的代码和前置步骤,我梳理了几个关键问题和修复方案:
1. 梯度方向计算的核心错误
你用atan(Ix./Iy)计算梯度方向,这是个典型的问题:
atan(Ix/Iy)的角度范围仅为[-π/2, π/2],无法区分四个象限的方向,当Ix和Iy符号不同时,会得到完全错误的角度值,直接导致圆心坐标计算偏离正确位置。- 当Iy为0时,会触发除以0的错误,产生
Inf或NaN,让后续的cos和sin计算直接失效。
修复方案:
改用atan2(Iy, Ix)计算梯度方向角。atan2(y, x)会返回从x轴正方向到向量(x,y)的角度,范围是[-π, π],能正确处理所有象限的情况,还能避免除以0的问题。
2. 圆心坐标的计算逻辑偏差
Matlab的图像坐标是(row, col)对应(y, x)(row是垂直方向,col是水平方向),而梯度向量(Ix, Iy)中,Ix是水平(x/col)方向的导数,Iy是垂直(y/row)方向的导数。
你当前的代码:
a = row - r * cos(gradient(row, col)); b = col - r * sin(gradient(row, col));
这里的方向大概率搞反了。因为梯度方向是边缘的法线方向(圆心应该在边缘点的法线方向上),正确的圆心坐标应该是沿着梯度方向(或反方向)移动r的距离。结合atan2(Iy, Ix)的角度定义,调整为:
theta = gradient(row, col); a = row + r * sin(theta); % y方向(row)的分量对应sin(theta) b = col + r * cos(theta); % x方向(col)的分量对应cos(theta)
如果发现圆心方向完全相反,把+改成-即可——这取决于你Sobel算子的梯度方向定义(是指向边缘外侧还是内侧)。
3. 累加数组的维度优化(非致命但建议)
你创建的累加数组A = zeros(rows, cols, maxr),但实际只用到了r从minr到maxr的部分,前面1到minr-1的维度全是浪费的内存。可以改成:
r_range = minr:maxr; A = zeros(rows, cols, length(r_range));
然后在循环中用索引对应r的位置:
for r_idx = 1:length(r_range) r = r_range(r_idx); % ...计算a,b... A(a, b, r_idx) = A(a, b, r_idx) + (magnitude(row, col)/r); end
这样能节省不少内存,尤其是当maxr和minr差距很大时。
4. 幅值加权的合理性检查
你用magnitude(row, col)/r作为累加权重,如果你的Magnitude是阈值化后的二值图像(只有0或1),那么大半径的累加值会被大幅缩小,可能导致大半径的圆难以被检测到。
参考Jaroslav Borovicka的文档,如果文档中是用边缘幅值的绝对值作为权重,那可以去掉除以r的操作,或者调整为更合理的加权方式,比如:
A(a, b, r_idx) = A(a, b, r_idx) + magnitude(row, col);
如果确实需要按r加权,也可以考虑保留magnitude(row, col) * (1/r),但要确保幅值不是二值的——比如调整阈值,让Magnitude保留原始的梯度强度。
额外验证步骤
- 先单独输出几个边缘点的梯度方向和计算出的(a,b)坐标,手动验证是否在预期的圆心方向上。
- 可以先测试一张带有已知半径圆的图片,检查累加数组中对应圆心位置的累加值是否为峰值,以此快速验证逻辑是否正确。
内容的提问来源于stack exchange,提问作者Faraz Mazhar

