0%

【OpenCv】图像的轮廓查找

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_L1CV_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
2
3
4
5
6
7
8
9
10
11
12
13
import cv2 as cv 
import numpy as np
import matplotlib.pyplot as plt
%matplotlib

img_planes = cv.imread('images/planes.png', 0)
img = np.zeros((img_planes.shape[0], img_planes.shape[1], 3))
#查找轮廓,要注意传入的图像一定要是二值图,因为我这里的图片本就是二值化图片,所以不需要二值化
contours, hierarphy = cv.findContours(img_planes, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
#绘制轮廓
cv.drawContours(img, contours, -1, (0, 0, 255), 1)
cv.imshow('img', img)
cv.waitKey(0)

效果:
在这里插入图片描述