这一节继续上面的内容。
轮廓近似是用更少的点组成轮廓的方法,特别是在已知轮廓不规则的情况下,用他来近似。新轮廓的点数由我们设定的精确度来确定。具体使用的是Douglas—Peucker算法。这里的效果是cv2.areLength()函数和cv2.approxPolyDP()函数。
cv2.approxPolyDP(curve, epsilon, closed, approxCurve=None)
第一个参数是图象的轮廓;第二个参数是精度;最后一个参数显示图像是否闭合。不得不说opencv虽然是一个开源的,但是里面的函数越来越像是黑箱的,说实话Douglas—Peucker算法我没细看。这种东西还是等编程能力上去了在看吧。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('C:/Users/dell/Desktop/u12.jpg')
imgray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh=cv2.threshold(imgray,127,255,0)
image,coutours,hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt=coutours[1]
epsilon=0.001*cv2.arcLength(cnt,True)
approx=cv2.approxPolyDP(cnt,epsilon,True)
im=cv2.drawContours(img,approx,-1,(0,0,255),5)
cv2.imshow('image',im)
cv2.waitKey(0)
cv2.destroyAllWindows()
一般来说epsilon设置的越小,你近似出来的点越多,也就是和原图像越接近。
凸包与轮廓近似相似,有些情况下他们给出的结果是一样的。但是凸包可以用来洁厕曲线是否有凸性缺陷,并且能纠正缺陷。
cv2.convexHull(points, hull=None, clockwise=None, returnPoints=None)
points是输入的轮廓;hull是输出,一般忽略;clockwise是方向标志true/false选择是否逆时针;returnPoints默认True,返回凸包是上点的坐标,False返回凸包上对应轮廓的点。
hull=cv2.convexHull(cnt)
把相应的位置换一下就好了,话说达到文档的效果,我现在还没搞懂,原理都是画点连线啊。
主要用的是线面的函数返回True/False.
cv2.isContourConvex(contour)
输入的擦书是轮廓。
一般有两类边界矩形:直边界和旋转边界。
直边界用到的函数是cv2.boundingRect()
cv2.boundingRect(points)
points是输入的轮廓。他的输出有四个值,左上角的坐标和长宽
x,y,w,h=cv2.boundingRect(cnt)
img=cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),5)
接下来是旋转矩形了,主要函数是cv2.minAreaRect()和cv2.boxpoint(),第一个函数返回左上顶点的坐标和长宽,还有矩阵旋转的角度,多用要用到第二个函数吧四个点都求出来。大家看看例子好好体会吧。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('C:/Users/dell/Desktop/u12.jpg')
imgray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh=cv2.threshold(imgray,127,255,0)
image,coutours,hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt=coutours[1]
rect=cv2.minAreaRect(cnt)
box=np.int0(cv2.boxPoints(rect))
img=cv2.drawContours(img,[box],0,(0,0,255),5)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
因为我选的样本图的关系,两种函数求出来的结果差不多,所以我也就不放图了。
这里用到的函数是cv2.fitellipse(),然后再用之前的绘制椭圆的函数表示出来就好。
最小外接圆用到的函数是cv2.minEnclosingCircle(),这个函数可以根据轮廓返回圆心和半径的值。就看一下应用吧。
(x,y),radius=cv2.minEnclosingCircle(cnt)
center=(int(x),int(y))
radius=int(radius)
img=cv2.circle(img,center,radius,(0,0,255),5)
这里注意的是数据类型的转化。这一节函数的样式都差不多,我就不说具体细节了,按照这种样子写程序,应该差不了多少。
ellipse=cv2.fitEllipse(cnt)
img=cv2.ellipse(img,ellipse,(0,0,255),5)
不传图片了,老是失败,大家自己体会吧。
说白了就是画一条符合图象趋势的直线。这个函数相对复杂一点,我接下来就详细说明一下。
cv2.fitLine(points, distType, param, reps, aeps, line=None)
第一个参数是轮廓;第二个参数是拟合算法dist_type=CV_DIST_L2 (L2): ρ(r)=r2/2 (最简单和最快的最小二乘法)
dist_type=cv2_DIST_L1 (L1): ρ(r)=r
dist_type=cv2_DIST_L12 (L1-L2): ρ(r)=2•[sqrt(1+r2/2) - 1]
dist_type=cv2_DIST_FAIR (Fair): ρ(r)=C2•[r/C - log(1 + r/C)], C=1.3998
dist_type=cv2_DIST_WELSCH (Welsch): ρ(r)=C2/2•[1 - exp(-(r/C)2)], C=2.9846
dist_type=cv2_DIST_HUBER (Huber): ρ(r)= r2/2, if r < C C•(r-C/2), otherwise; C=1.345;
第三到第五个参数分别推荐为0, 0.01, 0.01。这有点约定俗成的意思,就这样用。
至于输出内容则是两个点的横纵坐标。看下例子吧。
rows,cols=img.shape[:2]
[vx,vy,x,y]=cv2.fitLine(cnt,cv2.DIST_L2,0,0.01,0.01)
lefty=int((-x*vy/vx)+y)
righty=int(((cols-x)*vy/vx)+y)
#第一步不加任何处理的点
img=cv2.line(img,(x,y),(vx,vy),(0,0,255),2)
#文档上处理过的点
img=cv2.line(img,(cols-1,righty),(0,lefty),(0,0,255),2)
原理解释我也不懂,这个还是要看英文的文档和撸撸论文了。几天就到这了