我正在解决检测硬币的图像处理问题。
并想将错误连接的硬币分开。
我们已经尝试了 MATLAB 主页上所述的分水岭方法:
特别是因为第一个例子正是我们的问题。
但相反,我们得到了一个非常混乱的分离,如您在此处看到的:
我们已经使用 Extrema 参数提取了硬币的区域,regionprops
并且只在需要的区域上投射了分水岭。
我将不胜感激任何有关该问题的帮助,甚至是另一种将其分开的方法。
我正在解决检测硬币的图像处理问题。
并想将错误连接的硬币分开。
我们已经尝试了 MATLAB 主页上所述的分水岭方法:
特别是因为第一个例子正是我们的问题。
但相反,我们得到了一个非常混乱的分离,如您在此处看到的:
我们已经使用 Extrema 参数提取了硬币的区域,regionprops
并且只在需要的区域上投射了分水岭。
我将不胜感激任何有关该问题的帮助,甚至是另一种将其分开的方法。
如果您有图像处理工具箱,我还可以通过imfindcircles
. 但是,这至少需要 R2012a 版本,所以如果你没有它,这将不起作用。
为了完整起见,我假设您拥有它。如果您想保持图像不变,这是一个很好的方法。如果你不知道霍夫变换是什么,它是一种在图像中寻找直线的方法。圆形霍夫变换是一种特殊情况,旨在找到图像中的圆圈。
圆形霍夫变换的附加优点是它能够检测图像中的部分圆圈。这意味着图像中连接的那些区域,我们可以将它们检测为单独的圆圈。您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
andradii
变量。 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
我们首先使用和初始化一个与图像大小相同的全零 IDs 数组来定义一个矩形网格点。接下来,对于每个圆的每对半径和中心,我们定义一个以该点为中心的圆,该圆向外延伸给定半径。然后,我们将它们用作 IDs 数组中的位置,并将其设置为该特定圆圈的唯一 ID。will的结果IDs
类似于 的输出bwlabel
。因此,如果您想提取idx
圆圈所在的位置,您可以:
cir = IDs == idx;
出于演示目的,一旦我们缩放 ID 使其适合[0-255]
可见性范围,这就是 IDs 数组的样子:
imshow(IDs, []);
因此,不同灰色阴影的每个阴影圆圈表示用 检测到的唯一圆圈imfindcircles
。
然而,某些硬币的灰色阴影可能有点模糊,因为它融入了背景。我们可以将其可视化的另一种方法是将不同的颜色映射应用于 IDs 数组。我们可以尝试使用cool
颜色图,颜色的总数为背景的唯一圆圈数 + 1。因此,我们可以这样做:
cmap = cool(numel(radii) + 1);
RGB = ind2rgb(IDs, cmap);
imshow(RGB);
上面的代码将创建一个颜色图,以便每个圆圈都映射到cool
颜色图中的唯一颜色。下一行应用了一个映射,其中每个 ID 都与一种颜色相关联,ind2rgb
我们最终显示了图像。
这是我们得到的:
编辑:以下解决方案更适合不需要拟合精确周长的情况,尽管可以使用简单的启发式方法根据在腐蚀的中心找到的中心来近似原始图像中硬币的半径。
假设您可以访问图像处理工具箱,请尝试imerode
使用原始黑白图像。它将对您的图像应用侵蚀形态算子。事实上,带有该函数文档的 Matlab 网页有一个与您的问题/图像非常相似的示例,它们使用磁盘结构。
运行以下代码(基于上面链接的示例)假设您提交的图像被调用ima.jpg
并且是代码的本地图像:
ima=imread('ima.jpg');
se = strel('disk',50);
eroded = imerode(ima,se);
imshow(eroded)
您将看到以下图像作为输出。完成此操作后,您可以使用bwlabel
标记连接的组件并计算您可能想要的任何属性,例如,计算硬币的数量或检测它们的中心。