使用MATLAB在图像中完成部分圆

时间:2014-11-25 19:38:05

标签: matlab image-processing geometry

我有二进制图像,它们有半个或更少的圆圈。我的目标是找到这些圆圈,使它们成为整圆,并删除所有其他对象。我发现this但它适用于MATLAB R2013a。我使用的是R2011b,它没有centers = imfindcircles(A,radius)函数。

如何在MATLAB版本R2011b中完成?

图片: enter image description here enter image description here enter image description here

编辑: 我的目标是获得整个圈子。我在下面显示了最后一张图片。

enter image description here

1 个答案:

答案 0 :(得分:3)

关于imfindcircles太糟糕了!我可以建议的一件事是调用regionprops并指定'Area''BoundingBox'标志。只要我记得,regionprops就可以在MATLAB中找到,所以我们当然可以在这里使用它。

这样做的是,无论在图像中看到哪些不同的对象,我们都会找到它们的区域和绑定它们的边界框。执行此操作后,区域上的阈值,以便具有非常大区域的任何对象最可能包含感兴趣的圆。请记住,我只假设您的图像中有圆圈。如果你有任何大面积的对象,这种方法也会提取出来。

因此,让我们直接从Stack Overflow读取您的图像。当您上传图片时,它是RGB图片,因此我必须转换为二进制文件:

im = imread('http://i.stack.imgur.com/wQLPi.jpg');
im_bw = im2bw(im);

接下来,请致电regionprops

s = regionprops(im_bw, 'Area', 'BoundingBox');

现在,收集所有区域,让我们看一下此图片中所有对象的所有唯一区域:

areas = [s.Area].';
unique(areas)

ans =

           1
           2
           3
           4
           5
           6
           7
           8
           9
          10
          11
          12
          13
          14
          15
          16
          17
          19
          20
          23
          24
          25
          28
          29
          38
          43
          72
          73
          85
          87
         250
         465
        3127

如果你看一下最后,你会发现我们有一个3127像素的物体。这可能包含我们的圈子。因此,让我们选择包含此对象的单个元素:

s2 = s(areas == 3127);

一般情况下,您的图片中可能有多个圆圈,因此您应该对该区域进行阈值处理,以选择那些潜在的圆圈。类似的东西:

s2 = s(areas > 2000);

现在,让我们创建一个与原始图像大小相同的新空白图像,然后只需使用BoundingBox属性即可提取原始图像中包含圆圈的区域并复制它到输出图像中的相同位置。 BoundingBox字段的结构如下:

[x y w h]

xy是边界框的左上角。 x将成为列,y将成为行。 wh是边界框的宽度和高度。因此,我们可以直接使用它来访问我们的图像并将这些像素复制到输出图像中。

out = false(size(im_bw));
bb = floor(s2.BoundingBox); %// Could be floating point, so floor it
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);

这就是我得到的:

enter image description here

如果我们有多个圈子,你应该在圈子上做循环。上面的代码假设您只检测到一个圆圈。因此,做这样的事情:

out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
    bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
    %// Copy over pixels from original bw image to output
    out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end

要注意的一点是边界框包含整个对象,但也可能存在一些在该边界框内断开连接的噪声像素。您可能必须应用一些形态来摆脱这些像素。二进制开放就足够了。


这是我用其他图片得到的内容。我对该区域进行了阈值处理以搜索那些具有2000像素或更多像素的区域(我在上面做了这个):

enter image description here

enter image description here


仅仅为了自我控制和您的复制和粘贴乐趣,以下是一段中的代码:

clear all;
close all;
%im = imread('http://i.stack.imgur.com/qychC.jpg');
%im = imread('http://i.stack.imgur.com/wQLPi.jpg');
im = imread('http://i.stack.imgur.com/mZMBA.jpg');
im_bw = im2bw(im);

s = regionprops(im_bw, 'Area', 'BoundingBox');
areas = [s.Area].';
s2 = s(areas > 2000);

out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
    bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
    %// Copy over pixels from original bw image to output
    out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end

imshow(out);

代码中都有三张图片。您只需取消注释要使用的任何一个,注释掉其余部分,然后运行代码。它将显示包含所有检测到的圆圈的图像。


修改

您想绘制完整的圆圈,而不是自己提取形状。这不是一个问题。你需要做的就是确定最好的"半径"可以包含在每个边界框内。这只是每个边界框的宽度和高度的最大值,然后将这些数量除以2。

之后,通过meshgrid创建一个与原始图像本身大小相同的坐标的二维网格,然后创建一个二进制图像,使得此边界框的中心与任意点之间的欧几里德距离在此2D网格中,小于半径的设置为逻辑true,而其他位置设置为逻辑false

换句话说,这样做:

clear all;
close all;
im = imread('http://i.stack.imgur.com/qychC.jpg');
%im = imread('http://i.stack.imgur.com/wQLPi.jpg');
%im = imread('http://i.stack.imgur.com/mZMBA.jpg');
im_bw = im2bw(im);

s = regionprops(im_bw, 'Area', 'BoundingBox');
areas = [s.Area].';
s2 = s(areas > 2000);

out = false(size(im_bw));

for idx = 1 : numel(s2) %// For each potential circle we have...
    bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
    %// Copy over pixels from original bw image to output
    out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end
figure;
imshow(out);

%// Image that contains all of our final circles
out2 = false(size(im_bw));
[X,Y] = meshgrid(1:size(im_bw,2), 1:size(im_bw,1)); %// Find a 2D grid of co-ordinates

for idx = 1 : numel(s2) %// For each circle we have...
   bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it

   cenx = bb(1) + (bb(3) / 2.0); %// Get the centre of the bounding box
   ceny = bb(2) + (bb(4) / 2.0);

   radi = max(bb(3), bb(4)) / 2; %// Find the best radius
   tmp = ((X - cenx).^2 + (Y - ceny).^2) <= radi^2; %// Draw our circle and place in a temp. image
   out2 = out2 | tmp; %// Add this circle on top of our output image
end

figure;
imshow(out2);

此脚本现在向您显示原始提取的形状,以及最好的&#34;圆圈&#34;在两个单独的图中描述了这些形状。请记住,这与我之前用一个圆圈展示的有点不同。我现在要做的是分配一个空白图像,然后逐步将每个圆圈添加到这个新图像。对于每个圆圈,我创建一个临时二进制图像,其中只有一个我正在寻找的圆圈,然后我将其添加到新图像的顶部。最后,我们将根据您的需要显示图像中的所有圆圈。


这是我为每张图片制作最佳圆圈的原因:

enter image description here

enter image description here

enter image description here

祝你好运!