这是 Hough 变换的典型应用,但由于您只有一个圆,我们可以做得更好。
下面的代码计算图像的梯度。你有很多噪音,但你的圈子也很大。我为梯度算子使用的高斯正则化使用了一个大的 sigma(我喜欢使用卷积和高斯的导数来计算导数)。接下来,我找到梯度幅度最大的像素,并为这些点建立一个方程组。我们注意到,对于每个点 i,
原点_x + 半径 * 梯度_x(i) = 坐标_x( 我)
原点_y + 半径 * 梯度_y(i) = 坐标_y( 我)
(抱歉,我们无法对 SO 做适当的方程式)。 coordinate是该点的坐标,gradient是该点的归一化梯度,_x和_y 表示向量的对应分量。 radius 可以是负数,具体取决于渐变的方向。我们可以使用 MATLAB 的\ 运算符求解这个线性方程组。
% Load image (take only first channel, they're all the same)
img = imread('https://i.stack.imgur.com/wAwdh.jpg');
img = dip_image(img(:,:,1));
% Compute gradient
grad = gradient(img,10);
% Find N pixels with largest gradient magnitude
N = 5000;
mask = norm(grad);
mask = setborder(mask,0,50); % Don't use data close to the edge of the image
tmp = sort(double(mask(:)));
mask = mask > tmp(end-N);
index = find(mask);
value = grad(index);
value = value / norm(value);
coords = ind2sub(mask,index); % value(i) at coords(i,:)
% Solve set of linear equations
p = [ones(N,1),zeros(N,1),double(value{1})';zeros(N,1),ones(N,1),double(value{2})'] \ coords(:);
origin = p(1:2)'
radius = p(3)
rmse = sqrt(mean((origin + radius * squeeze(double(value))' - coords).^2))
% Plot some of the lines
img
hold on
for ii=1:25:N
plot(coords(ii,1)-[0,radius*double(value{1}(ii-1))],coords(ii,2)-[0,radius*double(value{2}(ii-1))],'r-')
end
输出:
origin =
-2.5667 177.5305
radius =
322.5899
rmse =
13.8160 13.0136
如您所见,噪声会给估计梯度带来很多麻烦。但是因为每个像素的估计没有偏差,所以最小二乘估计应该会得到一个准确的值。
上面的代码使用DIPimage 3,这是一个用于MATLAB(Apache许可)的开源图像分析工具箱。您必须自己编译它,因为我们还没有预编译的发布包。你可以下载DIPimage 2.9,它具有相同的功能,虽然我可能在上面的代码中使用了一些新语法,但我不确定。 DIPimage 2.9 不是开源的,只能在非商业应用程序中免费使用。