opencv-python 详解轮廓及findContours()、drawContours()函数

目录

轮廓的定义 

轮廓和边缘的区别 

寻找轮廓的方法和经验 

先看一个demo,图片:

findContours()详解 

 (敲黑板划重点)理解轮廓层级、等级:

轮廓的检索方法模式4种:

轮廓的近似办法有4种: 


轮廓的定义 

        轮廓是一系列相连的点组成的曲线,代表了物体的基本外形。    

轮廓和边缘的区别 

        谈起轮廓不免想到边缘,它们确实很像。简单的说,轮廓是连续的,边缘并不全都连续(下图)。其实边缘主要是作为图像的特征使用,比如可以用边缘特征可以区分脸和手,而轮廓主要用来分析物体的形态,比如物体的周长和面积等,可以说边缘包括轮廓。

寻找轮廓的方法和经验 

寻找轮廓的操作一般基于二值化图,所以通常会使用阈值分割或Canny边缘检测先得到二值图。
经验之谈:寻找轮廓是针对白色物体的,一定要保证物体是白色,而背景是黑色,不然很多人在
寻找轮廓时会找到图片最外面的一个框。

先看一个demo,图片:

 代码:

import cv2

img = cv2.imread('handwriting.jpg')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用Otsu自动阈值,注意用的是cv2.THRESH_BINARY_INV
ret, thresh = cv2.threshold(
    img_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# cv2.imshow("thresh", thresh)
"""
寻找轮廓方法三个参数:输入图像,轮廓检索模式,轮廓近似方法
返回值contours是轮廓本身contours,还有一个是每条轮廓对应的属性hierarchy,下边详解
"""
contours, hierarchy = cv2.findContours(
    thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(len(contours)) # 结果应该为2,两个轮廓
cnt = contours[1]
"""
绘制轮廓:
第一个参数是一张图片,可以是原图或者其他。
第二个参数是轮廓,也可以说是cv2.findContours()找出来的点集,一个列表。
第三个参数是对轮廓(第二个参数)的索引,当需要绘制独立轮廓时很有用,若要全部绘制可设为-1。
接下来的参数是轮廓的颜色和厚度。
"""
cv2.drawContours(img, [cnt], 0, (0, 0, 255), 2)

cv2.imshow('contours', img)
cv2.waitKey(0)

findContours()详解 

使用 cv2.findContours() 寻找轮廓,findContours()有三个参数:输入图像,轮廓检索模式,轮廓近似方法,返回值contours是轮廓本身contours,还有一个是每条轮廓对应的属性hierarchy,下边详解 。

 (敲黑板划重点)理解轮廓层级、等级:

 图中总共有8条轮廓,22a分别表示外层和里层的轮廓,33a也是一样。从图中看得出来:

  • 轮廓0/1/2是最外层的轮廓,我们可以说它们处于同一轮廓等级:0
  • 轮廓2a是轮廓2的子轮廓,反过来说22a的父轮廓,轮廓2a算一个等级:1
  • 同样32a的子轮廓,轮廓3处于一个等级:2
  • 类似的,3a3的子轮廓,等等…………
这里面 OpenCV 关注的就是两个概念:同一轮廓等级和轮廓间的子属关系。

如果我们打印出 cv2.findContours() 函数的返回值hierarchy,会发现它是一个包含4个值的数组:
[Next, Previous, First Child, Parent]

  •  Next:与当前轮廓处于同一层级的下一条轮廓,举例来说,前面图中跟0处于同一层级的下一条轮廓是1,所以Next=1;同理,对轮廓1来说,Next=2;那么对于轮廓2呢?没有与它同一层级的下一条轮廓了,此时Next=-1。
  • Previous:与当前轮廓处于同一层级的上一条轮廓,跟前面一样,对于轮廓1来说,Previous=0;对于轮廓2,Previous=1;对于轮廓1,没有上一条轮廓了,所以Previous=-1。
  • First Child:当前轮廓的第一条子轮廓,比如对于轮廓2,第一条子轮廓就是轮廓2a,所以First Child=2a;对轮廓3a,First Child=4。
  • Parent:当前轮廓的父轮廓

比如2a的父轮廓是2,Parent=2;轮廓2没有父轮廓,所以Parent=-1。

经验之谈: OpenCV 中找到的轮廓序号跟前面讲的不同噢,如下图:

轮廓的检索方法模式4种:

  •  CV2.RETR_EXTERNAL  表示只检测外轮廓。这种方式只寻找最高层级的轮廓,也就是它只会找到前面我们所说的30级轮廓:

  •  CV2.RETR_LIST  检测的轮廓不建立等级关系。这是最简单的一种寻找方式,它不建立轮廓间的子属关系,也就是所有轮廓都属于同一层级。这样, hierarchy中的后两个值[First Child, Parent]都为-1。比如同样的图,我们使用cv2.RETR_LIST来寻找轮廓:

         因为没有从属关系,所以轮廓0的下一条是11的下一条是2……

        经验之谈:如果你不需要轮廓层级信息的话,cv2.RETR_LIST 更推荐使用,因为性能更好。
  •  CV2.RETR_CCOMP  建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。cv2.RETR_CCOMP比较难理解,但其实也很简单:它把所有的轮廓只分为2个层级,不是外层的就是里层的。结合代码和图片,我们来理解下:

 图中括号里面1代表外层轮廓,2代表里层轮廓。比如说对于轮廓2,Next就是4,Previous是1,它有里层的轮廓3,所以First Child=3,但因为只有两个层级,它本身就是外层轮廓,所以Parent=-1。大家可以针对其他的轮廓自己验证一下。

  •  CV2.RETR_TREE  建立一个等级树结构的轮廓。前面已经详细说明过了

轮廓的近似办法有4种: 

CV2.CHAIN_APPROX_NONE  存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2), abs(y2-y1))<=1。
CV2.CHAIN_APPROX_SIMPLE  压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息。
CV2.CHAIN_APPROX_TC89_L1 和 CV2.CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法。

绘制轮廓cv2.drawContours()函数比较简单就不多说了,看上边demo就行。

  • 11
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Opencv-python图像变换是通过使用不同的变换矩阵来实现的。其中,平移是一种最简单的空间变换。使用Opencv函数cv2.warpAffine()可以实现平移操作。在代码中,我们需要定义一个变换矩阵M,这个矩阵是一个2行3列的矩阵,决定了平移的方式。其中,M矩阵中的tx和ty分别表示在x和y方向上平移的距离。更具体地说,如果我们向右平移tx个像素,向下平移ty个像素,那么变换矩阵M的定义如下: import numpy as np rows, cols = img.shape[:2] M = np.float32([[1, 0, tx], [0, 1, ty]]) dst = cv2.warpAffine(img, M, (cols, rows)) 在上述代码中,我们使用了NumPy库来创建一个2x3的浮点型变换矩阵M,并将其传递给cv2.warpAffine()函数,该函数会将图像img按照定义的方式进行平移,并生成一个新的图像dst。最后,我们可以通过cv2.imshow()函数显示平移后的图像。 除了平移之外,Opencv还提供了其他的图像变换操作,比如缩放。缩放可以按照指定的宽度和高度来调整图像的大小,也可以按照比例来进行缩放。通过cv2.resize()函数可以实现缩放操作。在代码中,我们可以使用下面的方式来进行缩放操作: import cv2 img = cv2.imread('drawing.jpg') # 按照指定的宽度、高度缩放图片 res = cv2.resize(img, (width, height)) # 按照比例缩放图片 res2 = cv2.resize(img, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) 在上面的代码中,我们首先使用cv2.imread()函数读取图像,并将其存储在变量img中。然后,我们可以使用cv2.resize()函数来调整图像的大小。其中,如果我们指定了宽度和高度,那么图像将按照这些指定的大小进行缩放;如果我们指定了fx和fy的比例因子,那么图像将按照这些比例进行缩放。最后,我们可以使用cv2.imshow()函数来显示缩放后的图像。 总结起来,Opencv-python提供了多种图像变换操作,包括平移、缩放等。通过使用相应的函数和变换矩阵,我们可以实现对图像的各种变换操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [opencv-python 详解图像的几何变换缩放、平移、旋转、翻转](https://blog.csdn.net/RayChiu757374816/article/details/120036004)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值