【发布时间】:2018-02-08 02:52:12
【问题描述】:
我想沿着分割图像的顶部像素拟合一条曲线(显示为红色曲线),我想找到沿曲线显示为蓝色的顶点。我已经研究过像遍历这样的基本想法从上到下并沿每列收集顶点。我想知道这个问题有没有简单的解决方案,比如直接取出边界像素并找到顶点。我正在使用 MATLAB 来解决这个问题
【问题讨论】:
标签: image matlab image-processing computer-vision
我想沿着分割图像的顶部像素拟合一条曲线(显示为红色曲线),我想找到沿曲线显示为蓝色的顶点。我已经研究过像遍历这样的基本想法从上到下并沿每列收集顶点。我想知道这个问题有没有简单的解决方案,比如直接取出边界像素并找到顶点。我正在使用 MATLAB 来解决这个问题
【问题讨论】:
标签: image matlab image-processing computer-vision
%download the image
img = logical(imread('http://i.stack.imgur.com/or2iX.png'));
%for some reason it appeared RGB with big solid borders.
%to monochrome
img = img(:,:,1);
%remove borders
img = img(~all(img,2), ~all(img,1));
%split into columns
cimg = num2cell(img,1);
%find first nonzero element per column
ridx = cellfun(@(x) find(x,1,'first'), cimg);
figure, imshow(img)
hold on
%image dim1 is Y, dim2 is X
plot(1:size(img,2),ridx-1,'r','linewidth',2)
%find top point
[yval, xval] = min(ridx);
如果你想要更平滑的曲线,试试 polyfit/polyval
@编辑 如果我们希望线在连接组件之间的间隙处中断,我们应该将代码更改为类似
bord_idx = sub2ind(size(img), ridx, 1:size(img,2));
regs=regionprops(bwlabel(img),'pixelidxlist');
regs_idx = struct2cell(regs);
split_step = cellfun(@(x) sum(ismember(bord_idx,x)), regs_idx);
split_step = split_step(split_step>0);
split_yvals = mat2cell(ridx',split_val);
split_xvals = mat2cell([1:size(img,2)]',split_val);
figure, imshow(img)
hold on
for k = 1:length(split_step),
plot(split_xvals{k}, split_yvals{k}, 'r', 'linewidth', 2),
end
但是,如果一个区域位于另一个区域之上,则结果并不理想。如果需要“阴影”点,您应该尝试 bwtraceboundary 或凸包并找到边界向下的位置
【讨论】:
至于“最简单的 matlab 解决方案”,我认为您的意思是内置 matlab 函数:imclose()->edge()->bwboundaries()->findpeaks()'在每个边界上'->'过滤结果基于峰的宽度和幅度”。 *您将需要调整这些函数中的所有参数,我只是列出了如果应用得当,您将获得什么。
就处理速度而言,我想我会完全按照您的做法进行,基本上是从自上而下的列搜索中收集顶部边缘,然后寻找最高拐点。一旦您开始进行任何类型的处理,您就会开始对每个像素进行多个操作,这将很快变得比您的初始搜索更昂贵(只需要您的图像和目标足够简单)
话虽如此,这里有一些想法可能会有所帮助:
1:如果您运行足够重的关闭(扩张->侵蚀),那应该会填满底部的所有垃圾。
2:如果您知道您的兴趣点不在图片的左侧或右侧(边界),您可以获取右侧和左侧边缘点并计算斜率作为偏移量,以使整个图像变平。
3:如果您的图像始终在峰值下方有较大的深色线性区域,如此处所示,您可以通过寻找垂直线的轮廓线定位这些边缘,然后仅搜索它们之间的列。
4:如果速度是一个问题,你可以做一个比从左到右更复杂的搜索模式,因为你的峰值在它周围有一个很好的分布,这有助于更快地定位最大值。
【讨论】: