【问题标题】:How to select the largest contour in MATLAB如何在MATLAB中选择最大的轮廓
【发布时间】:2015-04-21 06:03:05
【问题描述】:

在我的进度工作中,我必须检测寄生虫。我使用 HSV 发现了寄生虫,后来将其制成了灰色图像。现在我也做了边缘检测。我需要一些代码来告诉 MATLAB 找到最大的轮廓(寄生虫)并将该区域的其余部分设为黑色像素。

【问题讨论】:

  • 这很模糊,你能详细说明/提供示例图像/代码吗?否则您可能对regionprops 感兴趣
  • 我现在添加了图片@Benoit_11。我没有写任何代码。我只想在那里有大面积的覆盖线(如腰果形状),并将其余部分变为黑色像素。我通过阅读堆栈溢出时的另一个相关问题了解到我应该使用轮廓,如果我可以编写任何代码来选择大轮廓,我可以让它工作。但我不知道该怎么做。

标签: matlab image-processing contour pixels supervised-learning


【解决方案1】:

这可能是一种方法 -

%// Read in image as binary
im = im2bw(imread('http://i.stack.imgur.com/a5Yi7.jpg'));
im = im(40:320,90:375); %// clear out the whitish border you have
figure, imshow(im), title('Original image')

%// Fill all contours to get us filled blobs and then select the biggest one
outer_blob = imfill(im,'holes');
figure, imshow(outer_blob), title('Filled Blobs')

%// Select the biggest blob that will correspond to the biggest contour
outer_blob = biggest_blob(outer_blob); 

%// Get the biggest contour from the biggest filled blob
out = outer_blob & im;
figure, imshow(out), title('Final output: Biggest Contour')

基于bsxfun 的函数biggest_blob 是此处发布的其他答案使用regionprops 执行的替代方法。根据我的经验,我发现这种基于bsxfun 的技术比regionprops 更快。 Here are few benchmarks 在我之前的一个答案中比较这两种技术的运行时性能。

关联函数-

function out = biggest_blob(BW)

%// Find and labels blobs in the binary image BW
[L, num] = bwlabel(BW, 8); 

%// Count of pixels in each blob, basically should give area of each blob
counts = sum(bsxfun(@eq,L(:),1:num)); 

%// Get the label(ind) cooresponding to blob with the maximum area 
%// which would be the biggest blob
[~,ind] = max(counts);

%// Get only the logical mask of the biggest blob by comparing all labels 
%// to the label(ind) of the biggest blob
out = (L==ind);

return;

调试图像 -

【讨论】:

  • 啊。 bwlabelbsxfun。另一种有效的方法。它不依赖于regionprops。 +1。
  • @rayryeng 是的,这就是我能做的! ;)
  • 我很喜欢你用它来计算每个对象有多少像素。好奇:在这种情况下,您认为accumarraybsxfun 相比如何?可比?快点?慢一点?
  • 是的,非常聪明的方法,我喜欢它!当然bsxfun FTW!
  • @rayryeng 告诉你!!乍一看,histc 看起来很完美,因为这就是 histc 的用途(计数),这就是我们在这里所做的!
【解决方案2】:

由于我的答案几乎都写出来了,所以无论如何我都会给你,但这个想法类似于@rayryeng 的答案。

基本上,我在调用regionprops 期间使用PerimeterPixelIdxList 标志,因此一旦使用imclearborder 删除图像边框,就会得到形成最大轮廓的像素的线性索引。

代码如下:

clc
clear


BW = imclearborder(im2bw(imread('http://i.stack.imgur.com/a5Yi7.jpg')));

S= regionprops(BW, 'Perimeter','PixelIdxList');

[~,idx] = max([S.Perimeter]);

Indices = S(idx).PixelIdxList;

NewIm = false(size(BW));

NewIm(Indices) = 1;

imshow(NewIm)

还有输出:

如您所见,有很多方法可以达到相同的效果哈哈。

【讨论】:

  • PixelIdxList。聪明的。它消除了我打的不必要的sub2ind 电话。 +1。
  • 为什么每次运行都会出现这个错误?:??? [~,idx] = max([S.Perimeter]); |错误:表达式或语句不正确——可能是不平衡的 (、{ 或 [.
  • 嗯它不应该......它似乎没问题。你使用的正是这段代码?
【解决方案3】:

您可以通过填充每个轮廓围绕的孔来选择“最大”轮廓,找出哪个形状为您提供最大的区域,然后使用最大区域的位置并将其复制到最终图像。正如 Benoit_11 所建议的那样,使用 regionprops - 特别是 AreaPixelList 标志。像这样的:

im = imclearborder(im2bw(imread('http://i.stack.imgur.com/a5Yi7.jpg')));
im_fill = imfill(im, 'holes');
s = regionprops(im_fill, 'Area', 'PixelList');
[~,ind] = max([s.Area]);
pix = sub2ind(size(im), s(ind).PixelList(:,2), s(ind).PixelList(:,1));
out = zeros(size(im));
out(pix) = im(pix);
imshow(out);

第一行代码直接从 StackOverflow 读取图像。由于某种原因,该图像也是 RGB 图像,因此我通过im2bw 将其转换为二进制。图像周围还有一个白色边框。您很可能在figure 中打开了此图像并保存了图中的图像。我通过使用imclearborder 删除白色边框来摆脱这个问题。

接下来,我们需要填充轮廓包围的区域,所以使用imfillholes 标志。接下来,使用regionprops来分析图像中不同的填充对象——具体来说是Area以及填充图像中每个对象属于哪些像素。一旦我们获得这些属性,找到为您提供最大区域的填充轮廓,然后访问正确的regionprops 元素,提取属于对象的像素位置,然后使用这些并将像素复制到输出图像和显示结果。

我们得到:

或者,您可以使用 Perimeter 标志(如 Benoit_11 所建议的那样),并简单地找到对应于最大轮廓的最大周长。这仍然应该给你你想要的。因此,只需将第三行和第四行代码中的Area 标志替换为Perimeter,您仍然应该得到相同的结果。

【讨论】:

  • 哈哈,我写的是完全相同的答案,但带有Perimeter 标志:) 做得好,当然+1。
  • @Benoit_11 - 哦,是的!周边也可以在这里工作。哦,哈哈。你仍然应该把你的答案放在:) 我也会+1。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-13
  • 2017-04-06
  • 2016-06-29
  • 1970-01-01
  • 1970-01-01
  • 2016-12-10
  • 1970-01-01
相关资源
最近更新 更多