我正在研究检测硬币的图像处理问题。
并希望将虚假连接的硬币分开 我们已经尝试过MATLAB-Homepage上所述的分水岭方法:
特别是因为第一个例子正是我们的问题。
但相反,我们可以看到一个非常混乱的分离,你可以在这里看到:
我们已经使用regionprops
Extrema参数提取了硬币的区域,并仅在所需区域上投射了分水岭。
我很感激这个问题的任何帮助,甚至是另一种让它分开的方法。
答案 0 :(得分:3)
如果您有图像处理工具箱,我还可以建议Circular Hough Transform到imfindcircles
。但是,这至少需要版本R2012a,所以如果你没有它,这将不起作用。
为了完整起见,我假设你拥有它。如果您想保持图像不变,这是一个很好的方法。如果您不知道Hough Transform是什么,它是一种在图像中查找直线的方法。 圆形 Hough变换是一种特殊情况,旨在查找图像中的圆圈。
圆形霍夫变换的附加优势在于它能够检测图像中的部分圆。这意味着图像中连接的那些区域,我们可以将它们检测为单独的圆圈。如何调用imfindcircles
的方式如下:
[centers,radii] = imfindcircles(A, radiusRange);
A
将是对象的二进制图像,radiusRange
是一个双元素数组,用于指定要在图像中检测的圆的最小和最大半径。输出是:
centers
:一个N x 2
数组,可以告诉您图像中检测到的每个圆心的(x,y)
坐标 - x
是列和y
是排。 radii
:对于检测到的每个相应中心,这也给出了检测到的每个圆的半径。这是一个N x 1
数组。您可能会发现imfindcircles
的其他参数很有用,例如Sensitivity
。更高的灵敏度意味着它能够检测到更加不均匀的圆形形状,例如您在图像中显示的形状。它们不是完美的圆形,但它们是圆形的。默认灵敏度为0.85。我将其设置为0.9以获得良好的结果。另外,玩弄你的图像,我发现半径范围从50像素到150像素。因此,我这样做了:
im = im2bw(imread('http://dennlinger.bplaced.net/t06-4.jpg'));
[centers,radii] = imfindcircles(im, [50 150], 'Sensitivity', 0.9);
第一行代码直接从StackOverflow读入您的图像。我还将其转换为logical
或真正的黑白,因为您上传的图片属于uint8
类型。此图像存储在im
中。接下来,我们在我们描述的方法中调用imfindcircles
。
现在,如果我们想要查看检测到的圈子,只需使用imshow
显示您的图片,然后使用viscircles
在图片中绘制圆圈。
imshow(im);
viscircles(centers, radii, 'DrawBackgroundCircle', false);
默认情况下, viscircles
会在轮廓上绘制带有白色背景的圆圈。我想禁用它,因为你的图像有白色圆圈,我不想显示错误的轮廓。这是我用上面的代码得到的:
因此,您可以从中获取的是centers
和radii
变量。 centers
将为您提供每个检测到的圈子的中心,而radii
会告诉您每个圈子的半径是多少。
现在,如果你想模拟regionprops
正在做什么,我们可以遍历所有检测到的圆圈并将它们物理地绘制到2D地图上,其中每个圆圈都会被ID号标记。因此,我们可以这样做:
[X,Y] = meshgrid(1:size(im,2), 1:size(im,1));
IDs = zeros(size(im));
for idx = 1 : numel(radii)
r = radii(idx);
cen = centers(idx,:);
loc = (X - cen(1)).^2 + (Y - cen(2)).^2 <= r^2;
IDs(loc) = idx;
end
我们首先使用meshgrid
定义一个矩形网格点,然后初始化一个与图像大小相同的零的ID数组。接下来,对于每个圆的每对半径和中心,我们定义一个以此点为中心的圆,该圆向外延伸给定半径。然后,我们将这些作为ID数组的位置,并将其设置为该特定圆的唯一ID。 IDs
的结果将类似于bwlabel
的输出。因此,如果您想要提取idx
圈所在的位置,您可以这样做:
cir = IDs == idx;
出于演示目的,这是ID数组在我们扩展ID以使其符合[0-255]
范围以实现可见性时的样子:
imshow(IDs, []);
因此,每个不同灰色阴影的阴影圆圈表示使用imfindcircles
检测到的唯一圆圈。
然而,对于某些硬币而言,灰色阴影可能有点模棱两可,因为它会混合到背景中。我们可以看到这种方法的另一种方法是将不同的颜色映射应用于ID数组。我们可以尝试使用cool
颜色贴图,颜色总数为唯一圆的数量+背景为1。因此,我们可以这样做:
cmap = cool(numel(radii) + 1);
RGB = ind2rgb(IDs, cmap);
imshow(RGB);
上面的代码将创建一个颜色贴图,使每个圆圈都映射到cool
颜色贴图中的唯一颜色。下一行应用一个映射,其中每个ID与ind2rgb
的颜色相关联,我们最终显示图像。
这就是我们得到的:
答案 1 :(得分:0)
编辑:以下解决方案更适合于不需要拟合精确圆周的情况,尽管可以使用简单的启发式方法根据在原始图像中找到的中心来近似硬币的半径。侵蚀了一个。
假设您有权访问图像处理工具箱,请在原始黑白图像上尝试imerode
。它将对您的图像应用侵蚀形态运算符。事实上,Matlab webpage with the documentation of that function有一个与你的问题/图像惊人相似的例子,他们使用磁盘结构。
运行以下代码(基于上面链接的示例),假设您提交的图像名为ima.jpg
,并且代码是本地的:
ima=imread('ima.jpg');
se = strel('disk',50);
eroded = imerode(ima,se);
imshow(eroded)
您将看到后面的图像作为输出。执行此操作后,您可以使用bwlabel
标记已连接的组件并计算您可能需要的任何属性,例如,计算硬币数量或检测其中心。