12.1 查找并绘制轮廓

1. 查找图像轮廓:findContours函数

函数 cv2.findContours()的语法格式为:
image, contours, hierarchy = cv2.findContours( image, mode, method)
式中的返回值为:

  • image:与函数参数中的原始图像 image 一致。
  • contours:返回的轮廓。
  • hierarchy:图像的拓扑信息(轮廓层次)。
    式中的参数为:
  • image:原始图像。8 位单通道图像,所有非零值被处理为 1,所有零值保持不变。也就 是说灰度图像会被自动处理为二值图像。在实际操作时,可以根据需要,预先使用阈值 处理等函数将待查找轮廓的图像处理为二值图像。
  • mode:轮廓检索模式。
  • method:轮廓的近似方法。

1.1 返回值image

该返回值与参数 image 是一致的,就是原始输入图像。

1.2 返回值contours

该返回值返回的是一组轮廓信息,每个轮廓都是由若干个点所构成的。
(1)type 属性
返回值 contours 的 type 属性是 list 类型,list 的每个元素都是图像的一个轮廓,用 Numpy中的 ndarray 结构表示。
(2)轮廓的个数
print (len(contours))
(3)每个轮廓的点数
每一个轮廓都是由若干个像素点构成的,点的个数不固定,具体个数取决于轮廓的形状。
print(contours[0].shape)
(4)轮廓内的点
使用如下语句,可以获取轮廓内第 0 个轮廓中具体点的位置属性:
print (contours[0]) #打印第0个轮廓中的像素点

1.3 返回值hierarchy

每个轮廓 contours[i]对应 4 个元素来说明当前轮廓的层次关系。其形式为:
[Next,Previous,First_Child,Parent]式中各元素的含义为:

  • Next:后一个轮廓的索引编号。
  • Previous:前一个轮廓的索引编号。
  • First_Child:第 1 个子轮廓的索引编号
  • Parent:父轮廓的索引编号。
    使用 print 语句可以查看 hierarchy 的值:
    print(hierarchy)

1.4 参数image

一般情况下,都是将图像处理为二 值图像后,再将其作为 image 参数使用的。

1.5 参数mode

  • cv2.RETR_EXTERNAL:只检测外轮廓。
  • cv2.RETR_LIST:对检测到的轮廓不建立等级关系。
  • cv2.RETR_CCOMP:检索所有轮廓并将它们组织成两级层次结构。上面的一层为外边界,下面的一层为内孔的边界。如果内孔内还有一个连通物体,那么这个物体的边界仍
    然位于顶层。
  • cv2.RETR_TREE:建立一个等级树结构的轮廓。

1.6 参数method

  • cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻两个点的像素位置差不超过 1, 即 max(abs(x1-x2),abs(y2-y1))=1。
  • cv2.CHAIN_APPROX_SIMPLE:压缩水平方向、垂直方向、对角线方向的元素,只保 留该方向的终点坐标。例如,在极端的情况下,一个矩形只需要用 4 个点来保存轮廓信 息。

在使用函数 cv2.findContours()查找图像轮廓时,需要注意以下问题:

  1. 待处理的源图像必须是灰度二值图。因此,在通常情况下,都要预先对图像进行阈值分 割或者边缘检测处理,得到满意的二值图像后再将其作为参数使用。
  2. 在 OpenCV 中,都是从黑色背景中查找白色对象。因此,对象必须是白色的,背景必须 是黑色的。

2. 绘制图像轮廓:drawContours函数

在 OpenCV 中,可以使用函数 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:可选参数,表示绘制轮廓时所用的线型。关于参数 color、thickness 和 lineType的具体介绍,可参考第 19 章。
  • hierarchy:对应函数 cv2.findContours()所输出的层次信息。
  • maxLevel:控制所绘制的轮廓层次的深度。如果值为 0,表示仅仅绘制第 0 层的轮廓;如果值为其他的非零正数,表示绘制最高层及以下的相同数量层级的轮廓。
  • offset:偏移参数。该参数使轮廓偏移到不同的位置展示出来。

3. 轮廓实例

【例 12.1】绘制一幅图像内的所有轮廓。

import cv2
o = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/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 = cv2.findContours(binary,      #? binary没有返回值
                                        cv2.RETR_EXTERNAL,
                                        cv2.CHAIN_APPROX_SIMPLE)
o=cv2.drawContours(o,contours,-1,(0,0,255),5)  #?轮廓的颜色被设置为红色即(0,0,255),参数thickness(轮廓线条的粗细)被设置为“5”。
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()

【例 12.2】逐个显示一幅图像内的边缘信息。

import numpy as np

img = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/contours.bmp")
cv2.imshow("original",img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)

contours,hierarchy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

contoursImg = []
for i in range(len(contours)):
    temp = np.zeros(img.shape,np.uint8)
    contoursImg.append(temp)
    contoursImg[i] = cv2.drawContours(contoursImg[i],contours,i,(0,0,255),5)
    cv2.imshow("result="+str(i),contoursImg[i])
cv2.waitKey()
cv2.destroyAllWindows()

【例 12.3】使用轮廓绘制功能,提取前景对象。

img = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/loc3.jpg")
cv2.imshow("orginal",img)
gray = cv2.cvtColor(img,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(img.shape,np.uint8)
mask = cv2.drawContours(mask,contours,-1,(255,255,255),-1)

#? 参数 thickness 设置为“-1”,得到了前景对象的实心轮廓mask

cv2.imshow("mask",mask)
loc = cv2.bitwise_and(img,mask)

#? 将原始图像 o 与实心轮廓 mask 进行“按位与”运算

cv2.imshow("location",loc)
cv2.waitKey()
cv2.destroyAllWindows()
  1. 左图是原始图像,其前景对象是一朵小花。
  2. 中间的图像是从原始图像得到的小花的实心轮廓。
  3. 右图是提取的前景对象小花。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暮棂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值