检测连接对象之间的像素数

时间:2014-12-23 17:23:02

标签: matlab image-processing bitmap pixel connected-components

我有一个二进制图像,我需要找到连接对象之间的像素数 我正在使用MATLAB,这是我的图像

enter image description here

THX

2 个答案:

答案 0 :(得分:1)

一个有趣的问题,但不难解决。它只需要很多代码,但每行代码的理解都非常简单。这是我要执行的基本算法:

  1. 使用Circular Hough Transform - imfindcircles
  2. 查找图片中的所有圆圈
  3. 从图片中删除圆圈
  4. 使用regionprops计算剩余方形对象的面积,并确定封装方块所需的最小边界框。\ / li>
  5. 如果要完全填充,这些最小边界框坐标将是正方形的左上角和右下角坐标。因为有圆形重叠在正方形上,我们可以通过简单地获取每个边界框的整个区域来找到重叠区域,并用检测到的区域减去。留下的金额将是与圆圈重叠的区域。
  6. 要弄清楚两个圆圈重叠的区域,我们需要做的就是在图像上绘制两个圆圈并进行逻辑AND操作。这将找到两个圆相交的区域。一旦我们有了这些,我们只需计算剩余的像素,这将是两个圆圈的重叠区域。
  7. 我将假设您拥有图像处理工具箱,否则我的方法将无效。您还需要至少MATLAB R2012a将圆形霍夫变换包含在MATLAB发行版中。


    第1步

    我们需要首先反转您的图像,使白色对应于对象像素,黑色对应于背景。否则,regionpropsimfindcircles无法正常工作。我将直接从StackOverflow读取您的图片:

    im = imread('http://i.stack.imgur.com/WQtgP.png'); %// Already binary!
    im = ~im;
    

    接下来,让我们使用Circular Hough Transform。我们会像这样使用它:

    [centres, radii] = imfindcircles(im, [25 60]);
    

    im将是我们刚刚转换的二进制图像,数组[25 60]表示我们想要检测的圆的最小和最大半径。在这种情况下,最小半径为25,而最大半径为60. centresradii分别表示每个圆的中心和每个圆的半径的列和行坐标。 centres的第一列是列坐标,第二列是行坐标。运行此代码后,我们检测到4个圆圈(如预期的那样)。 centresradii看起来像这样:

    centres =
    
      267.5005   67.5005
      233.5152  200.4808
       83.2850   83.2850
      117.6691  118.0193
    
    radii =
    
       33.3178
       33.1137
       32.9332
       32.8488
    

    这意味着在第267.50列,第67.50行检测到一个圆,半径为33.3178,从每个结果的第一行读取。您可以跟随每个变量中的其余值。圆形霍夫变换的优点在于它可以检测部分圆,由于圆和正方形的重叠,它非常好。如果您想查看检测到的结果,可以使用viscircles,如下所示:

    imshow(im);
    viscircles(centres, radii, 'DrawBackgroundCircle', false);
    

    我将DrawBackgroundCircle设置为false,因为当我们绘制检测到的圆圈时,默认情况下会在圆圈上绘制白色轮廓。我不希望您将此与任何对象像素混淆,因此我将此标记设置为false

    这是我们得到的数字:

    enter image description here

    酷!


    步骤#2

    最简单的方法是循环遍历所有圆圈,创建圆形坐标网格,并将图像中的这些像素设置为false,以便从图像中删除这些像素。您可以使用meshgrid创建行和列位置的2D网格并将其编入索引,以将其设置为false。像这样:

    [X,Y] = meshgrid(1:size(im,2), 1:size(im,1));
    
    im_no_circles = im;
    for idx = 1 : numel(radii)
        r = radii(idx);
        c = centres(idx,:);
    
        mask = (X - c(1)).^2 + (Y - c(2)).^2 <= r^2;               
        im_no_circles(mask) = false;
    end
    

    此代码将采用每个圆圈并将图片中的相应位置设置为false。但是,现在的图像是:

    enter image description here

    由于量化噪声,圆圈中存在一些边缘伪影。我们可以使用bwareaopen删除这些像素。区域面积低于一定数量的区域将从图像中删除。我们可以选择像50这样的东西,因为这些正方形肯定超出50像素的区域,而虚假像素不是。在我们这样做之后,让我们用imopen做一个形态开口,以消除连接到每个方块的任何噪声像素,这样我们就可以真正得到没有任何圆圈的方形形状。

    所以:

    im_no_circles_open = bwareaopen(im_no_circles, 50);
    im_open = imopen(im_no_circles_open, strel('square', 5));
    

    这终于得到了:

    enter image description here

    步骤#3

    我们现在打电话给regionprops

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

    s将包含描述每个方形对象的结构。如果我们检查每个属性,这就是我们得到的:

    areas = [s.Area].'
    bb = reshape([s.BoundingBox], [], numel(areas)).'
    
    areas =
    
            4178
            4138
            4489
    
    bb =
    
      134.5000   50.5000   67.0000   67.0000
      150.5000  200.5000   67.0000   67.0000
      334.5000   59.5000   67.0000   67.0000
    

    每个方形区域都在数组areas中找到,而bb是一个数组,其中每个包含有关每个方块的信息。具体地,每行的第一和第二元素是用于完全封装对象的每个边界框的左上角的列坐标和行坐标。第三和第四个元素是每个边界框的宽度和高度。因此,这告诉我们每个边界框需要一个67 x 67像素的盒子来完全封装对象。如果整个边界框已满,这也等于的总面积。

    步骤#4

    MATLAB如何检测盒子是从上到下,从左到右。因此,只有两个框与任何圆重叠,因此这些是我们需要查看的检测结果中的前两个框。因此,对于重叠的左上角的正方形和圆形,总面积为:

    overlap1 = bb(1,3)*bb(1,4) - areas(1)
    
    overlap1  =
    
    311
    

    请记住,我们可以通过简单地将宽度和高度相乘来找到正方形的总面积。当我们用没有圆圈的正方形占据的实际面积减去它时,我们得到圆圈所取的像素。

    同样,对于底部的框:

    overlap2 = bb(2,3)*bb(2,4) - areas(2)
    
    overlap2  =
    
    351
    

    步骤#5

    最后,剩下的是实际的圈子本身。我们所要做的就是创建一个空白图像,在此图像中绘制两个圆圈以及一个逻辑AND运算符,并找到剩余的总面积。在第一步中,这两个重叠的圆圈对应于:(x,y) = 83.2850, 83.2850(x,y) = 117.6691, 118.0193。这些对应于在圆形霍夫变换中检测到的最后两个圆。让我们得到这两个圆圈并创建我们的面具:

    因此:

    centre1 = centres(3,:);
    centre2 = centres(4,:);
    radii1 = radii(3);
    radii2 = radii(4);
    circle1 = (X - centre1(1)).^2 + (Y - centre1(2)).^2 <= radii1^2;
    circle2 = (X - centre2(1)).^2 + (Y - centre2(2)).^2 <= radii2^2;
    final_two = circle1 & circle2;
    

    如果我们显示此图片,这就是我们得到的:

    enter image description here

    这可视化两个圆圈之间的重叠。现在剩下的就是简单地计算重叠:

    overlap3 = sum(final_two(:))
    
    overlap3 = 
    
    515
    

    呼!这是很多工作!

    修改

    你希望找到像上面那样的交叉区域和两个圆圈,但是对于图像的其余部分。我们需要找到另外两个相交的区域。第一个位于圆圈和正方形之间的图像底部,而第二个位于正方形和左上角的圆圈之间。

    要获得第一个,只需像我们之前所做的那样创建一个圆形蒙版,并使用触摸此圆圈的填充方块进行逻辑AND。底部的圆圈是来自圆形霍夫变换输出的第二个检测到的圆圈。此外,受影响的方格是从regionprops检测到的第二个方格。因此:

    r = radii(2);
    c = centres(2,:);
    mask_circle = (X - c(1)).^2 + (Y - c(2)).^2 <= r^2;
    mask_square = false(size(im));  
    mask_square(floor(bb(2,2)):floor(bb(2,2)) + bb(2,4), floor(bb(2,1)):floor(bb(2,1)) + bb(2,3)) = true;
    intersect1 = mask_circle & mask_square;
    

    这是第一个相交区域的样子:

    enter image description here


    您可以将上述相同的逻辑应用于顶部的其他方形和圆形区域。您只需选择正确的方形和圆形即可。这将是第四个检测到的圆圈和第一个检测到的正方形:

    r = radii(4);
    c = centres(4,:);
    mask_circle = (X - c(1)).^2 + (Y - c(2)).^2 <= r^2;
    mask_square = false(size(im));  
    mask_square(floor(bb(1,2)):floor(bb(1,2)) + bb(1,4), floor(bb(1,1)):floor(bb(1,1)) + bb(1,3)) = true;
    intersect2 = mask_circle & mask_square;
    

    这就是我们得到的:

    enter image description here

答案 1 :(得分:0)

在2个二进制图像之间找到重叠区域的更容易的解决方案是在元素上添加两个图像(在Python中简单地添加矩阵,我认为它在MATLAB中是相同的)。所有重叠的像素都将获得值2.在结果图像上应用二进制阈值,阈值设置为1.这将为您提供重叠区域。