通过插值在matlab中平滑图像轮廓
smooth image outline in matlab by interpolation
我正在绘制图像轮廓点 using this threshold method,但我的轮廓有直线段。我想在每个点绘制垂直角度,所以我真的需要曲线。
我可以使用凸包得到平滑的曲线。
图像生成如下:
B = bwboundaries(BW3);
outline = B{1,1};
plot(outline(:,2),outline(:,1),'r.','LineWidth',1)
K = convhull(outline(:,2),outline(:,1));
plot(outline(K,2),outline(K,1),'b+--','LineWidth',1)
但是我如何在凸包点之间"fill in the gaps"呢?我想要每个红点在蓝色曲线上的一个点。
我尝试使用 interp1 实现此目的:
outline2 = outline;
outline2(:,2)=interp1(outline(K,1),outline(K,2),outline(:,1),'spline');
但出现以下错误:
“使用 griddedInterpolant 时出错
网格向量必须包含唯一点。”
我认为这是因为轮廓形成了一个循环,而不是每个 y 的唯一 x 点。有没有其他方法可以使用样条曲线来填充那些缺失的点?
我也对寻找平滑边缘的其他想法持开放态度。
感谢您的帮助!
由于您的图像看起来平滑且采样良好,我建议您为每个边缘像素找到真实边缘的 sub-pixel 位置。有了这个,我们就不再需要凸包了,它可能对您的特定图像有用,但不会推广到任意形状。
这里有一些代码可以实现我的建议。
% A test image in the range 0-1, the true edge is assumed to be at 0.5
img = double(gaussianedgeclip(60-rr));
% Get rough outline
p = bwboundaries(img>0.5);
p = p{1,1};
% Refine outline
n = size(p,1);
q = p; % output outline
for ii=1:n
% Find the normal at point p(ii,:)
if ii==1
p1 = p(end,:);
else
p1 = p(ii-1,:);
end
if ii==n
p2 = p(1,:);
else
p2 = p(ii+1,:);
end
g = p2-p1;
g = (g([2,1]).*[-1,1])/norm(g);
% Find a set of points along a line perpendicular to the outline
s = p(ii,:) + g.*linspace(-2,2,9)';
% NOTE: The line above requires newer versions of MATLAB. If it
% fails, use bsxfun or repmat to compute s.
v = interp2(img,s(:,2),s(:,1));
% Find where this 1D sample intersects the 0.5 point,
% using linear interpolation
if v(1)<0.5
j = find(v>0.5,1,'first');
else
j = find(v<0.5,1,'first');
end
x = (v(j-1)-0.5) / (v(j-1)-v(j));
q(ii,:) = s(j-1,:) + (s(j,:)-s(j-1,:))*x;
end
% Plot
clf
imshow(img,[])
hold on
plot(p(:,2),p(:,1),'r.','LineWidth',1)
plot(q(:,2),q(:,1),'b.-','LineWidth',1)
set(gca,'xlim',[68,132],'ylim',[63,113])
生成测试图像的第一行需要 DIPimage,但其余代码仅使用标准 MATLAB 函数,bwboundaries
除外,您也使用了它,并且来自图像处理工具箱。
输出点集 q
未在整数 x 或 y 处采样。完成起来要复杂得多。
此外,对于 one-letter 变量感到抱歉...:)
使用行进方块 (https://en.wikipedia.org/wiki/Marching_squares#Isoline) 找到初始轮廓。
然后,如果您想对导数进行良好的估计,请拟合插值三次样条 (https://en.wikipedia.org/wiki/Spline_interpolation#Algorithm_to_find_the_interpolating_cubic_spline)。
这里有一点技术性:您似乎想要像素中心的斜率。但是从行进立方体获得的样条将通过边缘的已知点而不是通过中心。你可以
将中心点投影到样条上最近的点(可惜需要更高次多项式的解);
隐式化三次弧并计算隐函数的梯度。
如果你的精度要求不严格,你可能只用tagreted像素中的分割方向就可以了。
我正在绘制图像轮廓点 using this threshold method,但我的轮廓有直线段。我想在每个点绘制垂直角度,所以我真的需要曲线。
我可以使用凸包得到平滑的曲线。
图像生成如下:
B = bwboundaries(BW3);
outline = B{1,1};
plot(outline(:,2),outline(:,1),'r.','LineWidth',1)
K = convhull(outline(:,2),outline(:,1));
plot(outline(K,2),outline(K,1),'b+--','LineWidth',1)
但是我如何在凸包点之间"fill in the gaps"呢?我想要每个红点在蓝色曲线上的一个点。
我尝试使用 interp1 实现此目的:
outline2 = outline;
outline2(:,2)=interp1(outline(K,1),outline(K,2),outline(:,1),'spline');
但出现以下错误: “使用 griddedInterpolant 时出错 网格向量必须包含唯一点。”
我认为这是因为轮廓形成了一个循环,而不是每个 y 的唯一 x 点。有没有其他方法可以使用样条曲线来填充那些缺失的点?
我也对寻找平滑边缘的其他想法持开放态度。
感谢您的帮助!
由于您的图像看起来平滑且采样良好,我建议您为每个边缘像素找到真实边缘的 sub-pixel 位置。有了这个,我们就不再需要凸包了,它可能对您的特定图像有用,但不会推广到任意形状。
这里有一些代码可以实现我的建议。
% A test image in the range 0-1, the true edge is assumed to be at 0.5
img = double(gaussianedgeclip(60-rr));
% Get rough outline
p = bwboundaries(img>0.5);
p = p{1,1};
% Refine outline
n = size(p,1);
q = p; % output outline
for ii=1:n
% Find the normal at point p(ii,:)
if ii==1
p1 = p(end,:);
else
p1 = p(ii-1,:);
end
if ii==n
p2 = p(1,:);
else
p2 = p(ii+1,:);
end
g = p2-p1;
g = (g([2,1]).*[-1,1])/norm(g);
% Find a set of points along a line perpendicular to the outline
s = p(ii,:) + g.*linspace(-2,2,9)';
% NOTE: The line above requires newer versions of MATLAB. If it
% fails, use bsxfun or repmat to compute s.
v = interp2(img,s(:,2),s(:,1));
% Find where this 1D sample intersects the 0.5 point,
% using linear interpolation
if v(1)<0.5
j = find(v>0.5,1,'first');
else
j = find(v<0.5,1,'first');
end
x = (v(j-1)-0.5) / (v(j-1)-v(j));
q(ii,:) = s(j-1,:) + (s(j,:)-s(j-1,:))*x;
end
% Plot
clf
imshow(img,[])
hold on
plot(p(:,2),p(:,1),'r.','LineWidth',1)
plot(q(:,2),q(:,1),'b.-','LineWidth',1)
set(gca,'xlim',[68,132],'ylim',[63,113])
生成测试图像的第一行需要 DIPimage,但其余代码仅使用标准 MATLAB 函数,bwboundaries
除外,您也使用了它,并且来自图像处理工具箱。
输出点集 q
未在整数 x 或 y 处采样。完成起来要复杂得多。
此外,对于 one-letter 变量感到抱歉...:)
使用行进方块 (https://en.wikipedia.org/wiki/Marching_squares#Isoline) 找到初始轮廓。
然后,如果您想对导数进行良好的估计,请拟合插值三次样条 (https://en.wikipedia.org/wiki/Spline_interpolation#Algorithm_to_find_the_interpolating_cubic_spline)。
这里有一点技术性:您似乎想要像素中心的斜率。但是从行进立方体获得的样条将通过边缘的已知点而不是通过中心。你可以
将中心点投影到样条上最近的点(可惜需要更高次多项式的解);
隐式化三次弧并计算隐函数的梯度。
如果你的精度要求不严格,你可能只用tagreted像素中的分割方向就可以了。