在计算轮廓时,有时仅需要一个接近轮廓的近似多边形。OpenCV提供了多种计算轮廓近似多边形的方法。
[TOC]
矩形包围框
形式一:
retval = cv2.boundingRect(array)
- retval表示返回的矩形边界的左上角顶点的坐标值及矩形边界的宽度和高度
- array为灰度图像或轮廓
形式二:
x, y, w, h = cv2.boundingRect( array )
- 矩形边界左上角顶点的x坐标
- 矩形边界左上角顶点的y坐标
- 矩形边界的x方向的长度
- 矩形边界的y方向的长度
例1:设计程序,显示函数cv2.boundingRect()
不同形式的返回值。
import cv2
import numpy as np
img = cv2.imread(r'E:\Blog\OpenCV\Process\A1.png')
# =====处理为二值图=====
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)
# cv2.RETR_LIST 对检测的轮廓不建立等级关系
# =====返回顶点及变长=====
x, y, w, h = cv2.boundingRect(contours[0])
print("顶点及长度的形式:")
print('x= ',x)
print('y= ',x)
print('w= ',w)
print('h= ',h)
# =====仅有一个返回值=====
rect = cv2.boundingRect(contours[0])
print('\n')
print('只返回一个值(元组) :')
print('rect= ',rect)
结果:
顶点及长度的形式:
x= 14
y= 14
w= 248
h= 151只返回一个值(元组) :
rect= (14, 72, 248, 151)
例2:使用cv2.drawContours()
绘制矩形包围框。
import cv2
import numpy as np
img = cv2.imread(r'E:\Blog\OpenCV\Process\A1.png')
cv2.imshow("IMG",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)
# cv2.RETR_LIST 对检测的轮廓不建立等级关系
# =====构造矩形边界=====
x, y, w, h = cv2.boundingRect(contours[0])
brcnt = np.array([[[x, y]], [[x+w, y]], [[x+w, y+h]], [[x, y+h]]])
cv2.drawContours(gray,[brcnt],-1,(255,255,255),2)
# =====显示矩形边界=====
cv2.imshow("RESULT",gray)
cv2.waitKey()
还可以使用绘制矩形的函数cv2.rectangle()
实现:
最小包围矩形框
语法:
retval = cv2.minAreaRect( curve )
retval表示返回的矩形特征信息
该值的结构是
(最小外接矩形的中心(x,y),(宽度,高度),旋转角度)
- curve是轮廓
需要注意的是,retval
的结构不符合cv2.drawContours()
的参数结构要求。需要转换:
points = cv2.boxPoints( retval )
- 这里的points是能够用于函数
cv2.drawContours()
参数的轮廓点
例:使用函数cv2.minAreaRect()
计算图像的最小包围矩阵框。
import cv2
import numpy as np
img = cv2.imread(r'E:\Blog\OpenCV\Process\A1.png')
cv2.imshow("IMG",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)
# cv2.RETR_LIST 对检测的轮廓不建立等级关系
# ====返回最小方框====
rect = cv2.minAreaRect(contours[0])
print("返回值rect:\n",rect)
# ====方框格式转换====
points = cv2.boxPoints(rect)
print('转换后的points:\n',points)
points = np.int0(points) #取整
cv2.drawContours(img,[points],0,(255,255,255),2)
cv2.imshow("RESULT",img)
cv2.waitKey()
运行结果:
返回值rect:
((137.5, 138.5), (141.55892944335938, 244.25555419921875), 77.6609115600586)
转换后的points:
[[ 3.068015 95.453865]
[241.68129 43.25721 ]
[271.93198 181.54614 ]
[ 33.31871 233.7428 ]]
最小包围圆形
语法:
center, radius = cv2.minEnclosingCircle( points )
- center返回的是圆心
- radius返回的是半径
- points是轮廓
例:使用函数cv2.minEnclosingCircle()
计算图像的最小包围矩阵框。
import cv2
import numpy as np
img = cv2.imread(r'E:\Blog\OpenCV\Process\A4.png')
cv2.imshow("IMG",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)
# cv2.RETR_LIST 对检测的轮廓不建立等级关系
# ====返回最小包围圈====
(x,y),radius = cv2.minEnclosingCircle(contours[0])
center = (int(x),int(y))
radius = int(radius)
cv2.circle(img,center,radius,(255,255,255),2)
cv2.imshow("RESULT",img)
cv2.waitKey()
最优拟合椭圆
函数cv2.fitEllipse( )
可以用来构造最优拟合椭圆。语法:
retval = cv2.fitEllipse( points )
- points为轮廓
- retval值包含中心点、轴长度、椭圆的旋转角度
例:使用函数cv2.fitEllipse( )
构造最优拟合椭圆。
import cv2
import numpy as np
img = cv2.imread(r'E:\Blog\OpenCV\Process\A4.png')
cv2.imshow("IMG",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)
# cv2.RETR_LIST 对检测的轮廓不建立等级关系
# ====返回最小包围椭圆====
ellipse = cv2.fitEllipse(contours[0])
print("ellipse = \n",ellipse)
cv2.ellipse(img,ellipse,(255,0,0),3)
cv2.imshow("RESULT",img)
cv2.waitKey()
结果:
ellipse =
((259.45526123046875, 151.544189453125), (88.27090454101562, 150.53924560546875), 87.91172790527344)
- (259.45526123046875, 151.544189453125)是椭圆的中心
- (88.27090454101562, 150.53924560546875)是椭圆的轴长度
- 87.91172790527344是椭圆的旋转
最优直线拟合
在OpenCV中,函数cv2.fitLine()
用来构造最优拟合直线。
语法:
line = cv2.fitLine( points, distType, param, reps, aeps )
- points:轮廓
- distType:距离类型。拟合直线时,要使输入点到拟合直线的距离最小,具体参数值如下表所示
- param:距离参数,与所选的距离类型有关。当此参数被设置为0时,该函数会自动选择最优值
- reps:用于表示拟合直线所需要的径向精度,通常为0.01
- aeps:用于表示拟合直线所需要的角度精度,通常为0.01
例:使用函数cv2.fitLine()
构造最优拟合直线。
from turtle import right
import cv2
import numpy as np
img = cv2.imread(r'E:\Blog\OpenCV\Process\A4.png')
cv2.imshow("IMG",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)
# cv2.RETR_LIST 对检测的轮廓不建立等级关系
# ====返回最优直线====
rows, cols = img.shape[:2]
[vx, vy, x, y] = cv2.fitLine(contours[0], cv2.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x*vy/vx)+y)
righty = int(((cols-x)*vy/vx)+y)
# ====绘制最优直线====
cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
cv2.imshow("RESULT",img)
cv2.waitKey()
# 关于绘制的函数会在后面具体细说,此处了解即可。
最小外包三角形
语法:
retval, triangle = cv2.minEnvlosingTriangle(points)
- retval:最小外包三角形的面积
- triangle:最小外包三角形的三个顶点集
- points:轮廓
例:编写代码,构造最小外包三角形。
import cv2
img = cv2.imread(r'E:\Blog\OpenCV\Process\A5.png')
cv2.imshow("IMG",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)
# cv2.RETR_LIST 对检测的轮廓不建立等级关系
# ====返回外包三角形====
area, trg1 = cv2.minEnclosingTriangle(contours[0])
print("AREA=\n",area)
print("TRG1=\n",trg1)
# ====绘制外包三角形,原理是绘制三个线段===
for i in range(0,3):
cv2.line(img, tuple(trg1[i][0]), tuple(trg1[(i+1)%3][0]),(255,0,255),2)
cv2.imshow("RESULT",img)
cv2.waitKey()
此处代码有问题,报错,网上查了查,说是因为不能是浮点型,但是没成功解决,此处留个念想。
OpenCV(4.5.5) -1: error: (-5:Bad argument) in function 'line' > Overload resolution failed: > - Can't parse 'pt1'. Sequence item with index 0 has a wrong type > - Can't parse 'pt1'. Sequence item with index 0 has a wrong type
逼近多边形
语法:
approxCurve = cv2.approxPolyDP( curve, epsilon, closed )
- 用来构造指定精度的逼近多边形曲线
- curve是轮廓
- epsilon为精度,原始轮廓的边界点与逼近多边形边界之间的最大距离
- closed是布尔类型的值,为True时,逼近多边形是封闭的,否则不是封闭的。
例:构造不同精度的逼近多边形。
import cv2
img = cv2.imread(r'E:\Blog\OpenCV\Process\A5.png')
cv2.imshow("IMG",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)
# cv2.RETR_LIST 对检测的轮廓不建立等级关系
# ===== epsilon = 0.1 * 周长 =======
adp = img.copy()
epsilon = 0.1*cv2.arcLength(contours[0],True)
approx = cv2.approxPolyDP(contours[0],epsilon,True)
adp = cv2.drawContours(adp,[approx],0,(0,0,255),2)
cv2.imshow("result0.1",adp)
# ===== epsilon = 0.09 * 周长 =======
adp = img.copy()
epsilon = 0.09*cv2.arcLength(contours[0],True)
approx = cv2.approxPolyDP(contours[0],epsilon,True)
adp = cv2.drawContours(adp,[approx],0,(0,0,255),2)
cv2.imshow("result0.09",adp)
# ===== epsilon = 0.02 * 周长 =======
adp = img.copy()
epsilon = 0.02*cv2.arcLength(contours[0],True)
approx = cv2.approxPolyDP(contours[0],epsilon,True)
adp = cv2.drawContours(adp,[approx],0,(0,0,255),2)
cv2.imshow("result0.02",adp)
cv2.waitKey()