【发布时间】:2014-12-23 17:23:02
【问题描述】:
我有一个二值图像,我需要找到连接对象之间的像素数 我正在使用 MATLAB,这是我的图片
谢谢
【问题讨论】:
-
我回滚到以前的版本。向所有人展示您的图片的样子而不是将其从您的帖子中删除是有益的。
标签: matlab image-processing bitmap pixel connected-components
我有一个二值图像,我需要找到连接对象之间的像素数 我正在使用 MATLAB,这是我的图片
谢谢
【问题讨论】:
标签: matlab image-processing bitmap pixel connected-components
一个有趣的问题,但并不难解决。它只需要很多代码,但每一行代码的理解都非常简单。这是我将执行的基本算法:
imfindcircles 查找图像中的所有圆圈
regionprops 计算剩余正方形对象的面积,并确定封装圆形重叠的正方形所需的最小边界框。AND操作。这将找到两个圆圈相交的区域。一旦我们有了这些,我们只需计算剩余的像素,这将是两个圆圈的重叠区域。我将假设您有图像处理工具箱,否则我的方法将不起作用。您还需要至少 MATLAB R2012a 才能将循环霍夫变换包含在您的 MATLAB 发行版中。
我们需要首先反转您的图像,使白色对应于对象像素,黑色对应于背景。否则,regionprops 和 imfindcircles 将不起作用。我将直接从 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 个圆圈(如预期的那样)。 centres 和 radii 看起来像这样:
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 的优点在于它可以检测partial圆,由于圆和正方形的重叠,这非常好。如果你想查看检测到的结果,可以像这样使用viscircles:
imshow(im);
viscircles(centres, radii, 'DrawBackgroundCircle', false);
我将DrawBackgroundCircle 设置为false,因为当我们绘制检测到的圆圈时,默认情况下它会在圆圈上绘制白色轮廓。我不想让你将它与任何对象像素混淆,所以我将此标志设置为false。
这是我们得到的数字:
酷!
最简单的方法是遍历所有圆圈,创建一个圆形坐标网格,并将图像中的这些像素设置为 false 以从图像中删除这些像素。您可以通过使用meshgrid 创建行和列位置的二维网格并索引到图像以将它们设置为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));
这就是我们最终得到的:
我们现在像这样调用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 像素的框来完全封装对象。这也等于总面积如果整个边界框已满。
MATLAB 检测框的方式是从上到下、从左到右。因此,只有两个框与任何圆圈重叠,因此这是我们需要查看的检测结果中的前两个框。因此,对于左上角的正方形和圆形重叠,总面积为:
overlap1 = bb(1,3)*bb(1,4) - areas(1)
overlap1 =
311
请记住,我们可以通过简单地将正方形的宽度和高度相乘来计算正方形的总面积。当我们用没有圆圈的正方形所占据的实际面积减去它时,我们得到了圆圈所占据的像素。
同样,对于底部的框:
overlap2 = bb(2,3)*bb(2,4) - areas(2)
overlap2 =
351
最后,剩下的是实际的圆圈本身。我们所要做的就是创建一个空白图像,在这个图像中绘制两个圆圈以及一个逻辑 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;
这是我们得到的:
【讨论】:
在 2 个二进制图像之间找到重叠区域的更简单的解决方案是按元素添加两个图像(在 python 中简单地添加矩阵,我认为在 MATLAB 中是相同的)。所有重叠的像素都将获得 2 的值。对生成的图像应用二进制阈值,阈值设置为 1。这将为您提供重叠区域。
【讨论】: