openCV专栏(八):图像轮廓:绘制轮廓

OPENCV基础操作

提示:本专栏所用版本仅供参考,其他版本也可

版本
pythonPython 3.9.3
opencv4.5.5
matplotlib3.4.3
numpy1.19.5
QQ学习群点击加群:928357277

提问环节

1:什么是图像轮廓

答:是图像中非常重要个一个特征信息,通过对图像的检测,我们能够获得图像的大小,位置,方向等。

2:图像轮廓和边缘检测的区别

答:图像轮廓可以检测到完整的,连续的边缘信息,同时还能获得图像的各种特征信息,如大小,位置,方向等

3:如何进行图像检测

答:为了检测完整的,连续的边缘信息,openCv提供了findContours()轮廓查找函数,和drawContours()轮廓绘制函数

查找轮廓

c,h = cv2.findContours(image,mode,method)
注意:在opencv4之前该函数有三个返回值:image,c,h

返回值为轮廓信息c,和图像的拓扑信息h
参数Mode为轮廓的检索模式
参数method为轮廓的近似方法

参数mode表

参数说明
cv2.RETR_LIST检测到的轮廓不建立等级关系
cv2.RETR_EXTERNAL检测所有外轮廓
cv2.RETR_CCOMP检索素有轮廓并组织为两级层次结构
cv2.RETR_TREE建立等级数结构的轮廓

参数method表

参数说明
cv2.CHAIN_APPROX_NONE存储所有轮廓点,两点位置差不超过1
cv2.CHAIN_APPROX_SIMPLE只保留该方向的终点坐标
cv2.CHAIN_APPROX_TC89_L1ten_chinl chain近似算法风格
cv2.CHAIN_APPROX_TC89_KCOSten_chinl chain近似算法风格

代码演示

import matplotlib.pyplot as plt #导入模块
import cv2
import numpy as np

轮廓获取

img  = cv2.imread('1.jpg',0)

#对图像进行二值化处理
r,img = cv2.threshold(img,180,255,cv2.THRESH_BINARY)
# print(data.shape)
#返回轮廓信息,拓扑信息,检测轮廓的模式为只检测外轮廓,方式为存储所有的轮廓蒂娜
c,h = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)


a = len(c)
print(a)#打印轮廓数量
print(c[a-1].shape)#打印最后一个轮廓的信息

for X in range(a):#打印每个轮廓的拓扑信息
    """Next , Previous , First_Child , Parent"""
    print(X,":",h[X])

运行结果:

07\exercise> python .\opencv3.py
轮廓数量 1
(2300, 1, 2)
0 : [[-1 -1 -1 -1]]

第一行为轮廓数量,第二行为当前轮廓信息,第三行为当前的轮廓拓扑信息

轮廓绘制

image = cv2.drawContours(image,contours,contourIdx,color[,thickness[,lineType[,hierachy[,maxlevel[,offset]]]]])

参数依次为:原始图像,轮廓信息,边缘索引,绘制颜色,画笔粗细,线形,层次信息,轮廓深度,偏移位置

参数依次为:原始图像,轮廓信息,边缘索引,绘制颜色,画笔粗细,线形,层次信息,轮廓深度,偏移位置

代码演示

import matplotlib.pyplot as plt #导入模块
import cv2
import numpy as np

img  = cv2.imread('1.jpg',0)

#对图像进行二值化处理
r,img = cv2.threshold(img,180,255,cv2.THRESH_BINARY_INV)
# print(data.shape)
#返回轮廓信息,拓扑信息,检测轮廓的模式为只检测外轮廓,方式为存储所有的轮廓蒂娜
c,h = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)

image = cv2.drawContours(img,c,-1,(255,255,255),-1)#绘制实心轮廓,提取前景色
cv2.imshow('img',image)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果:
在这里插入图片描述

轮廓矩特征

轮廓矩特征:moments()
语法格式:cv2.moments(array[,binaryImage])
参数为:点集array,图像二值化处理标志
返回值为轮廓矩:

轮廓矩包括:
1、空间矩(零阶矩(m00),一阶矩(m10,m01),二阶矩(m20,m11,m02),三阶矩)
2、中心矩(二阶中心矩(mu20,mu11,mu02),三阶中心矩)
3、归一化中心矩(二阶Hu矩(nu20,nu11,nu02),三阶Hu矩)
各矩阵都有自己独特的用法,比如说m00矩可以用来比较面积大小,归一化中心矩可以描述平移,缩放不变性。

使用零阶矩计算轮廓面积

import matplotlib.pyplot as plt #导入模块
import cv2
import numpy as np
img  = cv2.imread('1.jpg',0)

#对图像进行二值化处理
r,img = cv2.threshold(img,180,255,cv2.THRESH_BINARY_INV)
# print(data.shape)
#返回轮廓信息,拓扑信息,检测轮廓的模式为只检测外轮廓,方式为存储所有的轮廓蒂娜
c,h = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)

#计算轮廓的面积
a = len(c)
for X in range(a):
    print(X,"的面积:%d" %cv2.moments(c[X])['m00'])

image = cv2.drawContours(img,c,-1,(255,255,255),-1)#绘制实心轮廓,提取前景色
cv2.imshow('img',image)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果:

0 的面积:1914
1 的面积:2455
2 的面积:3662
3 的面积:2882
4 的面积:3104
5 的面积:6100
6 的面积:23765
7 的面积:23287
8 的面积:9
9 的面积:23680

使用函数计算轮廓周长面积

当然,我们还可以通过openCv提供的其他函数来进行面积计算

计算面积:retval = cv2.contourAera(contour[,oriented])
计算长度:retcal = cv2.arcLength(contour,colsed)

Hu矩:

HU矩是归一化中心矩的线性组合。Hu矩阵在图像旋转,缩放,平移等操作后,仍能保持矩阵的不变特性,经常被用来识别图像的特征
在OpenCV中使用HuMomente()得到Hu矩,返回值为monments()函数的返回值作为参数,返回7个Hu矩值
== hu = cv2.HuMoments(m) ==
关于得到7个矩值的计算方式,有想了解的可以自行百度

基于Hu矩的形状匹配

函数支持:cv2.matchShapes(contour1,contour2,method,parameter)
参数为:第一个轮廓或者灰度图像,第二个轮廓或者灰度图像,比较方法,扩展参数(扩展参数仅支持opencv4.1.0及之后版本)

图表:比较方法参数

在这里插入图片描述

计算俩个图像不同的匹配度


img1 = cv2.imread('1.jpg',cv2.IMREAD_GRAYSCALE)

#二值化处理
rt,img1 = cv2.threshold(img1,150,255,cv2.THRESH_BINARY)

#做出第二章图片
img2 = img1

c1,h2 = cv2.findContours(img1,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
c2,h2 = cv2.findContours(img2,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) 

c11 = c1[0]
c22 = c2[0]
#形状匹配
r1 = cv2.matchShapes(c11,c22,cv2.CONTOURS_MATCH_I1,0.0)

print("形状匹配度 ", r1)

运行结果:

形状匹配度  0.0

轮廓拟合

为了方便计算得到一个接近于轮廓的多边形,我们需要对轮廓进行轮廓拟合操作

绘制矩形包围框

函数:retval = cv2.boundingRect(array)
返回值为边界左上角顶点的坐标值及矩形边界的宽度和高度,参数为灰度图像或者轮廓
还可以写作四个返回值的形式:x,y,w,h = cv2.boundingRect

代码:

import matplotlib.pyplot as plt #导入模块
import cv2
import numpy as np

img = cv2.imread('1.jpg')

imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
r,imgGray = cv2.threshold(imgGray,180,255,cv2.THRESH_BINARY_INV)
c,h = cv2.findContours(imgGray,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#构造矩形边框
print(len(c))
x,y,w,h = cv2.boundingRect(c[10])
#矩形边框点集
rect = np.array([[[x,y]],[[x+w,y]],[[x+w,y+h]],[[x,y+h]]])
#绘制
# cv2.rectangle(imgGray,(x,y),(x+w,y+h),(255,255,255),2)
cv2.drawContours(imgGray,[rect],-1,(255,255,255),2)
cv2.imshow('imgGray',imgGray)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果:

在这里插入图片描述

绘制最小包围矩形框

retval = minAreaRect(points)
返回值为矩形特征信息(最小外接矩形的中心,(宽度,高度),旋转角度)
参数为轮廓

代码:

import matplotlib.pyplot as plt #导入模块
import cv2
import numpy as np

img = cv2.imread('1.jpg')

imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
r,imgGray = cv2.threshold(imgGray,180,255,cv2.THRESH_BINARY_INV)
c,h = cv2.findContours(imgGray,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#构造矩形边框
print(len(c))
#矩形边框点集
rect = cv2.minAreaRect(c[10])
points = cv2.boxPoints(rect)#返回值转换函数
points = np.int0(points)# 结果取整数
#绘制
# cv2.rectangle(imgGray,(x,y),(x+w,y+h),(255,255,255),2)
cv2.drawContours(imgGray,[points],-1,(255,255,255),2)
cv2.imshow('imgGray',imgGray)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果:
在这里插入图片描述

绘制最小包围圆形

center,radius = cv2.minEnclosingCircle(points)
返回值为圆形中心,圆形半径

绘制最优拟合圆

retval = cv2.fitEllipse(points)
返回值为RotateRect类型的值,包含外接矩形的质心、宽、高、旋转角度等参数信息,对应椭圆的中心点,轴长度,旋转角度
参数为轮廓信息
使用代码:

#使用下面代码代码替换绘制部分即可
 ellipse = cv2.fitEllipse(c[10])
 cv2.ellipse(img,ellipse,(1,255,1),3)

绘制最优拟合直线

line = cv2.fitLine(points,disType,param,reps,aeps)
返回值为最优拟合直线参数
参数为轮廓,距离类型,距离参数,用于拟合直线所需要的的径向精度【0.01】,用于拟合直线所需要的的角度精度【0.01】

图表:距离类型参数

在这里插入图片描述

使用代码:

import matplotlib.pyplot as plt #导入模块
import cv2
import numpy as np

img = cv2.imread('1.jpg')

imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
r,imgGray = cv2.threshold(imgGray,180,255,cv2.THRESH_BINARY_INV)
c,h = cv2.findContours(imgGray,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#构造矩形边框

print(len(c))
#矩形边框点集
rows,cols = imgGray.shape[:2]
[vx,vy,x,y] = cv2.fitLine(c[10],cv2.DIST_L2,0,0.01,0.01)

#计算左右距离
lefty = int((-x*vy/vx)+y)
righty = int(((cols-x)*vy/vx)+y)

#绘制直线
cv2.line(imgGray,(cols-1,righty),(0,lefty),(0,255,0),2)

cv2.imshow('imgGray',imgGray)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果:
在这里插入图片描述

绘制最小外包三角形

retval,triangle = minEnclosingTriangle(points)
返回值为:最小外包三角形的面积retval、最小外包三角形的三个顶点集triangle
参数为轮廓信息

使用代码:

import matplotlib.pyplot as plt #导入模块
import cv2
import numpy as np

img = cv2.imread('1.jpg')

imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
r,imgGray = cv2.threshold(imgGray,180,255,cv2.THRESH_BINARY_INV)
c,h = cv2.findContours(imgGray,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#构造矩形边框

print(len(c))
#获取三角形信息,最小外包面积和三个顶点集
area,trgl = cv2.minEnclosingTriangle(c[10])

#绘制三角形
for i in range(3):
    cv2.line(imgGray,tuple([int(trgl[i][0][0]),int(trgl[i][0][1])]),
            tuple([int(trgl[(i + 1 )% 3][0][0]),int(trgl[(i + 1 )% 3][0][1])]),(255,255,255),2)

#显示图片
cv2.imshow('imgGray',imgGray)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果:
在这里插入图片描述

绘制逼近多边形

approxCurve = cv2.approxPolyDp(curve,epsilon,colsed)
返回值为逼近多边形的点集
参数为:轮廓curve、精度epsilon[原始轮廓的边界点与逼近多边形边界之间的最大距离]、是否封闭标志colsed

使用代码:

import matplotlib.pyplot as plt #导入模块
import cv2
import numpy as np

img = cv2.imread('1.jpg')

imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
r,imgGray = cv2.threshold(imgGray,180,255,cv2.THRESH_BINARY_INV)
c,h = cv2.findContours(imgGray,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#构造矩形边框

print(len(c))
# 设置epsilon = 0.1为周长
imgGrayL  = imgGray.copy()#复制一个矩阵
epslion = 0.1*cv2.arcLength(c[10],True)
approx = cv2.approxPolyDP(c[10],epslion,True)
imgGrayL = cv2.drawContours(imgGrayL,[approx],0,(0,255,255),2)
# 设置epsilon = 0.05为周长
imgGrayL2  = imgGray.copy()#复制一个矩阵
epslion = 0.05*cv2.arcLength(c[10],True)
approx = cv2.approxPolyDP(c[10],epslion,True)
imgGrayL2 = cv2.drawContours(imgGrayL2,[approx],0,(0,0,255),2)

imgcom = np.hstack((imgGrayL,imgGrayL2))
#显示图片
cv2.imshow('imgGrayL',imgcom)
cv2.waitKey()
cv2.destroyAllWindows()

运行结果:
在这里插入图片描述
如果你也喜欢编程,点击群号加入我们的QQ大家庭 928357277吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

亿只萌新

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

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

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

打赏作者

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

抵扣说明:

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

余额充值