0

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

在此处输入图像描述

谢谢

4

2 回答 2

1

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

  1. 使用圆形霍夫变换查找图像中的所有圆圈-imfindcircles
  2. 从图像中删除圆圈
  3. 用于regionprops计算剩余正方形对象的面积,并确定封装圆形重叠的正方形所需的最小边界框。
  4. 如果要完全填充,这些最小边界框坐标将是正方形的左上角和右下角坐标。因为有些圆圈与正方形重叠,所以我们可以通过简单地取每个边界框的全部区域并减去检测到的区域来找到重叠区域。剩下的数量将是与圆圈重叠的区域。
  5. 要找出两个圆圈重叠的区域,我们需要做的就是在图像上绘制两个圆圈并进行逻辑AND运算。这将找到两个圆圈相交的区域。一旦我们有了这些,我们只需计算剩余的像素,这将是两个圆圈的重叠区域。

我将假设您有图像处理工具箱,否则我的方法将不起作用。您还需要至少 MATLAB R2012a 才能将循环霍夫变换包含在您的 MATLAB 发行版中。


步骤1

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

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

接下来,让我们使用圆形霍夫变换。我们会这样使用它:

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

im将是我们刚刚转换的二进制图像,数组[25 60]表示我们要检测的圆的最小和最大半径。在这种情况下,最小半径为 25,最大半径为 60。 centres分别radii表示每个圆心的列坐标和行坐标以及每个圆的半径。的第一列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,从每个结果的第一行读取。您可以跟随每个变量中的其余值。Circular Hough Transform 的优点在于它可以检测部分圆形,由于圆形和正方形的重叠,这非常好。如果要查看检测到的结果,可以viscircles这样使用:

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

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

这是我们得到的图:

在此处输入图像描述

凉爽的!


第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. 但是,图像现在的样子是:

在此处输入图像描述

由于量化噪声,圆圈中存在一些边缘伪影。我们可以使用 删除这些像素bwareaopen。任何面积低于一定数量的区域,将其从图像中删除。我们可以选择 50 之类的值,因为这些正方形肯定超出了 50 像素的区域,而虚假像素则没有。完成此操作后,让我们进行形态学开场,imopen以消除与每个正方形相连的任何嘈杂像素,这样我们就可以真正得到没有任何圆圈的正方形形状。

所以:

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

这最终是我们得到的:

在此处输入图像描述

步骤#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

每个正方形区域都在数组中找到,而数组areasbb一个数组,其中每包含有关每个正方形的信息。具体来说,每一行的第一个和第二个元素是用于完全封装对象的每个边界框的左上角的列坐标和行坐标。第三个和第四个元素是每个边界框的宽度和高度。因此,这告诉我们每个边界框都需要一个 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;

如果我们展示这张图片,我们会得到:

在此处输入图像描述

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

overlap3 = sum(final_two(:))

overlap3 = 

515

哇!那是很多工作!

编辑

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

要获得第一个,只需像我们之前所做的那样创建一个圆形蒙版,并与接触该圆圈的填充方块进行逻辑与运算。底部的圆圈是圆形霍夫变换输出中检测到的第二个圆圈。此外,受影响的方块是从 中检测到的第二个方块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;

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

在此处输入图像描述


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

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;

这是我们得到的:

在此处输入图像描述

于 2014-12-23T18:33:50.307 回答
0

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

于 2017-02-01T14:41:57.770 回答