如何使用MATLAB将下图中的两个连接圆分开?我尝试过使用imerode
,但这并没有给出好的结果。腐蚀不起作用,因为为了腐蚀足以分离圆圈,线条消失或变得严重。在其他起始图片中,圆圈和线条重叠,因此隔离重叠的对象也不会起作用。
图像显示由bwboundaries
标识的对象,每个对象绘制不同的颜色。正如你所看到的那样,两个淡蓝色圆圈相连,我想将它们分开,产生两个独立的圆圈。感谢
答案 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));
这是我得到的图像:
现在,应用Circular Hough Transform。一般语法是:
[centres, radii, metric] = imfindcircles(img, [start_radius, end_radius]);
img
将是包含您的形状的二进制图像,start_radius
和end_radius
将是您要查找的圆的最小和最大半径。执行圆形霍夫变换,使得它将找到在该范围内的任何圆(以像素为单位)。输出是:
centres
:返回检测到的每个圆圈中心的(x,y)
位置radii
:每个圆圈的半径metric
:圆圈纯度的衡量标准。值越高意味着形状更可能是圆形,反之亦然。 我搜索了半径在30到60像素之间的圆圈。因此:
[centres, radii, metric] = imfindcircles(out, [30, 60]);
然后,我们可以通过plot
和viscircles
的组合来演示检测到的圆圈以及半径。因此:
imshow(out);
hold on;
plot(centres(:,1), centres(:,2), 'r*'); %// Plot centres
viscircles(centres, radii, 'EdgeColor', 'b'); %// Plot circles - Make edge blue
结果如下:
正如您所看到的,即使重叠圆圈朝向顶部,圆形霍夫变换也能够检测到该形状中的两个不同圆圈。
您希望在执行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
到目前为止的样子:
您会注意到绘制的圆圈是干净的,但原始图像中的实际圆圈有点锯齿状。如果我们尝试使用此干净图像移除圆圈,您将获得沿边框的一些残留像素,并且您不会完全删除圆圈本身。为了说明我的意思,如果我尝试用circles_img
删除圈子,那么这就是您的图片的样子:
......不好,对吧?
如果要完全删除圆圈,请通过imreconstruct
进行形态重建,您可以将此图像用作种子图像,并将原始图像指定为我们正在处理的图像。形态重建的工作基本上是洪水填充。您可以指定种子像素和要处理的图像,imreconstruct
的作业来自这些种子,使用白色填充填充,直到我们到达种子像素所在的对象的边界。因此:< / p>
out_circles = imreconstruct(circles_img, out);
因此,我们为最终重建的圆形图像得到了这个:
大!现在,使用此选项并从原始图像中删除圆圈。完成此操作后,请在此最终图像上再次运行regionprops
并附加到struct_reg
变量。显然,在执行此操作之前保存原始图像的副本:
out_copy = out;
out_copy(out_circles) = false;
struct_reg = [struct_reg; regionprops(out_copy)];
仅仅为了争论,这就是删除了圆圈时图像的样子:
现在,我们已经分析了所有形状。请记住,我进行了完整的regionprops
电话,因为我在分析中并不确切地知道你想要什么...所以我决定给你一切。
希望这有帮助!
答案 1 :(得分:-1)
侵蚀是要走的路。您应该使用更大的结构元素。
答案 2 :(得分:-1)
怎么样
1腐蚀
2检测你的物体
3使用相同的结构元素扩展每个对象