绘制图像轮廓:drawContours函数
在 OpenCV 中,可以使用函数 cv2.drawContours()绘制图像轮廓。该函数的语法格式是:
image=cv2.drawContours( image, contours, contourIdx, color[,
thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]] )
其中,函数的返回值为 image,表示目标图像,即绘制了边缘的原始图像。
该函数有如下参数:
-
image:待绘制轮廓的图像。需要注意,函数 cv2.drawContours()会在图像 image 上直接绘制轮廓。也就是说,在函数执行完以后,image 不再是原始图像,而是包含了轮廓的图像。因此,如果图像 image 还有其他用途的话,则需要预先复制一份,将该副本图像传递给函cv2.drawContours()使用。
-
contours:需要绘制的轮廓。该参数的类型与函数 cv2.findContours()的输出 contours 相同,都是 list 类型。
-
contourIdx:需要绘制的边缘索引,告诉函数 cv2.drawContours()要绘制某一条轮廓还是全部轮廓。如果该参数是一个整数或者为零,则表示绘制对应索引号的轮廓;如果该值
为负数(通常为"-1"),则表示绘制全部轮廓。
-
color:绘制的颜色,用 BGR 格式表示。
-
thickness:可选参数,表示绘制轮廓时所用画笔的粗细。如将该值设置为"-1",则表示
要绘制实心轮廓。
-
lineType:可选参数,表示绘制轮廓时所用的线型。
-
hierarchy:对应函数 cv2.findContours()所输出的层次信息。
-
maxLevel:控制所绘制的轮廓层次的深度。如果值为 0,表示仅仅绘制第 0 层的轮廓;如果值为其他的非零正数,表示绘制最高层及以下的相同数量层级的轮廓。
-
offset:偏移参数。该参数使轮廓偏移到不同的位置展示出来。
函数 cv2.drawContours()的参数 image 和返回值 image,在函数运算后的值是相同的。因此,也可以将函数 cv2.drawContours()写为没有返回值的形式:
cv2.drawContours( image, contours, contourIdx, color[, thickness[,
lineType[, hierarchy[, maxLevel[, offset]]]]] )
代码示例:绘制一幅图像内的所有轮廓。
如果要绘制图像内的所有轮廓,需要将函数 cv2.drawContours()的参数 contourIdx 的值设置为"-1"。
实验原图上一节中有可下载
代码如下:
import cv2
o = cv2.imread('contours.bmp')
cv2.imshow("original",o)
#将原图像转换为灰度图像
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
#将灰度图像转换为二值图像
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
#寻找轮廓,返回的contours是轮廓的列表,hierarchy是每个轮廓对应的属性
contours, hierarchy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#绘制轮廓,contours是轮廓的列表,-1表示绘制所有轮廓,(0,0,255)表示轮廓颜色为红色,5表示轮廓宽度为5
o=cv2.drawContours(o,contours,-1,(0,0,255),5)
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()
运行效果如下:
在本程序中,轮廓的颜色被设置为红色(由于黑白印刷的原因,在纸质书中显示为灰色),
即(0, 0, 255),参数 thickness(轮廓线条的粗细)被设置为"5"。
示例2 逐个切割一幅图像内的边缘信息。
import cv2
import numpy as np
o = cv2.imread('contours.bmp')
#显示原始图像
cv2.imshow("original",o)
#将原图像转换为灰度图像
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
#将灰度图像转换为二值图像
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
#寻找轮廓,返回的contours是轮廓的列表,hierarchy是每个轮廓对应的属性
contours, hierarchy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#获取轮廓的数量
n=len(contours)
#对每个轮廓进行绘制
contoursImg=[]
for i in range(n):
#创建空白画布
temp=np.zeros(o.shape,np.uint8)
contoursImg.append(temp)
#绘制轮廓,contours是轮廓的列表,i表示绘制第i个轮廓,(255,255,255)表示轮廓颜色为白色,5表示轮廓宽度为5
contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,(255,255,255),5)
cv2.imshow("contours[" + str(i)+"]",contoursImg[i])
cv2.waitKey()
cv2.destroyAllWindows()
示例3:使用轮廓绘制功能,提取前景对象。
将函数 cv2.drawContours()的参数 thickness 的值设置为"-1",可以绘制前景对象的实心轮廓。将该实心轮廓与原始图像进行"按位与"操作,即可将前景对象从原始图像中提取出来。
代码如下:
import cv2
import numpy as np
o = cv2.imread('loc3.jpg')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#创建空白画布
mask=np.zeros(o.shape,np.uint8)
#绘制轮廓,contours是轮廓的列表,-1表示绘制所有轮廓,(255,255,255)表示轮廓颜色为白色,-1表示轮廓宽度为-1,表示对轮廓进行填充
mask=cv2.drawContours(mask,contours,-1,(255,255,255),-1)
#显示掩膜
cv2.imshow("mask" ,mask)
#将原图像和掩膜进行位运算
loc=cv2.bitwise_and(o,mask)
cv2.imshow("location" ,loc)
cv2.waitKey()
cv2.destroyAllWindows()
本例中将函数 cv2.drawContours()的参数 thickness 设置为"-1",得到了前景对象的实心轮
廓 mask。接下来,通过语句"cv2.bitwise_and(o, mask)",将原始图像 o 与实心轮廓 mask 进行
"按位与"运算,就得到了原始图像的前景对象。
运行结果:
- 左图是原始图像,其前景对象是一朵小花。
- 中间的图像是从原始图像得到的小花的实心轮廓。
- 右图是提取的前景对象小花。
实验原图