Main Content

检测和测量图像中的圆形目标

此示例说明如何自动检测图像中的圆或圆形目标并可视化检测到的圆。

步骤 1:加载图像

读取并显示包含各种颜色的圆形塑料片的图像。除了有大量要检测的圆之外,从圆检测的角度来看,此图像还有一些有趣的特点:

  1. 有不同颜色的塑料片,它们相对于背景有不同对比度。一方面,蓝色和红色塑料片在此背景上形成强烈的对比。另一方面,一些黄色塑料片与背景的对比不明显。

  2. 请注意一些塑料片重叠在一起,而另一些塑料片则靠得很近,几乎互相接触。对于目标检测来说,场景中存在重叠的对象边缘和对象遮挡通常具有挑战性。

rgb = imread("coloredChips.png");
imshow(rgb)

Figure contains an axes object. The axes object contains an object of type image.

步骤 2:确定搜索圆的半径范围

使用 drawline 函数找到合适的圆半径范围。在塑料片的近似直径上绘制一条线。

d = drawline;

Figure contains an axes object. The axes object contains 2 objects of type image, images.roi.line.

线 ROI 的长度就是塑料片的直径。通常的塑料片的直径在 40 到 50 个像素的范围内。

pos = d.Position;
diffPos = diff(pos);
diameter = hypot(diffPos(1),diffPos(2))
diameter = 45

步骤 3:寻找圆的初步尝试

imfindcircles 函数搜索符合半径范围的圆。搜索半径在 20 到 25 个像素范围内的圆。在此之前,最好要清楚对象是比背景亮还是比背景暗。要回答该问题,请看此图像的灰度版本。

gray_image = im2gray(rgb);
imshow(gray_image)

Figure contains an axes object. The axes object contains an object of type image.

背景相当亮,大多数塑料片比背景暗。但是,默认情况下,imfindcircles 会找到比背景亮的圆形目标。因此,在 imfindcircles 中将 ObjectPolarity 名称-值参量指定为 "dark" 以搜索较暗的圆。

[centers,radii] = imfindcircles(rgb,[20 25],ObjectPolarity="dark")
centers =

     []


radii =

     []

请注意,输出 centersradii 为空,这意味着未找到圆。这种情况经常发生,因为 imfindcircles 是圆形检测器,与大多数检测器类似,imfindcircles 有内部检测阈值决定其敏感度。简而言之,这意味着检测器对某个(圆形)检测的信心必须大于某个水平,才将其视为有效检测。imfindcirclesSensitivity 名称-值参量,可用于控制此内部阈值,从而控制算法的敏感度。Sensitivity 值越高,检测阈值设置得越低,并导致检测到更多圆。这类似于家庭安全系统中使用的运动检测器的敏感度控制。

步骤 4:提高检测敏感度

回到塑料片图像,在默认敏感度水平下,可能所有圆都低于内部阈值,因此未检测到圆。Sensitivity 是介于 0 和 1 之间的数字,默认设置为 0.85。将 Sensitivity 提高到 0.9。

[centers,radii] = imfindcircles(rgb,[20 25],ObjectPolarity="dark", ...
    Sensitivity=0.9)
centers = 8×2

  146.1895  198.5824
  328.8132  135.5883
  130.3134   43.8039
  175.2698  297.0583
  312.2831  192.3709
  327.1316  297.0077
  243.9893  166.4538
  271.5873  280.8920

radii = 8×1

   23.1604
   22.5710
   22.9576
   23.7356
   22.9551
   22.9995
   22.9055
   23.0298

这次,imfindcircles 发现了一些圆 - 准确地说是八个。centers 包含圆心的位置,radii 包含这些圆的估计半径。

步骤 5:在图像上绘制圆

函数 viscircles 可用于在图像上绘制圆。来自 imfindcircles 的输出变量 centersradii 可以直接传递给 viscircles

imshow(rgb)
h = viscircles(centers,radii);

Figure contains an axes object. The axes object contains 3 objects of type line, image.

圆心似乎定位正确,它们对应的半径似乎与实际塑料片匹配良好。但仍未检测到相当多的塑料片。请尝试将 Sensitivity 提高到 0.92。

[centers,radii] = imfindcircles(rgb,[20 25],ObjectPolarity="dark", ...
    Sensitivity=0.92);

length(centers)
ans = 16

提高 Sensitivity 会找到更多的圆。再次在图像上绘制这些圆。

delete(h)  % Delete previously drawn circles
h = viscircles(centers,radii);

Figure contains an axes object. The axes object contains 3 objects of type line, image.

步骤 6:使用第二种方法(两阶段)寻找圆

此方法的结果看起来更好。imfindcircles 有两种不同寻找圆的方法。到当前为止,默认方法(称为相位编码方法)用于检测圆。在 imfindcircles 中还可以使用另一种方法,通常称为两阶段方法。使用两阶段方法并显示结果。

[centers,radii] = imfindcircles(rgb,[20 25],ObjectPolarity="dark", ...
    Sensitivity=0.92,Method="twostage");

delete(h)
h = viscircles(centers,radii);

Figure contains an axes object. The axes object contains 3 objects of type line, image.

两阶段方法在 Sensitivity 值为 0.92 处检测到更多圆。一般来说,这两种方法是互补的,因为它们各有优点。相位编码方法通常比两阶段方法更快,抗噪声的稳定性稍强。但是,它也可能需要更高的 Sensitivity 水平才能实现与两阶段方法相同数量的检测。例如,如果 Sensitivity 水平提高到 0.95,相位编码方法也会找到相同的塑料片。

[centers,radii] = imfindcircles(rgb,[20 25],ObjectPolarity="dark", ...
          Sensitivity=0.95);

delete(h)
viscircles(centers,radii);

Figure contains an axes object. The axes object contains 3 objects of type line, image.

请注意,imfindcircles 中的两种方法都能准确找到部分可见(遮挡)塑料片的中心和半径。

步骤 7:为什么有些圆仍检测不到?

查看最后一个结果,很奇怪 imfindcircles 没有在图像中找到黄色塑料片。黄色塑料片与背景的对比不够强烈。事实上,它们看起来和背景的强度非常相似。是不是黄色塑料片并没有想象中的那样比背景“更暗”?要确认这一点,请再次显示该图像的灰度版本。

imshow(gray_image)

Figure contains an axes object. The axes object contains an object of type image.

步骤 8:在图像中找到“明亮”的圆

与背景相比,黄色塑料片的强度几乎相同,甚至更亮。因此,要检测黄色塑料片,请将 ObjectPolarity 更改为 "bright"

[centersBright,radiiBright] = imfindcircles(rgb,[20 25], ...
    ObjectPolarity="bright",Sensitivity=0.92);

步骤 9:用不同颜色绘制“Bright”圆

通过更改 viscircles 中的 Color 名称-值参量,以不同颜色绘制明亮的圆。

imshow(rgb)

hBright = viscircles(centersBright,radiiBright,Color="b");

Figure contains an axes object. The axes object contains 3 objects of type line, image.

请注意,找到了三个原先未检测到的黄色塑料片,但仍有黄色塑料片未检测到。这些黄色塑料片很难检测到,因为在这种背景下,它们没有呈现出与众不同。

步骤 10:降低 EdgeThreshold 的值

在这里还可以使用 imfindcircles 中的另一个名称-值参量,即 EdgeThreshold。要查找圆,imfindcircles 仅使用图像中的边缘像素。这些边缘像素基本上是具有高梯度值的像素。EdgeThreshold 名称-值参量控制像素的梯度值必须有多高,才能将其视为边缘像素并包含在计算中。该参数的高值(更接近 1)只允许包含强边缘(较高梯度值),而低值(更接近 0)的宽容度更高,可在计算中包含较弱的边缘(较低梯度值)。对于检测不到黄色塑料片的情况,是因为对比度低,一些边界像素(在塑料片的圆周上)预期具有低梯度值。因此,请降低 EdgeThreshold 值,以确保黄色塑料片的大多数边缘像素都包含在计算中。

[centersBright,radiiBright,metricBright] = imfindcircles(rgb,[20 25], ...
    ObjectPolarity="bright",Sensitivity=0.92,EdgeThreshold=0.1);

delete(hBright)
hBright = viscircles(centersBright,radiiBright,Color="b");

Figure contains an axes object. The axes object contains 3 objects of type line, image.

步骤 11:同时绘制“暗”和“亮”圆

现在 imfindcircles 找到了所有黄色圆,还找到了一个绿色圆。用蓝色绘制这些塑料片,用红色绘制之前发现的其他塑料片(ObjectPolarity 设置为 "dark")。

h = viscircles(centers,radii);

Figure contains an axes object. The axes object contains 5 objects of type line, image.

所有圆都被检测到。最后 - 应注意,在检测中更激进地更改参数可能会发现更多圆,但也会增加检测到假圆的可能性。需要在可找到的真圆数量(检测率)和用它们找到的假圆数量(虚警率)之间实现某种平衡。

祝您能顺利检测到圆!

另请参阅

| |

相关主题