1 原理
边界或者轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。
在机器视觉领域最常用的轮廓查找的算法之一是 Moore-Neighbor 算法,像素的摩尔邻域 $P$ 是与该像素共享顶点或边的 $8$ 个像素的集合。这些像素即 如下图所示的像素$P1$、$P2$、$P3$、$P4$、$P5$、$P6$、$P7$和$P8$。 摩尔邻域(也称为8 邻域或 间接邻域)是文献中经常出现的一个重要概念。
其大概的原理如下:
- 找到一个黑色像素,并将它定为你的起始像素。(定位一个起始像素可以以多种方式来完成的;我们将从网格的左下角开始,自下而上扫描每一列像素,从最左向右的每列像素,直到遇到一个黑色的像素,我们将其作为我们的起始像素)。
- 每次碰到黑色像素P时,都回溯,即回到之前站立的白色像素,然后以顺时针方向绕过像素$P$,访问其摩尔邻域中的每个像素,直到击中黑色像素。
- 重复这个过程,当起始像素被第二次访问时算法终止,在整个运行过程走过的黒色像素就是目标的边界像素。走过的黑色像素将成为图案的轮廓。
动画演示,说明 Moore-Neighbor 跟踪如何继续跟踪给定模式的轮廓。(以顺时针方向跟踪轮廓)
2 API
此部分参考了https://blog.csdn.net/sunny2038/article/details/12889059
在 OpenCv 中轮廓查找主要由如下两个 API 来完成。第一个是查找函数 findContours,第二个是绘制轮廓的函数 drawContours。
1 | contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]]) |
输入:
- 第一个参数是寻找轮廓的图像,注意是二值图。
- 第二个参数表示轮廓的检索模式,有四种,cv2.RETR_EXTERNAL 表示只检测外轮廓,cv2.RETR_LIST 检测的轮廓不建立等级关系,cv2.RETR_CCOMP 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。cv2.RETR_TREE 建立一个等级树结构的轮廓。
- 第三个参数method为轮廓的近似办法,cv2.CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过 1,即$max(abs(x1-x2),abs(y2-y1))==1$,cv2.CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需 4 个点来保存轮廓信息,cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用 teh-Chinl chain 近似算法
输出:
- contours 是轮廓本身。
- hierarchy 是每条轮廓对应的属性。
1 | cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]]) |
输入:
- 第一个参数是指明在哪幅图像上绘制轮廓。
- 第二个参数是轮廓本身,在 Python 中是一个 list。
- 第三个参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。thickness 表明轮廓线的宽度。
3 案例
绘制下面所有飞机的轮廓
代码:
1 | import cv2 as cv |
效果: