OpenCV图像处理应用(面向Python)之图像轮廓

Posted OpenCV小课堂

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV图像处理应用(面向Python)之图像轮廓相关的知识,希望对你有一定的参考价值。

OpenCV图像处理应用(面向Python)

欢迎来到梁老湿课堂

版权声明:
作者:OpenCV小课堂
导师:Fu Xianjun
本文版权归作者导师共有,欢迎转载,但未经作者同意必须在文章页面注明来源及原作者或原文链接,否则保留追究法律责任的权利。

1.图像轮廓基本概念

边缘检测虽然能够检测出边缘,但边缘是不连续的,检测到的边缘并不是一个整体。图像轮廓是指将边缘连接起来形成的一个整体,用于后续的计算。图像轮廓是图像中非常重要的一个特征信息,通过对图像轮廓的操作,我们能够获取目标图像的大小位置方向等信息。
轮廓是一些列相连的点组成的曲线,代表了物体的基本外形,相对于边缘,轮廓是连续的,边缘并不全是连续的。
重要的是逻辑思维:1.导入相对应所需要的包;2.读取要处理的原始图像;3进行二值化,阈值与平滑处理,如果没有学过可以查看往期教程;4.边缘检测,图像梯度与Canny边缘检测;5.轮廓查找绘制。

2.轮廓查找与绘制

2.1 OpenCV提供了 cv2.findContours()函数,实现图像轮廓的查找:

contoours,hierarchy=cv2.findContours(img,mode,method)

1.img: 输入原始图。8位单通道。
2.contours: 返回的轮廓,例如contours[i]表示第i个轮廓。
3.hierarchy: 图像的拓扑信息(轮廓层次)。
4.mode: 轮廓检 索模式,决定了轮廓的提取方式。
4.1 cv2.RETR_EXTERNAL 只检测外轮廓
4.2 cv2.RETR_LIST检测的轮廓不建立等级关系
4.3 cv2.RETR_CCOMP建立两个等级的轮廓
4.4 cv2.RETR_TREE建立一个等级树结构的轮廓
5.method: 轮廓的近似方法,决定了如何表达轮廓。
5.1 cv2.CHAIN_APPROX_NONE存储所有的轮廓点
5.2 cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息。

寻找轮廓的操作一般用于二值化图,所以通常会使用阈值分割或Canny边缘检测先得到二值图。

显示下面这张图有几个轮廓并且绘制出轮廓

显示有几个轮廓以及轮廓大小

import cv2
import numpy as np
img = cv2.imread('qwer.png')    #读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
ret, binary = cv2.threshold(gray,220,255,cv2.THRESH_BINARY) #转为二值图
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,\\
                                       cv2.CHAIN_APPROX_NONE) #寻找轮廓
n=len(contours)       #轮廓个数
print(n)
print(len(contours[0]))       #轮廓0像素数目
print(len(contours[1]))       #轮廓1像素数目
print(len(contours[2]))       #轮廓2像素数目
#显示有几个轮廓并且显示轮廓大小详情见图1

图1:

2.2 OpenCV提供了 cv2.drawContours()函数,实现图像轮廓的绘制:

img=cv2.drawContours(img, contours, contourIdx, color, thickness=None,\\
 lineType=None, hierarchy=None, maxLevel=None, offset=None)

1.img: 待绘制轮廓的图像。
2.contours: 需要绘制的轮廓。
3.contourIdx: 需要绘制的边缘索引,如果为-1,则表示绘制全部轮廓。
4.color: 绘制的颜色,opencv中使用的是BGR格式,不是我们平时说的RGB。色彩空间转换。
5.thickness: 可选参数,表示绘制轮廓时使用画笔粗细,如果为-1,则表示填充,画出实心轮廓。
6.line Type: 可选参数,表示绘制轮廓时所使用的线型。
7.hierarchy: 对应函数cv2.findContours()所输出的层次信息。
8.maxLevel: 绘制轮廓层次的深度。
9.offset: 偏移参数,该参数使轮廓偏移到不同的位置展示出来。
例如我们要在一张图片中用绿色画出重点我们可以这么写

img=cv2.drawContours(img,contours,-1,(0,255,0),5)
#(0,255,0)表示颜色为绿色;5表示的是线条粗细(若为-1,则会将轮廓内部进行填充);img表示是在img这张图上画;-1表示的是画出所有轮廓

绘制所有轮廓

import cv2
import numpy as np
img = cv2.imread('qwer.png')    #读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
ret, binary = cv2.threshold(gray,220,255,cv2.THRESH_BINARY) #转为二值图
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,\\
                                       cv2.CHAIN_APPROX_NONE) #寻找轮廓
cv2.imshow("img",img) #显示原图像
img2 = cv2.drawContours(img,contours,-1,(0,255,0),5)  #绘制轮廓,1表示绘制第几个轮廓
cv2.imshow("contours",img2)   #显示轮廓
cv2.waitKey()
cv2.destroyAllWindows()
#详情见图2效果图

图2

显示图像边缘信息

import cv2
import numpy as np
img = cv2.imread('qwer.png')    #读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
ret, binary = cv2.threshold(gray,220,255,cv2.THRESH_BINARY) #转为二值图
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,\\
                                       cv2.CHAIN_APPROX_NONE) #寻找轮廓
n=len(contours)       #轮廓个数
contoursImg=[]
for i in range(n):
    temp=np.zeros(img.shape,np.uint8) #生成黑背景
    contoursImg.append(temp)
    contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,(0,255,0), 3)  #绘制轮廓
    cv2.imshow("contours[" + str(i)+"]",contoursImg[i])   #显示轮廓
cv2.waitKey()
cv2.destroyAllWindows()

一个一个画出图像中的轮廓边缘
图3

开打开打

#实战演练
import cv2
import numpy as np
img = cv2.imread('hmbb.png')
cv2.imshow("img",img)   #显示原图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)      #转为灰度图
ret, binary = cv2.threshold(gray,200,255,cv2.THRESH_BINARY_INV)  #转为二值图
cv2.imshow("binary" ,binary)        #显示二值化结果
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)#寻找轮廓
mask=np.zeros(img.shape,np.uint8)  #生成黑背景,即全为0
mask=cv2.drawContours(mask,contours,-1,(255,255,255),-1)  #绘制轮廓,形成掩膜
cv2.imshow("mask" ,mask)        #显示掩膜
result=cv2.bitwise_and(img,mask)   #按位与操作,得到掩膜区域
cv2.imshow("result" ,result)     #显示图像中提取掩膜区域
cv2.waitKey()
cv2.destroyAllWindows()
#详情看效果图4

图4

3.计算 轮廓的面积及长度

3.1 矩特征,OpenCV提供了cv2.moments()函数来进行实现:
比较两个轮廓最简单的方法是比较二者的轮廓矩。轮廓矩代表了一个轮廓、一幅图像、一组点集的全局特征。矩信息包含了对应对象不同类型的几何特征,例如大小位置角度形状等。矩特征被广泛地应用在模式识别、图像识别等方面。

retval=cv2.moments(array[,binaryImage])

1. array: 可以是点集,也可以是灰度图像或者二值图像。
2. binaryImage: 当为True时,array内所有的非零值都会被处理为1。
使用上面函数提取出图5的特征
图5

import cv2
import numpy as np
img = cv2.imread('hmbb.png')    #读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
ret, binary = cv2.threshold(gray,200,255,cv2.THRESH_BINARY) #转为二值图
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,\\
                                       cv2.CHAIN_APPROX_NONE) #寻找轮廓
n=len(contours)       #轮廓个数
contoursImg=[]
for i in range(n):
    temp=np.zeros(img.shape,np.uint8) #生成黑背景
    contoursImg.append(temp)
    contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,(255,255,255), 3)  #绘制轮廓
    cv2.imshow("contours[" + str(i)+"]",contoursImg[i])   #显示轮廓
print("计算图像的矩特征:")
for i in range(n):
    moment=cv2.moments(contours[i])
    print(f"轮廓i的矩:\\nmoment")
cv2.waitKey()
cv2.destroyAllWindows()

以下三张图就是图5的所有轮廓



这张图为每个轮廓矩的大小

3.2 图像轮廓的面积计算,OpenCV提供了cv2.contourArea()函数来进行实现:
1.contour : 轮廓。
2.oriented: 布尔值,当为True时,表示顺时针或逆时针计算。

计算轮廓面积

import cv2
import numpy as np
img = cv2.imread('qwer.png')    #读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
ret, binary = cv2.threshold(gray,220,255,cv2.THRESH_BINARY) #转为二值图
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,\\
                                       cv2.CHAIN_APPROX_NONE) #寻找轮廓
n=len(contours)       #轮廓个数
contoursImg=[]
for i in range(n):
    area = cv2.contourArea(contours[i])
    temp = np.zeros(img.shape, np.uint8)  # 生成黑背景
    contoursImg.append(temp)
    contoursImg[i] = cv2.drawContours(contoursImg[i], contours, i, (0, 255, 0), 3)  # 绘制轮廓
    cv2.imshow("contours[" + str(i) + "]", contoursImg[i])#显示轮廓
    print(f"轮廓i的面积:\\narea")
cv2.waitKey()
cv2.destroyAllWindows()

图6

显示面积小于20000的轮廓

import cv2
import numpy as np
img = cv2.imread('qwer.png')    #读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
ret, binary = cv2.threshold(gray,220,255,cv2.THRESH_BINARY) #转为二值图
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,\\
                                       cv2.CHAIN_APPROX_NONE) #寻找轮廓
n=len(contours)       #轮廓个数
contoursImg=[]
for i in range(n):
    area = cv2.contourArea(contours[i])
    temp=np.zeros(img.shape,np.uint8)
    contoursImg.append(temp)
    contoursImg[i]=cv2.drawContours(contoursImg[i],\\
                                    contours,i,(0,255,0),3)
    if area<20000:#此处为新加代码
        cv2.imshow("contours["+str(i)+"]",contoursImg[i])
        print(f"轮廓i的面积:\\narea")
cv2.waitKey()
cv2.destroyAllWindows()
#看下面效果图7

图7

3.3 .图像轮廓的长度计算,OpenCv提供了cv2.arcLength()函数来进行实现:
1. curve : 轮廓。
2. closed : 布尔值,当为True时,表示闭合。

计算论轮廓长度

后续有待补充

多练多学多坚持,我们下期再见。

以上是关于OpenCV图像处理应用(面向Python)之图像轮廓的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV图像处理应用(面向Python)之图像金字塔

OpenCV图像处理应用(面向Python)之图像轮廓

OpenCV图像处理应用(面向Python)之图像轮廓

OpenCV图像处理应用(面向Python)之图像运算

OpenCV图像处理应用(面向Python)之入门操作

OpenCV图像处理应用(面向Python)之图像轮廓