【进阶】图像轮廓提取
1. 什么是图像轮廓?
轮廓是沿着边界连接所有连续点的曲线,具有相同的颜色或灰度值。轮廓是形状分析、物体检测和识别的有用工具。
轮廓与边缘的区别在于:边缘是零零散散的,但是轮廓是一个整体。
一幅图像经过轮廓提取后的效果应该如下图所示




有了一个对轮廓检测感性的认识之后,我们学习其图像处理实现方式。
2. 函数实现
轮廓提取的原理:先通过阈值分割提取目标物体,再通过边缘检测提取目标物体轮廓。一个轮廓就是一系列的点(像素),这些点构成了一个有序的点集合。
使用 cv2.findContours [ˈkɑnˌtʊrz] 函数可以用来检测图像的边缘。
contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
image:输入图像(二值图,而非灰度图,注意)mode:轮廓检索模式: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 个点来保存轮廓信息。
contours:返回的轮廓;hierachy[ˈhī(ə)ˌrärkē]:每条轮廓对应的属性;offset:每个轮廓点移动的可选偏移量。
返回结果是等高线和层次结构。
轮廓提取之后,还要通过 cv2.drawContours 函数绘制轮廓:
drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
image:输入图像;contours:轮廓,在 Python 中是一个 list,就是cv2.findContours函数返回的点集,一个列表;contourIdx:轮廓的索引,指定绘制轮廓 list 中的哪条轮廓,要绘制所有轮廓,传递-1;color:颜色;thickness[ˈθɪknəs] :厚度,如果是-1,表示填充;lineType:线型;hierarchy:层次结构的可选信息;maxLevel:绘制轮廓的最大级别,0:仅绘制指定的轮廓,1:绘制轮廓和所有嵌套轮廓,2:绘制轮廓,所有嵌套轮廓,所有嵌套到嵌套的轮廓;offset:轮廓偏移参数。
了解如上信息就可以有如下完整代码:
"""
Author: Will Wang
Email: WillWang1998@163.com
"""
import cv2
color_red = (0, 0, 255) # 画笔颜色(BGR)
img = cv2.imread('tyut_logo.png')
img = cv2.resize(img, (512, 512))
img_c = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转化为灰度图
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 阈值二值化
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 寻找轮廓
cv2.drawContours(img, contours, -1, color_red, 2) # 绘制轮廓到img(注意原图会被改变)
cv2.imshow('origin', img_c) # 显示原图
cv2.imshow('findContours', img) # 显示绘制轮廓后的图像
cv2.waitKey(0)
cv2.destroyAllWindows()

你也可以对自己的图像进行测试。