CH09-图像轮廓
1. 什么是轮廓
轮廓是由一系列具有相同或类似的 BGR 值或灰度值的点构成的曲线;边缘是数字图像中亮度变化明显的点所构成的曲线.
边缘检测是检测图像的边缘,也就是图像差异比较大的地方;轮廓检测是提取出图像的轮廓,轮廓可能是边缘的一部分.
边缘检测一般会将图像中边界的像素点标记为 1, 其余部分标记为 0,只有两种取值;轮廓提取则是将整个轮廓上的所有像素点的数值保留下来,因此取值比较多样.
2. 轮廓的查找与绘制
2.1 轮廓查找
contours, hierarchy = cv2.findContours(image, mode, mechod)
| 参数 | 说明 |
|---|---|
| image | 原图像 |
| mode | 寻找轮廓的模式 |
| method | 找到轮廓后的保存方式 |
| contours | 找到的轮廓,为列表的形式,列表中是一个个小的列表,每个小列表代表一条轮廓线 |
| hierarchy | 轮廓之间的结构关系 |
寻找轮廓的模式(mode)一般有以下 4 种:
| 序号 | 模式参数 | 说明 |
|---|---|---|
| 1 | cv2.RETR_EXTERNAL | 只检测外轮廓 |
| 2 | cv2.RETR_LIST | 检测的轮廓不建立等级关系 |
| 3 | cv2.RETR_CCOMP | 建立两个等级的轮廓:最外层与内层 |
| 4 | cv2.RETR_TREE | 建立一个等级树结构的轮廓 |
找到轮廓后的保存方式(method):
| 序号 | 模式参数 | 说明 |
|---|---|---|
| 1 | cv2.CHAIN_APPROX_NONE | 保存找到的轮廓中的所有点 |
| 2 | cv2.CHAIN_APPROX_SIMPLE | 将找到的轮廓上额冗余点去掉,压缩轮廓,从而节省内存空间,节省内存主要是因为其会压缩垂直、水平、对角方向,只保留端点 |
2.2 轮廓绘制
dst = cv2.drawContours(image, contours, contoursIdx, color, thickness = None, lineType = None)
| 参数 | 说明 |
|---|---|
| image | 在哪张轮廓上绘制轮廓 |
| contours | 需要绘制的轮廓,必须以列表的形式传入,且列表内的元素也必须是列表 |
| contoursIdx | 轮廓的索引,当设置为-1 时,会绘制出所有传入的 contours |
| color | 线条的颜色 |
| thickness | 线条的宽度 |
| lineType | 线条的类型 |
| dst | 绘制后输出的图像 |
2.3 轮廓的查找与绘制实例
# 读取图像
img = cv2.imread("./img/CH09-01.jpg")
x = img.shape[0]
y = img.shape[1]
# 转换为灰度值
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 高斯模糊
gauss = cv2.GaussianBlur(grey, (3, 3), 0)
# 边缘检测
edges = cv2.Canny(gauss, 50, 150)
# 去噪处理
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
closed = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
# 寻找边缘
contours, hierarchy = cv2.findContours(closed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 画出轮廓
out = cv2.drawContours(img, contours, -1, (0, 255, 0), 1)
# 图像显示
cv2.namedWindow('out', cv2.WINDOW_NORMAL)
cv2.resizeWindow('out', int(y/2), int(x/2))
cv2.imshow('out', img)
cv2.waitKey(0)
cv2.destroyAllWindows()