【问题标题】:smooth image outline in matlab by interpolation通过插值在matlab中平滑图像轮廓
【发布时间】:2018-08-23 16:17:11
【问题描述】:

我正在绘制图像轮廓点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)

但是我怎样才能“填补”凸包点之间的空白?我希望每个红点在蓝色曲线上都有一个点。

我尝试使用 interp1 来实现:

outline2 = outline;
outline2(:,2)=interp1(outline(K,1),outline(K,2),outline(:,1),'spline');

但出现以下错误: “使用 griddedInterpolant 时出错 网格向量必须包含唯一点。”

我认为这是因为轮廓形成了一个循环,而不是每个 y 的唯一 x 点。是否有其他方法可以使用样条线填充这些缺失点?

我也对寻找平滑边缘的其他想法持开放态度。

感谢您的帮助!

【问题讨论】:

  • 这是因为outline(:,1) 包含重复值。您是要获得离红点最近的点,还是只是等距点?
  • 我希望曲线上的一个点(在对象的每一侧)为范围内的每个 y 值,同样对于 x 轴,以使轮廓闭合。这些点应位于(或靠近)蓝色曲线。

标签: matlab image-processing interpolation


【解决方案1】:

由于您的图像看起来很平滑且采样良好,我建议您为每个边缘像素找到真正边缘的子像素位置。这样,我们就不再需要凸包,这可能对您的特定图像有用,但不能推广到任意形状。

这里有一些代码可以完成我的建议。

% 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 处采样。这要复杂得多。

另外,对于单字母变量感到抱歉... :)

【讨论】:

  • 嗨,克里斯,感谢您的回答。我尝试实现它,但在第 26 行不断遇到问题:“使用 griddedInterpolant 时出错样本值必须是单数组或双数组。interp2>makegriddedinterp 中的错误(第 230 行)F = griddedInterpolant(varargin{:} ); interp2 错误(第 114 行) F = makegriddedinterp({X,Y},V,method,extrap); Subpix 错误(第 26 行) v = interp2(frame,s(:,2),s(:, 1));".我开始时在 interp1 中出现错误,现在在 interp2 中出现错误......似乎我还没有走得太远......
  • @FrederickStevenWells:在脚本开头的某处执行frame = double(frame)interp2 函数需要浮点输入数组,您传递的是(我认为)和整数值数组。
【解决方案2】:

使用 Marching Squares (https://en.wikipedia.org/wiki/Marching_squares#Isoline) 找到初始轮廓。

然后,如果您想对导数进行良好估计,请拟合插值三次样条 (https://en.wikipedia.org/wiki/Spline_interpolation#Algorithm_to_find_the_interpolating_cubic_spline)。

这里有一点技术性:您似乎希望像素中心的斜率。但是从行进立方体获得的样条曲线将通过边缘的已知点而不是中心。你可以

  • 将中心点投影到样条曲线上最近的点(不幸的是需要更高次多项式的解);

  • 隐式三次弧并计算隐式函数的梯度。

如果您的精度要求不严格,您可能只需使用标记像素中的分段方向即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-15
    • 1970-01-01
    • 2015-12-12
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    • 2011-09-11
    • 1970-01-01
    相关资源
    最近更新 更多