购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.9 轮廓检测

轮廓检测是计算机视觉中的一项重要任务。我们希望检测图像或者视频帧中包含的主体轮廓,这不仅是其本身的目的,而且也是其他操作的一个步骤。这些操作包括多边形边界、近似形状以及常见感兴趣区域(Region Of Interest,ROI)的计算。感兴趣区域极大地简化了与图像数据的交互,因为在NumPy中很容易用数组切片定义矩形区域。在探索物体检测(包括人脸检测)和物体跟踪的概念时,我们会经常使用轮廓检测和感兴趣区域。

我们通过一个例子来熟悉一下这个API:

首先,创建一幅空白的黑色图像,大小为200×200像素。然后,利用数组的能力为切片赋值,在其中心放置一个白色的正方形。

接着,阈值化图像并调用findContours函数。这个函数有3个参数:输入图像、层次结构类型以及轮廓近似方法。第2个参数指定函数返回的层次结构树类型。其中一个值是cv2.RETR_TREE,它让函数检索外部轮廓和内部轮廓的完整结构。如果在较大物体(或者较大区域)内搜索较小的物体(或者较小的区域),这些关系可能很重要。如果只想检索最外部的轮廓,请使用cv2.RETR_EXTERNAL。在物体出现于普通的背景上并且我们不关心是否搜索物体内的对象的情况下,这可能是一种好的选择。

回顾代码示例,请注意,findContours函数返回2个元素:轮廓及其层次结构。我们使用轮廓线在彩色图像上绘制绿色的轮廓。最后,显示图像。

结果是轮廓用绿色绘制的一个白色正方形——一个斯巴达场景,但是有效地展示了此概念!我们再来看一个更有意义的例子。

3.9.1 边框、最小矩形区域以及最小外接圆

找出正方形的轮廓非常简单,不规则、倾斜和旋转的形状则需要充分发挥OpenCV的cv2.findContours函数的潜力。我们来看如图3-5所示的图像。

图3-5 示例图像

在实际应用中,我们最感兴趣的是确定主体的边框、最小外接矩形及其外接圆。cv2.findContours函数结合一些其他OpenCV实用程序,使这一任务非常容易实现。首先,下面的代码从文件读取一幅图像并将其转换为灰度图像,对灰度图像应用阈值,并在阈值化图像中找到轮廓:

其次,针对每个轮廓寻找并画出边框、最小外接矩形和最小外接圆,如下列代码所示:

最后,使用下列代码绘制轮廓并在窗口中显示图像,直到用户按下某个键:

请注意,轮廓检测是在阈值化图像上进行的,因此在这一阶段颜色信息已经丢失了,但是我们是在原始彩色图像上绘制,所以显示的是彩色结果。

我们回过头来更仔细地看一下之前的for循环中执行的步骤——在for循环中处理每个检测到的轮廓。首先,计算一个简单的边框:

这是一个非常简单的方法,可以把轮廓信息转换为矩形的(x,y)坐标、高度和宽度。绘制矩形非常简单,可以用下面的代码实现:

接下来,计算包围主体的最小矩形区域:

这里使用的机制特别有趣:OpenCV没有可以直接从轮廓信息计算最小矩形顶点坐标的函数。相反,我们先计算最小矩形区域,然后计算矩形的顶点。请注意,计算的顶点是用浮点数表示的,而像素是用整数访问的(就OpenCV的绘图函数而言,不能访问半个像素),因此我们需要进行变换。接下来,画一个框,这样才有机会引入cv2.drawContours函数:

这个函数就像所有的OpenCV绘图函数一样,都会修改原始图像。请注意,它的第2个参数接受一个轮廓线数组,这样就可以在一个操作中绘制多条轮廓线。因此,如果一组点代表一个多边形的轮廓,那么需要将这些点封装在一个数组中,就像前面的示例中对边框所做的那样。第3个参数指定要绘制的contours数组的索引:值为-1,则绘制所有的轮廓线;否则,就绘制contours数组(第2个参数)中指定的索引处的轮廓线。

大多数绘图函数将绘制的颜色(表示为BGR元组)及线宽(以像素为单位)作为最后2个参数。

我们要研究的最后一个边界轮廓是最小外接圆:

cv2.minEnclosingCircle函数的唯一特点是它返回一个二元组,其中第一个元素本身就是一个元组,表示圆心的坐标,第二个元素是圆的半径。在将所有的值转换为整数之后,画圆就非常简单了。

将前面的代码应用于原始图像,最终的结果如图3-6所示。

图3-6 生成的最小外接圆和最小外接矩形

这是一个很好的结果,因为圆和矩形紧紧包围着物体。显然,这个物体不是圆形或者矩形的,所以我们可以用更适合的其他形状。接下来就来完成这个任务吧。

3.9.2 凸轮廓和Douglas-Peucker算法

在处理轮廓时,我们可能会遇到各种形状的主体,包括凸形主体。凸形是指在形状中没有两个点的连接线在形状四周边界之外。

OpenCV提供的计算形状的近似边界多边形的第一个工具是cv2.approxPolyDP。这个函数有3个参数:

·轮廓。

·表示原始轮廓和近似多边形之间最大误差的ε值(值越低,近似值越接近原始轮廓)。

·布尔标志。如果是True,则表示多边形是闭合的。

ε值对于获得有用的轮廓非常重要,所以我们要理解它代表什么。ε是近似多边形周长和原始轮廓线周长之差的最大值。差值越小,近似多边形就越接近原始轮廓。

你可能会问自己,已经有精确表示的轮廓时,为什么还需要一个近似的多边形?因为多边形是用一组直线表示的,如果可以定义多边形,那么许多计算机视觉任务将变得简单,这样它们就可以划分区域,以便进一步操作和处理。

既然我们知道了ε是什么,那么需要获得轮廓周长信息作为参考值。这可以通过OpenCV的cv2.arcLength函数获得:

实际上,我们正在指示OpenCV计算一个近似多边形,使其周长与原始轮廓周长之间只相差ε比率,即原弧长的1%。

OpenCV还提供了一个cv2.convexHull函数,用于获取凸形的轮廓处理信息。这是一个简单的一行表达式:

我们将原始轮廓、近似多边形轮廓和凸包放在同一幅图像中以观察它们之间的差异。为了简化,我们将在黑色背景上绘制轮廓,这样原始主体就不可见了,但是它的轮廓可见,如图3-7所示。

图3-7 原始轮廓、近似多边形轮廓和凸包

如你所见,凸包包围了整个主体,近似多边形是最内层的多边形,两者之间是主要由弧线组成的原始轮廓。

通过将上述所有步骤组合到一个脚本中,进而加载文件,寻找轮廓,将轮廓近似为多边形,寻找凸包并显示可视化效果,代码如下:

这样的代码可以很好地处理简单的图像——只有一个或几个对象,而且只有几种颜色,可以很容易地用阈值分割。可是,在包含多个对象或者多种颜色对象的复杂图像中,颜色阈值和轮廓检测的效果较差。对于这些更具挑战性的情况,我们必须考虑更复杂的算法。 j48gjTdIAGASUkMWM/TP4Hk5FBLubeMyaxrnprCYEfLXG3r9Cy566SfHuzwA0jAw

点击中间区域
呼出菜单
上一章
目录
下一章
×