opencv入门:轮廓拟合

轮廓拟合

计算轮廓时,可能不需要实际的轮廓,而仅需要一个接近于轮廓的近似多边形,Opencv中提供了多种计算轮廓近似多边形的方法。

矩形包围框

retval = cv2.boundingRect( array ) 绘制轮廓的边界矩形

  • 返回值 retval 表示返回的矩形边界左上角顶点的坐标值及矩形边界的宽度和高度。
  • array可以是灰度图或轮廓
  • 还可以是有四个返回值的形式,x,y,w,h = cv2.boundingRect( array ) 返回的四个值分别对应 矩形边界左上角顶点的x,y坐标,矩形边界x,y方向的长度。retval 就是这四个的元组形式。
    opencv入门:轮廓拟合_第1张图片
    注意,drawContours() 的 contours 参数要是一个列表的形式,我很想知道轮廓像素点为啥是 n-1-2 这种结构数组,,,
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 )

  • 返回值表示返回的矩阵特征信息,结构是(最小外接矩形的中心(x,y),(宽度,高度),旋转角度)。
  • points 是轮廓

注意,返回值不满足 cv2.drawContours() 参数结构要求,必须将其转换为符合要求的结构才可以使用。
points = cv2.boxPoints(box) 这个函数可以将上面的返回值转换成符合要求的结构

  • 返回值 points,是能够用于函数 cv2.drawContours()参数的轮廓点。
  • 参数 box 是函数 cv2.minAreaRect()返回值的类型的值。
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]]

opencv入门:轮廓拟合_第2张图片

最小包围圆形

center, radius = cv2.minEnclosingCircle( points ) 这个通过迭代算法构造一个对象的面积最小包围圆形

  • center 圆形,radius 半径,参数是轮廓
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()

opencv入门:轮廓拟合_第3张图片

最优拟合椭圆

retval = cv2.fitEllipse( points )

  • 返回值是 RotatedRect 类型的值,这个是拟合椭圆的外界矩形,包含外接矩形的质心,宽,高,旋转角度等参数信息,这些信息与椭圆的中心点,轴长度,旋转角度等信息吻合
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)
# 中心点,轴长度,旋转角度

opencv入门:轮廓拟合_第4张图片

最优拟合直线

line = cv2.fitLine( points, distType, param, reps, aeps )

  • line 为返回值,是返回的最优拟合直线参数
  • points轮廓
  • distType 距离信息,拟合直线时,要使输入点到拟合直线的距离之和最小
    opencv入门:轮廓拟合_第5张图片
  • param 距离参数,0就好,自动选择最好的
  • reps ,aeps 用于表示拟合直线所需要的径向,角度 精度,通常设置为0.01
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()

在这里插入图片描述

opencv入门:轮廓拟合_第6张图片
这里讲的肯定粗糙,详细的看看大佬的文章吧脑补链接

最小外包三角形

retval, triangle = cv2.minEnclosingTriangle( points )

  • retval 最小外包三角形的面积。 triangle 最小外包三角形的三个顶点集
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()

opencv入门:轮廓拟合_第7张图片

逼近多边形

approxCurve = cv2.approxPolyDP( curve, epsilon, closed ) 用来构造指定精度的逼近多边形曲线。

  • approxCurve 为逼近多边形的点集
  • curve 轮廓
  • epsilon 精度,原始轮廓的边界的与逼近多边形边界之间的最大距离
  • closed 布尔值,是否封闭

函数 cv2.apprxPolyDP() 采用 Douglas-Peucker算法(DP算法) 该算法首先从轮廓中找到距离最远的两个点,将两点相连,然后在轮廓上找一个离当前直线最远的带你,将该点与原有直线连成一个封闭的多边形,就可以得到一个三角形,然后不断重复上述过程,将新找到的距离当前多边形最远的点加入到结果中,当轮廓上所有的点到到当前多边形的距离都小于函数epsilon 参数的值,就停止。epsilon 是逼近多边形的精度信息,通常设置为多边形总长度百分比的形式。。。想起了物理老师的话,也许了解后感觉很简单,但当时我们就不会想到还可以这么做。。。
opencv入门:轮廓拟合_第8张图片

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()

opencv入门:轮廓拟合_第9张图片
如果有多个轮廓注意索引啊。。

你可能感兴趣的:(opencv从入门到放弃,opencv)