轮廓拟合
矩形包围轮廓
1,函数cv2.boundingRect()能够绘制轮廓的矩形边界
retval = cv2.boundingRect( array)
retval 表示返回矩形边界左上角顶点的坐标值及矩形边界的宽和高 , 也可以是4个返回值形式
x , y ,w ,h = cv2.boundingRect( array)
array 是灰度图像或轮廓
然后使用函数cv2.drawContours()来绘制矩形包围框
1 import cv2 2 import numpy as np 3 o = cv2.imread("cc.bmp") 4 cv2.imshow("original" , o) 5 gray = cv2.cvtColor(o , cv2.COLOR_BGR2GRAY) 6 ret , binary = cv2.threshold(gray , 127 , 255 ,cv2.THRESH_BINARY) 7 contours , hierarchy = cv2.findContours(binary , cv2.RETR_LIST , 8 cv2.CHAIN_APPROX_SIMPLE) 9 x,y,w,h = cv2.boundingRect(contours[0]) 10 brcnt = np.array([[[x,y]] ,[[x+w , y]] , [[x+w , y+h]] , [[x,y+h]]] ) 11 cv2.drawContours(o , [brcnt] , -1 ,(255,255,255) , 2) 12 cv2.imshow("result" ,o) 13 cv2.waitKey() 14 cv2.destroyAllWindows()
原图
效果图
2,使用函数cv2.boundingRect() 即cv2.rectangle()绘制矩形包围框
1 import cv2 2 import numpy as np 3 o = cv2.imread("cc.bmp") 4 gray = cv2.cvtColor(o , cv2.COLOR_BGR2GRAY) 5 ret , binary = cv2.threshold(gray , 127 , 255 ,cv2.THRESH_BINARY) 6 contours , hierarchy = cv2.findContours(binary , cv2.RETR_LIST , 7 cv2.CHAIN_APPROX_SIMPLE) 8 x,y,w,h = cv2.boundingRect(contours[0]) 9 cv2.rectangle(o , (x,y) , (x+w , y+h) ,(255,255,255) , 2) 10 cv2.imshow("result" ,o) 11 cv2.waitKey() 12 cv2.destroyAllWindows()
效果图
3。,最小包围矩形框函数cv2.minAreaRect()
该函数能绘制轮廓的最小包围矩形框,函数形式:
retval = cv2.minAreaRect( points )
返回值retval表示返回矩阵特征的信息,结构为(最小外接矩形的中心(x,y) , (宽度, 高度) , 旋转角度)
points为轮廓
返回值retval 结构不能用于函数cv2.drawContours() 参数结构要求, 需要将其转换为合适的参数结构,
即使用函数cv2.boxPoints(box)
import cv2 import numpy as np o = cv2.imread("cc.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 , cv2.RETR_LIST , cv2.CHAIN_APPROX_SIMPLE) rect = cv2.minAreaRect(contours[0]) print("rect: " , rect) points = cv2.boxPoints(rect) print(" points_back: " , points) points = np.int0(points) binary = cv2.drawContours(o , [points] , 0 ,(255,255,255) , 2) cv2.imshow("result" , o) cv2.waitKey() cv2.destroyAllWindows()
rect: ((280.3699951171875, 138.58999633789062), (154.99778747558594, 63.78103256225586), -8.130102157592773) points_back: [[208.16002 181.12 ] [199.14 117.979996] [352.57996 96.06 ] [361.59998 159.2 ]]
rect表示返回的矩形特征信息
points是一些点,时能够用作函数cv2.drawContours()参数的点
4,最小包围圆形函数cv2.minEnclosingCircle()
该函数构造一个对象的面积最小包围圆形,函数形式
center , radius = cv2.minEnclosingCircle( points)
center为最小包围圆形的中心
radius为最小包围圆形的半径
points轮廓
1 import cv2 2 o = cv2.imread("cc.bmp") 3 cv2.imshow("original" , o) 4 gray = cv2.cvtColor(o , cv2.COLOR_BGR2GRAY) 5 ret , binary = cv2.threshold(gray , 127 , 255 ,cv2.THRESH_BINARY) 6 contours , hirrarchy = cv2.findContours( binary , cv2.RETR_LIST , 7 cv2.CHAIN_APPROX_SIMPLE) 8 (x,y) , radius = cv2.minEnclosingCircle(contours[0]) 9 center = (int(x) , int(y)) 10 radius = int(radius) 11 cv2.circle(o , center , radius , (255,255,255) , 2) 12 cv2.imshow("resultl" , o) 13 cv2.waitKey() 14 cv2.destroyAllWindows()
5,最优拟合椭圆函数cv2.fitEllipse()
可以构造最优拟合椭圆, 函数形式:
retval = cv2.fitEllipse( points )
retval 是RotatedRect()类型的值,这是因为该函数返回的是 拟合椭圆的外接矩形,包含外接矩形的质心,宽, 高,旋转角度
,正好与椭圆的中心点,轴长度,旋转角度等信息吻合
1 import cv2 2 o = cv2.imread("cc.bmp") 3 gray = cv2.cvtColor( o , cv2.COLOR_BGR2GRAY) 4 ret , binary = cv2.threshold(gray , 127 , 255, cv2.THRESH_BINARY) 5 contours , hierarchy = cv2.findContours(binary , cv2.RETR_LIST , 6 cv2.CHAIN_APPROX_SIMPLE) 7 cv2.imshow("original" , o) 8 ellipse = cv2.fitEllipse(contours[0]) 9 print("ellipse=" , ellipse) 10 cv2.ellipse(o , ellipse ,(0 , 255, 0) , 3) 11 cv2.imshow("result" , o) 12 cv2.waitKey() 13 cv2.destroyAllWindows()
6,最优拟合直线 函数cv2.fitLine()
函数形式: line = cv2.fitLine( points , distType , param , reps , aeps )
line 返回的是最优拟合直线参数
points是轮廓
distType是距离类型,
param是距离参数,与算选激励类型有关, 当参数设置为0时,会自动选择最优值
reps表示拟合直线所需的径向精度,通常被设置为0.01
aeps表示拟合直线所需的角度精度,通常被设置为0.01
import cv2 o = cv2.imread("cc.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 ,cv2.RETR_LIST , cv2.CHAIN_APPROX_SIMPLE) rows , cols = binary.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(o , (cols -1 ,righty) , (0,lefty) , (0,255,0) , 2) cv2.imshow("result" , o) cv2.waitKey() cv2.destroyAllWindows()
7,最优外包三角形函数 cv2.minEnclosingTriangle()
retval , triangle = cv2.minEnclosingTreangle( points )
retval 为最小外包三角形的面积
triangle 最小外包三角形的三个顶点集
points轮廓
1 import cv2 2 o = cv2.imread("cc.bmp") 3 cv2.imshow("original" , o) 4 gray = cv2.cvtColor(o , cv2.COLOR_BGR2GRAY) 5 ret , binary = cv2.threshold(gray , 127 , 255 , cv2.THRESH_BINARY) 6 contours , hierarchy = cv2.findContours(binary , cv2.RETR_LIST , 7 cv2.CHAIN_APPROX_SIMPLE) 8 area , trgl = cv2.minEnclosingTriangle(contours[0]) 9 print("area = " , area) 10 print("trgl:" , trgl) 11 for i in range(0,3): 12 cv2.line(o , tuple(trgl[i][0]), 13 tuple(trgl[(i+1) % 3][0]) , (255,255,255) , 2) 14 cv2.imshow("result" , o) 15 cv2.waitKey() 16 cv2.destroyAllWindows()
8,逼近多边形函数cv2.approxPolyDP()
该函数用来构造指定精度的逼近多边形曲线,函数形式:
approxCurve = cv2.approxPolyDP( curve , epsilon , closed)
返回值approxCurve为逼近多边形的点集
curve为轮廓
epsilon为精度,原始轮廓的边界点与逼近多边形边界之间的最大值
colsed为布尔值该值为True,毕竟多边形是封闭的,否则多边形不封闭
该函数采用的是Douglas-Peucker算法,首先杂i轮廓上找到距离最远的两个点连接起来,然后在轮廓上找到离直线最远的点
连接之前的点形成封闭的多边形,此时为三角形,按此方式不断的迭代将找到的离多边形最远的点加入,形成新的多边形
当最远距离小于参数epsilon的值时,就停止迭代,该参数多设置为百分比形式
import cv2 o = cv2.imread("cc.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 , cv2.RETR_LIST , cv2.CHAIN_APPROX_SIMPLE) #epsilon = 0.1 * 周长 adp = o.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 = o.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.055 * 周长 adp = o.copy() epsilon = 0.055*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.055" , adp) #epsilon = 0.05 * 周长 adp = o.copy() epsilon = 0.05*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.05" , adp) #epsilon = 0.02* 周长 adp = o.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() cv2.destroyAllWindows()
epsilon = 0.1 * 周长
epsilon = 0.09 * 周长
epsilon = 0.055* 周长
epsilon = 0.05 * 周长
epsilon = 0.02 * 周长