使用MATLAB分离图像中重叠的两个圆

5
我该如何使用MATLAB分离下面图片中连接的两个圆形?我已经尝试使用imerode,但效果不佳。腐蚀操作不起作用,因为要想腐蚀得足够分开这两个圆,线条就会消失或变形。在其他起始图片中,圆形和线条重叠,所以隔离重叠的对象也行不通。
该图片显示由bwboundaries识别出的对象,每个对象都涂上了不同的颜色。如你所见,两个浅蓝色的圆形是连接在一起的,我想将它们分离,产生两个独立的圆形。谢谢!
图片链接:

我建议使用霍夫变换(链接1链接2)来识别圆心 - 然后您将得到连接形状包含两个圆。 - Dev-iL
@Dev-iL - MATLAB提供了imfindcircles,它本质上是圆形霍夫变换,基本上就是链接#2。这是从R2012a开始提供的。我认为链接#2是在MATLAB中提供此功能之前创建的。但是,我同意您的建议! - rayryeng
3个回答

4
我建议您使用imfindcircles中的圆形霍夫变换。但是,您需要Image Processing Toolbox的8版,该版本从R2012a版本开始提供。如果您没有此工具箱,则不幸的是无法运行:(...但让我们假设您已经拥有它。但是,如果您使用的是早于R2012a版本的东西,Dev-iL在他/她的评论中链接了一些代码,这是在圆形霍夫变换可用之前创建的:http://www.mathworks.com/matlabcentral/fileexchange/9168-detect-circles-with-various-radii-in-grayscale-image-via-hough-transform/
这是Hough变换的一种特殊情况,其中您正在尝试在图像中查找圆而不是线。这样做的好处是,即使圆形部分完成或重叠,您也能够找到圆形。
我将采取您上面提供的图像并进行后处理。我将把图像转换为二进制,并删除白色边框,其中包含标题。我还将填补任何导致的空洞,以便所有对象都用纯白色填充。在执行此步骤后,还存在一些残余量化噪声,因此我将使用3 x 3正方形元素进行小型开口处理。然后,我将使用3 x 3正方形元素关闭形状,因为我发现形状中有明显的间隙。因此:
因此,直接从您发布的位置读取图像:
im = imread('http://s29.postimg.org/spkab8oef/image.jpg'); %// Read in the image
im_gray = im2double(rgb2gray(im)); %// Convert to grayscale, then [0,1]
out = imclearborder(im_gray > 0.6); %// Threshold using 0.6, then clear the border
out = imfill(out, 'holes'); %// Fill in the holes
out = imopen(out, strel('square', 3));
out = imclose(out, strel('square', 3));

这是我得到的图片:

在此输入图片描述

现在,应用圆形霍夫变换。一般的语法是:

[centres, radii, metric] = imfindcircles(img, [start_radius, end_radius]);

img是包含您的形状的二进制图像,start_radiusend_radius是您想要查找的圆的最小和最大半径。执行循环霍夫变换以查找在此范围内(以像素为单位)的任何圆。输出如下:

  1. centres:返回检测到的每个圆的中心位置的(x,y)坐标。
  2. radii:每个圆的半径。
  3. metric:圆的纯度度量值。较高的值意味着该形状更可能是圆形,反之亦然。

我搜索了半径在30至60像素之间的圆。因此:

[centres, radii, metric] = imfindcircles(out, [30, 60]);

我们可以通过使用plotviscircles的组合来展示检测到的圆以及半径。因此:
imshow(out);
hold on;
plot(centres(:,1), centres(:,2), 'r*'); %// Plot centres
viscircles(centres, radii, 'EdgeColor', 'b'); %// Plot circles - Make edge blue

这是结果:
如您所见,即使在顶部的重叠圆周中,圆形霍夫变换也能够检测出该形状中的两个不同圆。
编辑-2014年11月16日:
在进行bwboundaries之前,您需要确保对象已分离。这有点棘手。我唯一能想到的方法是完全不使用bwboundaries而自己处理。我假设您希望在所有操作之后逐个分析每个形状的属性,因此建议您遍历每个圆,然后将每个圆放在一个新的空白图像上,在该图像上调用regionprops,然后将其附加到单独的数组中。您还可以通过将每个圆逐个添加到该数组来跟踪所有圆。
完成所有圆的处理后,您将拥有一个包含找到的所有圆的测量属性的结构数组。您将使用仅包含以上圆的数组,然后使用这些圆并将其从原始图像中删除,以得到仅包含线条的图像。然后,在此图像上调用更多的regionprops以获取线的信息,并将其附加到最终结构数组中。
这是我上面概述的过程的第一部分。
num_circles = numel(radii); %// Get number of circles
struct_reg = []; %// Save the shape analysis per circle / line here

%// For creating our circle in the temporary image
[X,Y] = meshgrid(1:size(out,2), 1:size(out,1));

%// Storing all of our circles in this image
circles_img = false(size(out));

for idx = 1 : num_circles %// For each circle we have...        
    %// Place our circle inside a temporary image    
    r = radii(idx);
    cx = centres(idx,1); cy = centres(idx,2);
    tmp = (X - cx).^2 + (Y - cy).^2 <= r^2;        

    % // Save in master circle image
    circles_img(tmp) = true;

    %// Do regionprops on this image and save    
    struct_reg = [struct_reg; regionprops(tmp)]; 
end

以上代码可能有点难以理解,但我们可以慢慢来。首先,我要确定我们有多少个圆,这只需要查看我们检测到了多少个半径即可。我会保留一个名为struct_reg的单独数组,它将为我们图像中每个圆和线附加一个regionprops结构体。我使用meshgrid来确定相对于包含我们形状的图像的(X,Y)坐标,以便我可以在每次迭代中在空白图像上绘制一个圆。为此,您只需要找到相对于每个圆心的欧几里得距离,并仅在该位置的距离小于r时将像素设置为true。完成此操作后,您将仅创建一个圆并过滤掉所有圆。然后,您将在此圆上使用regionprops,将其添加到我们的circles_img数组中,该数组仅包含圆,然后继续处理剩余的圆。
此时,我们将保存所有圆。到目前为止,circles_img如下所示: enter image description here 您会注意到绘制的圆很干净,但原始图像中的实际圆有点锯齿状。如果我们尝试使用此清晰图像删除圆,则会在边界周围留下一些残留像素,并且无法完全删除圆本身。为了说明我的意思,如果我仅使用circles_img尝试删除圆,则您的图像如下所示: enter image description here ... 不好看,对吧?
如果您想完全删除圆,则可以通过imreconstruct进行形态重建,在其中可以将此图像用作种子图像,并指定要处理的原始图像。形态重建的工作实质上是洪水填充。您指定种子像素和要处理的图像,imreconstruct的工作是从这些种子开始,洪水填充白色,直到我们到达种子像素所在对象的边界。因此:
out_circles = imreconstruct(circles_img, out);

因此,我们得到了最终重构的圆形图像: enter image description here 太好了!现在,使用这个图像并从原始图片中删除圆。完成后,在这个最终图像上再次运行regionprops,并将结果附加到struct_reg变量中。在执行此操作之前,显然要保存一份原始图像的副本:
out_copy = out;
out_copy(out_circles) = false;
struct_reg = [struct_reg; regionprops(out_copy)];

为了举例说明,这是去掉圆形后的图片:

enter image description here

现在,我们分析了所有的形状。请注意,我使用了完整的regionprops调用,因为我不知道你希望在分析中得到什么...所以我决定给你全部内容。


希望这有所帮助!


太好了!但我需要将图像中的两个圆分开,这样regionprops才能检测到不同的对象。这可行吗? - tsorn
我当然是指bwboundaries,而不是regionprops。我需要在bwboundaries中将所有对象分开,即使是圆和线重叠的情况下也要分开。分开的对象的结构并不重要,只要圆仍然是圆,线仍然是线就可以。 - tsorn
@tsorn - 完成了。请看一下我的修改。由于您的图像有很多量化噪声,我不得不更改我第一篇帖子中的原始代码。我必须通过形态学去除它们。 - rayryeng
1
@rayreng,正是我所需要的。干得好,谢谢你。 - tsorn

-1

腐蚀是正确的方法。你应该使用一个更大的结构元素。


这样做也可能会消除图像中的线条。 - rayryeng

-1

怎么样呢

1 腐蚀

2 检测您的对象

3 使用相同的结构元素对每个对象进行膨胀


1
腐蚀并不起作用,因为为了侵蚀足够分离圆形,线条会消失或变形。在其他起始图片中,一个圆和一条线重叠,因此隔离重叠的对象也行不通。 - tsorn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接