5.1 理解斑点检测

5.1 理解斑点检测

斑点是我们可以根据颜色辨别的区域。也许斑点本身有独特的颜色,或者背景有。与“物体”一词不同,“斑点”一词不一定意味着有质量和体积的东西。例如,表面的变化,如污渍,可以是斑点,即使他们有微不足道的质量和体积。光学效果也可以是斑点。例如,镜头的光圈会产生散焦球或失焦高光,使得光线或闪亮的物体看起来异常巨大,与光圈的形状异常相似。然而,在BeanCounter中,我们倾向于假设斑点是一个可分类的对象。

[“bokeh”一词来源于日语中竹子的意思。不同的作者对bokeh的词源给出了不同的说法,但也许有人认为散焦球就像是一截竹子明亮的边缘。]

一个典型的斑点检测器需要解决一下这些问题:

  • 分割:区分背景色和前景色;
  • 边缘检测:区分边缘像素和非边缘像素.Canny边缘检测算法是一个很流行的选择.
  • 轮廓分析:简化边缘的表示方式,这样我们就可以把它们看成几何形状。
    在下面的自章节中,我们一个一个地来实现这些步骤.

5.1.1 分割

这一步看似简单。我们将一个颜色范围映射到蒙版的背景色(白色),其余的颜色范围映射到蒙版的前景色(黑色),反之亦然。cv::inRange函数正好符合这个目的。对于某些应用程序,我们可能认为我们事先知道正确的颜色范围是什么。这通常是一个错误。灯光或场景的内容可能会发生意想不到的变化,或者我们可能只是没有考虑到一个重要的颜色。

让我们考虑一个例子。当开发人员试图检测人类存在时,他们通常依赖于对人类肤色范围的假设,无论是可见光还是红外光。这些假设往往没有得到很好的检验,因此检测器可能存在无意中的种族偏见。用户抱怨说,从Xbox Kinect到自动肥皂分配器,很多电脑视觉设备都存在这样的缺陷。

[Tech.Mic 的Max Plenke在http://mic.com/articles/124899/the-reason-this-racist-soap-dispenser-doesn-t-work-on-black-skin发表了一篇关于计算机视觉中无意识的种族偏见的有趣报告]

我们应该考虑一种自适应的方法,而不是依赖于死板的假设。我们可以在分析图像的基础上为每一帧选择一个新的背景颜色范围。一种简单且计算成本低廉的方法是分别基于平均颜色和标准差估计背景范围的中心和宽度。cv::meanStdDev函数计算了这些统计信息。更复杂的方法可以使用多个帧的历史来构建背景模型,甚至在前台对象移动时也是如此。然而,出于BeanCounter的目的,我们将继续使用更简单的方法。

[OpenCV_contrib中的bgsegm模块包含了使用历史记录的高级分割技术.官方资料位于:http://docs.opencv.org/3.1.0/d2/d55/group__bgsegm.html]

5.1.2 Canny边缘检测

在生成前景遮罩之后,我们想要检测前景和背景相接的边缘。在我之前的著作《OpenCV for Secret Agents》(Packt Publishing, 2015)中,我对边缘检测和Canny算法的一般描述是:

形状检测的一般方法应该从边缘发现滤波器(将边缘区域标记为白色,内部区域标记为黑色)开始,然后进行阈值化处理。我们将边缘定义为不同亮度的相邻区域之间的不连续的地方。因此,边缘像素的一侧有较暗的邻域,另一侧有较亮的邻域。寻找边缘的滤波器从一侧减去邻边值,然后从另一侧加上邻边值,以测量一个像素在给定方向上显示这种边缘对比度的强度。为了实现不依赖于边缘方向的测量,我们可以应用多个过滤器(每个过滤器面向不同方向的边缘),并将每个过滤器的输出视为一个向量的维度,其大小表示像素的总体“边缘”。所有像素的一组这样的测量值有时被称为图像的导数。计算了图像的导数后,我们根据边缘所需的最小对比度选择一个阈值。高阈值只接受高对比度的边缘,而低阈值只接受低对比度的边缘。

一种常用的边缘发现技术是Canny算法。OpenCV中的实现[imgproc模块中的[cv::Canny函数],同时执行过滤和阈值化。它接受灰度图像、输出图像、低阈值和高阈值作为参数。低阈值应该接受所有可能是好的边缘的像素。高阈值应该只接受确定是好的边缘的一部分的像素。对于成员可能为边缘像素的集合,Canny算法只接受连接到确定边缘像素的成员。这一双重标准有助于确保我们能够在拒绝完全模糊的边缘的同时接受大边缘的薄端。例如,笔画的线条或者延伸到远处的路缘,都可以被当做是主要的边缘。

[请注意Canny边缘查找算法生成了另一个掩码,但这是一个边缘掩码而不是前景掩码。边缘掩码在边缘区域为黑色,在非边缘区域为白色]

5.1.3 轮廓分析

给定一个边缘掩码,我们可以通过迭代地从一个黑色像素移动到相邻的黑色像素来找到连通的边缘像素集。这个过程称为边界跟踪。然后,我们可以用更少的点数来估计定义了一个轮廓的边缘。OpenCV在cv::findContours函数中实现了这种通用方法。
[cv::findeContours中实现的算法在以下论文中有详细的描述:Satoshi Suzuki. Topological Structural Analysis of Digitized Binary Images by Border Following. Computer Vision, Graphics, and Image Processing, 第30卷 (1985),32-46页.]

在找到轮廓之后,我们可以进一步简化模型。我们可以找到一个简单的几何形状来近似轮廓的边界。为此,OpenCV提供了cv::boundingRectcv::boundingEllipse等函数。边界矩形很方便,因为在BeanCounter中,我们希望裁剪出斑点的子图像。

对于某些应用程序,我们可以预先知道我们只对特定大小或形状的块感兴趣。然后,我们可以拒绝不符合我们期望的轮廓或边界形状。对于BeanCounter,我们拒绝非常小的斑点,但是我们不应用任何其他限制,因为我们想构建一个通用检测器。

###返回到第五章目录###
###返回到书籍目录###

猜你喜欢

转载自blog.csdn.net/GikkiAres/article/details/86522697
5.1