OpenCV findContours()函数的用法(附带实例)
在 OpenCV 中,使用 findContours() 函数,只需简单的几个步骤就可以检测出物体的轮廓,十分方便。
findContours() 函数声明如下:
1) image 表示原始图像,必须是 8 位单通道二值图像。一般情况下,都是将图像处理为二值图像后,再将其作为 image 参数来使用;
2) 参数 mode 决定了轮廓的提取方式,具体有如下 4 种:
3) 参数 method 决定了如何表达轮廓,可以取如下值:
4) 参数 contours 是一个向量,并且是双重向量,向量内每个元素保存了一组由连续的 Point 构成的点的集合向量,每一组 Point 点集就是一个轮廓,有多少个轮廓,向量 contours 内就有多少个元素。
5) 参数 hierarchy 定义为“vector<Vec4i> hierarchy”,其中,Vec4i 的定义如下:
向量 hierarchy 内的元素和轮廓向量 contours 内的元素是一一对应的,向量的容量相同。hierarchy 向量内每一个元素的 4 个 int 型变量(hierarchy[i][0]~hierarchy[i][3]),分别表示第 i 个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓,那么 hierarchy[i][0]~hierarchy[i][3] 的相应位被设置为默认值 -1。
6) 参数 offset 表示每个轮廓点移动的可选偏移量。
另外,绘制轮廓函数 drawContours() 经常和查找轮廓函数 findContours() 联合使用,查找出轮廓后通常需要把轮廓绘制出来。函数 drawContours() 声明如下:
【实例】查找图像的轮廓。
运行工程,结果如下图所示:
注意,findContours() 函数会“原地”修改输入的图像。这一点可以通过下面的语句验证:
findContours() 函数声明如下:
cv.findContours( image, mode, method[, contours[, hierarchy[, offset]]]) -> contours, hierarchy各个参数的含义如下:
1) image 表示原始图像,必须是 8 位单通道二值图像。一般情况下,都是将图像处理为二值图像后,再将其作为 image 参数来使用;
2) 参数 mode 决定了轮廓的提取方式,具体有如下 4 种:
- cv2.RETR_EXTERNAL:只检测外轮廓;
- cv2.RETR_LIST:对检测到的轮廓不建立等级关系;
- cv2.RETR_CCOMP:检索所有轮廓并将它们组织成两级层次结构。上面的一层为外边界,下面的一层为内孔的边界。如果内孔内还有一个连通物体,那么这个物体的边界仍然位于顶层;
- cv2.RETR_TREE:建立一个等级树结构的轮廓。
3) 参数 method 决定了如何表达轮廓,可以取如下值:
- cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻两个点的像素位置差不超过 1,即 max(abs(x1-x2),abs(y2-y1))=1;
- cv2.CHAIN_APPROX_SIMPLE:压缩水平方向、垂直方向、对角线方向的元素,只保留该方向的终点坐标。例如,在极端的情况下,一个矩形只需要用4个点来保存轮廓信息;
- cv2.CHAIN_APPROX_TC89_L1:使用 teh-Chinl chain 近似算法的一种风格;
- cv2.CHAIN_APPROX_TC89_KCOS:使用 teh-Chinl chain 近似算法的一种风格。
4) 参数 contours 是一个向量,并且是双重向量,向量内每个元素保存了一组由连续的 Point 构成的点的集合向量,每一组 Point 点集就是一个轮廓,有多少个轮廓,向量 contours 内就有多少个元素。
5) 参数 hierarchy 定义为“vector<Vec4i> hierarchy”,其中,Vec4i 的定义如下:
typedef Vec<int, 4> Vec4i;Vec4i 是 Vec<int,4> 的别名,定义了一个“向量内每一个元素包含了 4 个 int 型变量”的向量。所以从定义上看 hierarchy 也是一个向量,向量内每个元素保存了一个包含 4 个 int 型的数组。
向量 hierarchy 内的元素和轮廓向量 contours 内的元素是一一对应的,向量的容量相同。hierarchy 向量内每一个元素的 4 个 int 型变量(hierarchy[i][0]~hierarchy[i][3]),分别表示第 i 个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓,那么 hierarchy[i][0]~hierarchy[i][3] 的相应位被设置为默认值 -1。
6) 参数 offset 表示每个轮廓点移动的可选偏移量。
另外,绘制轮廓函数 drawContours() 经常和查找轮廓函数 findContours() 联合使用,查找出轮廓后通常需要把轮廓绘制出来。函数 drawContours() 声明如下:
cv.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) -> image各个参数的含义如下:
- image 表示目标图像;
- contours 表示输入的轮廓组,每一组轮廓由点 vector 构成;
- contourIdx 指明画第几个轮廓,如果该参数为负值,则画全部轮廓;
- color 为轮廓的颜色;
- thickness 为轮廓的线宽,如果为负值或 CV_FILLED,就表示填充轮廓内部;
- lineType 为线型;
- hierarchy 为轮廓结构信息;
- maxLevel 表示绘制轮廓的最高级别,只在 hierarchy 有效的时候才有效,值为 0 时,绘制与输入轮廓属于同一等级的所有轮廓(输入轮廓和与其相邻的轮廓),值为 1 时,绘制与输入轮廓同一等级的所有轮廓与其子节点,值为 2 时,绘制与输入轮廓同一等级的所有轮廓与其子节点以及子节点的子节点;
- offset 表示可选的轮廓偏移参数。
【实例】查找图像的轮廓。
import cv2 img = cv2.imread("test2.jpg") gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) #检测轮廓 contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img,contours,-1,(0,0,255),3) #绘制轮廓 cv2.imshow("img", img) cv2.waitKey(0)需要注意的是,cv2.findContours() 函数接收的参数为二值图,即黑白图(不是灰度图),所以读取的图像要先转为灰度图再转为二值图。最后检测轮廓、绘制轮廓。
运行工程,结果如下图所示:

注意,findContours() 函数会“原地”修改输入的图像。这一点可以通过下面的语句验证:
cv2.imshow("binary", binary) contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) cv2.imshow("binary2", binary)执行这段代码后,可以发现原图被修改了。