一、轮廓的检测
- 轮廓检测是指在包含目标和背景的数字图像中,忽略背景和目标内部的纹理以及噪声干扰的影响,采用一定的技术和方法来实现目标轮廓提取的过程
- 注意:做轮廓检测前需要将图片读取为二值数据,即像素值只为0和255
- 轮廓检测所用到的函数为 cv2.findcontours(img, mode, method)
- 参数介绍:
- image:需要实现轮廓检测的原图
- mode:轮廓的检索模式,主要有四种方式:
- CV2.RETR_EXTERNAL:只检测外轮廓,所有子轮廓被忽略
- CV2.RETR_LIST:检测的轮廓不建立等级关系,所有轮廓属于同一等级。
- CV2.RETR_CCOMP: 检索所有的轮廓,并建立一个两级层次结构,其中上面的一层为外边界,里面的一层为内孔的边界轮廓。
- CV2.RETR_TREE:返回所有的轮廓,建立一个完整的组织结构的轮廓。
- method:轮廓的近似方法,主要有以下两种:
- CV2.CHAIN_APPROX_NONE:存储所有的轮廓点。
- CV2.CHAIN_APPROX_SIMPLE:压缩模式,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廊信息。
- 返回的参数:image,contours,hierarchy
- image:返回处理的原图(在 OpenCV 4.x 中这个返回值已经被移除)
- contours:包含图像中所有轮廓的list对象。其中每一个独立的轮廓信息以边界点坐标(x,y)的形式储存在numpy数组中。
- hierarchy:轮廓的层次结构。一个包含4个值的数组:[Next,Previous,First child,Parent]
- Next:与当前轮廓处于同一层级的下一条轮廓
- Previous:与当前轮廓处于同一层级的上一条轮廓
- First Child:当前轮廓的第一条子轮廓
- Parent:当前轮廓的父轮廓
二、轮廓的绘制
- cv2.drawContours()函数是用于在图像上绘制轮廓
- 参数介绍:cv2.drawContours(image, contours, contourIdx, color, thickness=None
lineType=None, hierarchy=None, maxLevel=None, offset=None)- image:要在其上绘制轮廓的输入图像(在原图中画)。
- contours:轮廓列表,通常由cv2.findContours()函数返回。
- contourIdx:要绘制的轮廓的索引。如果为负数,则绘制所有轮廓。–> -1
- color:轮廓的颜色,以BGR格式表示。例如,(0,255,0)表示绿色。
- thickness:轮廓线的粗细,默认值为1。
- lineType:轮廓线的类型。默认值为cV2.LINE_8
- hierarchy:轮廓层次结构。通常由cv2.findContours()函数返回.
- maxLevel:绘制的最大轮廓层级。默认值为None,表示绘制所有层级。
- offset:轮廓点的偏移量。默认值为None。
图像轮廓检测与绘制的代码实现
import cv2
# 读取图片
phone = cv2.imread('phone.png')
phone_gray = cv2.cvtColor(phone, cv2.COLOR_BGR2GRAY) # 转换为灰度图
# 阙值处理为二值(黑白图像)
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)
# 查找图像轮廓 cv2.RETR_LIST --> 查找所有轮廓,且不建立等级关系
_, contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# 查看轮廓的层次结构
print(hierarchy)
# 查看一共有多少的轮廓
print(len(contours))
# 绘制所有的轮廓
Contours_show = cv2.drawContours(phone, contours=contours, contourIdx=-1, color=(0, 255, 0), thickness=3)
# 显示灰度图和在原图中绘出轮廓后的图
cv2.imshow('phone_gray', phone_gray)
cv2.imshow('Contours_show', Contours_show)
# 等待任意键按下后关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
- 结果如下
三、轮廓的近似
-
轮廓的近似是计算机视觉和图像处理中的一个常用技术。它可以帮助我们简化轮廓的形状,去除一些不必要的细节,同时保持轮廓的主要形状特征。
-
在OpenCV中,可以使用cv2.approxPolyDP()函数来近似一个轮廓。这个函数基于 Douglas-Peucker 算法,该算法通过迭代的方式简化轮廓的顶点集合,以生成一个近似于原始轮廓的多边形,但顶点数量更少。这在处理图像中的形状时非常有用,特别是当你想要去除轮廓上的小噪点或不必要的细节,同时保留其主要形状特征时。
-
参数解释:cv2.approxPolyDP(curve, epsilon, closed)
- curve:输入轮廓,通常是一个由点组成的 NumPy 数组,这些点定义了轮廓的形状。
- epsilon:近似的精度参数。它是原始轮廓到近似多边形之间的最大距离。较小的 epsilon 值意味着近似多边形将更接近原始轮廓,但可能会包含更多的顶点。较大的 epsilon 值会导致生成一个更简单的多边形,但可能会丢失一些细节。
- closed:一个布尔值,指定近似多边形是否应该是封闭的。如果为 True,则函数将确保近似多边形是封闭的,即第一个和最后一个顶点将相同。
-
返回值 approx 是一个新的 NumPy 数组,包含了近似多边形的顶点。
-
代码实现
import cv2 # 读取图像 he = cv2.imread('he.png') # 转换为灰度图像 he_gray = cv2.cvtColor(he, cv2.COLOR_BGR2GRAY) # 应用阈值处理 ret, he_thresh = cv2.threshold(he_gray, 120, 255, cv2.THRESH_BINARY) # 查找轮廓 _, contours, hierarchy = cv2.findContours(he_thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 创建一个新图像用于绘制轮廓 he_new = he.copy() # 遍历所有轮廓 for cnt in contours: # 轮廓近似 # cv2.arcLength()函数用于计算轮廓的周长(近似的精度设置为周长的0.2%) epsilon = 0.002 * cv2.arcLength(cnt, True) # 可以调整epsilon的值以获得不同的近似精度 approx = cv2.approxPolyDP(cnt, epsilon, True) # 绘制近似后的轮廓 cv2.drawContours(he_new, [approx], 0, (0, 255, 0), 3) # 显示原始图像和带有轮廓的图像 cv2.imshow('Original Image', he) cv2.imshow('Image with Contours', he_new) # 等待任意键按下后关闭所有窗口 cv2.waitKey(0) cv2.destroyAllWindows()
- 结果如下
- 由结果可以看出轮廓的近似结果就是一个近似于原始轮廓的多边行。
- 结果如下