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

时间:2014-11-13 10:40:49

标签: matlab image-processing image-segmentation

如何使用MATLAB将下图中的两个连接圆分开?我尝试过使用imerode,但这并没有给出好的结果。腐蚀不起作用,因为为了腐蚀足以分离圆圈,线条消失或变得严重。在其他起始图片中,圆圈和线条重叠,因此隔离重叠的对象也不会起作用。

图像显示由bwboundaries标识的对象,每个对象绘制不同的颜色。正如你所看到的那样,两个淡蓝色圆圈相连,我想将它们分开,产生两个独立的圆圈。感谢

3 个答案:

答案 0 :(得分:4)

我建议你通过imfindcircles使用Circular Hough Transform。但是,您需要第8版的图像处理工具箱,该版本可从R2012a版本开始提供。如果你没有这个,那么不幸的是,这不会起作用:(但是让我们假设你有它。但是,如果你使用的是比R2012a更旧的东西,Dev-iL在他/她的上述评论中与MATLAB的文件交换上的一些代码相关联,其中很可能是在圆形霍夫变换可用之前创建的:http://www.mathworks.com/matlabcentral/fileexchange/9168-detect-circles-with-various-radii-in-grayscale-image-via-hough-transform/


这是霍夫变换的一个特例,您试图在图像中找到圆圈而不是线条。这样的美妙之处在于,即使圆圈部分完成或重叠,您也能找到圆圈。

我将拍摄您上面提供的图片并对其进行一些后期处理。我要将图像转换为二进制,并删除边框,该边框为白色并包含标题。我还要填补任何洞,以便所有物体都用纯白色填充。在我执行此步骤后,还有一些残余的量化噪声,因此我将使用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));

这是我得到的图像:

enter image description here

现在,应用Circular Hough Transform。一般语法是:

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

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

  1. centres:返回检测到的每个圆圈中心的(x,y)位置
  2. radii:每个圆圈的半径
  3. metric:圆圈纯度的衡量标准。值越高意味着形状更可能是圆形,反之亦然。
  4. 我搜索了半径在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
    

    结果如下:

    enter image description here

    正如您所看到的,即使重叠圆圈朝向顶部,圆形霍夫变换也能够检测到该形状中的两个不同圆圈。


    编辑 - 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 struct。我使用meshgrid来确定与包含我们形状的图像相关的(X,Y)坐标,这样我就可以在每次迭代时在空白图像上绘制一个圆。要执行此操作,您只需找到相对于每个圆的中心的欧几里德距离,并仅在该位置的距离小于true时将像素设置为r。完成此操作后,您将只创建一个圆圈并将其全部过滤掉。然后,您可以在此圈子上使用regionprops,将其添加到我们的circles_img数组中,该数组仅包含圈子,然后继续其余圈子。

    此时,我们将保存所有圈子。这是circles_img到目前为止的样子:

    enter image description here

    您会注意到绘制的圆圈是干净的,但原始图像中的实际圆圈有点锯齿状。如果我们尝试使用此干净图像移除圆圈,您将获得沿边框的一些残留像素,并且您不会完全删除圆圈本身。为了说明我的意思,如果我尝试用circles_img删除圈子,那么这就是您的图片的样子:

    enter image description here

    ......不好,对吧?

    如果要完全删除圆圈,请通过imreconstruct进行形态重建,您可以将此图像用作种子图像,并将原始图像指定为我们正在处理的图像。形态重建的工作基本上是洪水填充。您可以指定种子像素和要处理的图像,imreconstruct的作业来自这些种子,使用白色填充填充,直到我们到达种子像素所在的对象的边界。因此:< / p>

    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电话,因为我在分析中并不确切地知道你想要什么...所以我决定给你一切。


    希望这有帮助!

答案 1 :(得分:-1)

侵蚀是要走的路。您应该使用更大的结构元素。

答案 2 :(得分:-1)

怎么样

1腐蚀

2检测你的物体

3使用相同的结构元素扩展每个对象