计算轮廓时,可能不需要实际的轮廓,而仅需要一个接近于轮廓的近似多边形,Opencv中提供了多种计算轮廓近似多边形的方法。
retval = cv2.boundingRect( array )
绘制轮廓的边界矩形
x,y,w,h=cv2.boundingRect(contours[0]) # 前面一样的
cv2.rectangle(o,(x,y),(x+w,y+h),(255,255,255),2) # 这个可以绘制矩形,详细介绍就是后话了
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows() # 结果跟上面一样
retval =cv2.minAreaRect( points )
注意,返回值不满足 cv2.drawContours() 参数结构要求,必须将其转换为符合要求的结构才可以使用。
points = cv2.boxPoints(box)
这个函数可以将上面的返回值转换成符合要求的结构
o=cv2.imread('19.jpg')
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:\n",rect)
points = cv2.boxPoints(rect)
print("\n 转换后的 points:\n",points)
points = np.int64(points) #取整,np.int64=np.int0
image=cv2.drawContours(o,[points],0,(255,255,255),2)
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()
返回值 rect:
((244.51844787597656, 236.61021423339844), (74.56189727783203, 179.9214324951172), -75.54324340820312)
# 最小外接矩形的中心(x,y),(宽度,高度),旋转角度
转换后的 points:
[[322.32352 295.16934]
[148.09906 250.25209]
[166.71338 178.05109]
[340.93784 222.96834]]
center, radius = cv2.minEnclosingCircle( points )
这个通过迭代算法构造一个对象的面积最小包围圆形
o=cv2.imread('19.jpg')
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)
(x,y),radius = cv2.minEnclosingCircle(contours[0])
center = (int(x),int(y))
radius = int(radius)
cv2.circle(o,center,radius,(255,255,255),2) # 跟 matplotlib 类似吧。。
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()
retval = cv2.fitEllipse( points )
o=cv2.imread('19.jpg')
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)
ellipse = cv2.fitEllipse(contours[0])
print("ellipse=",ellipse)
cv2.ellipse(o,ellipse,(0,255,0),3)
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()
ellipse= ((242.83892822265625, 245.02655029296875), (66.35440826416016, 157.01898193359375), 90.87149810791016)
# 中心点,轴长度,旋转角度
line = cv2.fitLine( points, distType, param, reps, aeps )
o=cv2.imread('19.jpg')
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 = o.shape[:2]
[vx,vy,x,y] = cv2.fitLine(contours[0], cv2.DIST_L2,0,0.01,0.01) # 返回值是共线的归一化向量,和线上一点
lefty = int((-x*vy/vx) + y) # 说白了就是一个方向和一个点,点斜式嘛,还啥vec4f,,讲究
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()
retval, triangle = cv2.minEnclosingTriangle( points )
o=cv2.imread('19.jpg')
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)
area,trgl = cv2.minEnclosingTriangle(contours[0])
print("area=",area)
print("trgl:",trgl)
for i in range(0, 3):
cv2.line(o, tuple(trgl[i][0]), tuple(trgl[(i + 1) % 3][0]), (255,255,255), 2) # 让我是想不出来的,这些小技巧还是厉害的
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()
approxCurve = cv2.approxPolyDP( curve, epsilon, closed )
用来构造指定精度的逼近多边形曲线。
函数 cv2.apprxPolyDP() 采用 Douglas-Peucker算法(DP算法) 该算法首先从轮廓中找到距离最远的两个点,将两点相连,然后在轮廓上找一个离当前直线最远的带你,将该点与原有直线连成一个封闭的多边形,就可以得到一个三角形,然后不断重复上述过程,将新找到的距离当前多边形最远的点加入到结果中,当轮廓上所有的点到到当前多边形的距离都小于函数epsilon 参数的值,就停止。epsilon 是逼近多边形的精度信息,通常设置为多边形总长度百分比的形式。。。想起了物理老师的话,也许了解后感觉很简单,但当时我们就不会想到还可以这么做。。。
o=cv2.imread('19.jpg')
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)
adp = o.copy()
epsilon = 0.1*cv2.arcLength(contours[0],True) # 得到轮廓的周长,精度为0.1*周长
approx = cv2.approxPolyDP(contours[0],epsilon,True)
adp=cv2.drawContours(adp,[approx],0,(0,0,255),2)
cv2.imshow("result0.1",adp)
adp = o.copy()
epsilon = 0.02*cv2.arcLength(contours[0],True) # 精度为0.02*周长
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()