1. 凸包
凸缺陷可以用来处理手势识别问题
Hull = cv2.convexHull(points,clockwise,returnPoints)
points:轮廓
clockwise:True:凸包按顺时针方向排列;False:凸包按逆时针排列
returnPoints:True:返回凸包角点(x,y)坐标 ;False:返回轮廓中凸包角点的索引
import cv2
img=cv2.imread("D:/part12/part12_8.bmp")
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)
hull1=cv2.convexHull(contours[0])
print("默认是False,hull的值",hull1)
hull2=cv2.convexHull(contours[0],returnPoints=False)
print("是True,hull的值",hull2)
默认是False,hull的值 [[[256 28]]
[[260 29]]
[[319 45]]
[[392 91]]
...
是True,hull的值 [[526]
[524]
[428]
[347]
...
绘制凸包
import cv2
img=cv2.imread("D:/part12/part12_8.bmp")
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)
hull=cv2.convexHull(contours[0])
cv2.polylines(img,[hull],True,(0,255,0),2)
cv2.imshow("img",img)
cv2.waitKey(0)
cv2.destroyWindow()
2. 凸缺陷
凸包与轮廓间的部分称为凸缺陷
convexityDefects=cv2.convexityDefects(contour,convexhull)
返回值:[起点,终点,轮廓上距离凸包最远的点,最远点的近似距离]
前三个值是轮廓点的索引
参数:contour是轮廓;convexhull是凸包
因为用到的是轮廓点的索引,所以cv2.convexHull的参数returnPoints的值必须是False
import cv2
img=cv2.imread("D:/part12/part12_8.bmp")
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)
cnt=contours[0]
hull=cv2.convexHull(cnt,returnPoints=False)
defects=cv2.convexityDefects(cnt,hull)
print("defects:\n",defects)
##构造凸缺陷
for i in range(defects.shape[0]):
s,e,f,d=defects[i,0]
start=tuple(cnt[s][0])
end=tuple(cnt[e][0])
far=tuple(cnt[f][0])
cv2.line(img,start,end,[0,0,255],2)
cv2.circle(img,far,5,(255,0,0),-1)
cv2.imshow("img",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
defects:
[[[ 0 102 46 29796]]
[[ 102 105 104 284]]
[[ 106 166 133 17825]]
[[ 167 173 170 225]]
[[ 173 181 180 262]]
[[ 181 189 188 208]]
[[ 189 248 238 5027]]
[[ 250 344 267 3672]]
[[ 345 347 346 114]]
[[ 347 428 390 20365]]
[[ 428 524 479 28489]]
[[ 524 526 525 186]]]
cnt=contours[0]
#print(cnt) 随机图片会出现的问题,很小,捕捉不到凸包
#[[[256 366]]
# [[255 367]]]
3. 几何学测试
检测轮廓是否是凸形
retval=cv2.isContourConvex(contour)
retval: bool类型
contour:需要判断的轮廓
import cv2
img=cv2.imread("D:/part12/part12_8.bmp")
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)
#-----------------凸包
image1=img.copy()
hull=cv2.convexHull(contours[0])
cv2.polylines(image1,[hull],True,[0,255,0],2)
print("使用函数cv2.convexHull()构造的多边形是否是凸形的:",cv2.isContourConvex(hull))
cv2.imshow("result1",image1)
#-------------------逼近多边形
image2=img.copy()
epsilon=0.01*cv2.arcLength(contours[0],True)
approx=cv2.approxPolyDP(contours[0],epsilon,True)
image2=cv2.drawContours(image2,[approx],0,(0,0,255),2)
print("使用函数cv2.approxPolyDP()构造的多边形是否是凸形:",cv2.isContourConvex(approx))
cv2.imshow("result2",image2)
#-----------------------
cv2.waitKey(0)
cv2.destroyWindow()
使用函数cv2.convexHull()构造的多边形是否是凸形的: True
使用函数cv2.approxPolyDP()构造的多边形是否是凸形: False
点到轮廓的距离
用来计算点到多边形(轮廓)的最短距离,也就是垂线距离
retval=cv2.pointPolygonTest(contour,pt,measureDist)
pt: 为待判定的点
measureDist:True(距离,内正,上0,外负);False(相对位置关系,1,-1,0)
import cv2
img=cv2.imread("D:/part12/part12_6.bmp")
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)
#---------------获取凸包
image1=img.copy()
hull=cv2.convexHull(contours[0])
cv2.polylines(image1,[hull],True,(0,255,0),2)
#print(hull)
#------------------内部点A到轮廓的距离
distA=cv2.pointPolygonTest(hull,(320,50),True)
font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(image1,'A',(320,50),font,1,(0,255,0),3)
print("distA=",distA)
#-----------------轮廓上点B到轮廓的距离
distB=cv2.pointPolygonTest(hull,(432,100),True)
font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(image1,'B',(432,100),font,1,(0,255,0),3)
print("distB=",distB)
#-----------------轮廓外点C到轮廓的距离
distC=cv2.pointPolygonTest(hull,(432,150),True)
font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(image1,'C',(432,150),font,1,(0,255,0),3)
print("distC=",distC)
cv2.imshow("image1",image1)
cv2.waitKey(0)
cv2.destroyAllWindows()
distA= 19.27341155003588
distB= -0.0
distC= -27.164164493555205
点与轮廓的位置判断
将参数改为False
distA= 1.0
distB= 0.0
distC= -1.0
4. 轮廓的特征值
1.宽高比
import cv2
img=cv2.imread("D:/part12/part12_1.bmp")
cv2.imshow("result",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)
x,y,w,h=cv2.boundingRect(contours[0])
cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,255),3)
aspectRatio=float(w)/h
print(aspectRatio)
cv2.imshow("result",img)
cv2.waitKey(0)
cv2.destroyWindow()
1.6503067484662577
2. Extent
轮廓面积(对象面积)/矩形边界面积
import cv2
img=cv2.imread("D:/part12/part12_1.bmp")
cv2.imshow("result",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)
x,y,w,h=cv2.boundingRect(contours[0])
cv2.drawContours(img,contours[0],-1,(0,0,255),3)
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),3)
rectArea=w*h
cntArea=cv2.contourArea(contours[0])
extend=float(cntArea)/rectArea
print(extend)
cv2.imshow("result",img)
cv2.waitKey(0)
cv2.destroyWindow()
0.6662371427919812
3. Solidity
轮廓面积/凸包面积
import cv2
img=cv2.imread("D:/part12/part12_6.bmp")
cv2.imshow("result",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.drawContours(img,contours[0],-1,(0,255,255),3)
hull=cv2.convexHull(contours[0])
cntArea=cv2.contourArea(contours[0])
hullArea=cv2.contourArea(hull)
cv2.polylines(img,[hull],True,(0,255,0),2)
solidity=float(cntArea)/hullArea
print(solidity)
cv2.imshow("result",img)
cv2.waitKey(0)
cv2.destroyWindow()
0.7329527393863876
4. 等效直径
该值是与轮廓面积相等的圆形的直径
import cv2
import numpy as np
img=cv2.imread("D:/part12/part12_1.bmp")
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.drawContours(img,contours[0],-1,(0,0,255),3)
cntArea=cv2.contourArea(contours[0])
equiDiameter=np.sqrt(4*cntArea/np.pi)
print(equiDiameter)
cv2.circle(img,(100,100),int(equiDiameter/2),(0,0,255),3)
cv2.imshow("result",img)
cv2.waitKey(0)
cv2.destroyWindow()
192.85878305271953
5. 方向
(x,y),(MA,ma),angle=cv2.fitEllipse(cnt)
其中:
(x,y):椭圆的中心点
(MA,ma) :椭圆水平方向轴和垂直方向轴的长度
angle:椭圆的旋转角度
import cv2
img=cv2.imread("D:/part12/part12_1.bmp")
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)
ellipse=cv2.fitEllipse(contours[0])
retval=cv2.fitEllipse(contours[0])
print("单个返回形式:")
print("retval=\n",retval)
print("三个返回形式:")
(x,y),(MA,ma),angle=cv2.fitEllipse(contours[0])
print("(x,y)=(",x,y,")")
print("(MA,ma)=(",MA,ma,")")
print("angle=",angle)
cv2.ellipse(img,ellipse,(0,0,255),2)
cv2.imshow("img",img)
cv2.waitKey(0)
cv2.destroyWindow()
单个返回形式:
retval=
((246.05667114257812, 185.529541015625), (141.45005798339844, 282.24273681640625), 77.81553649902344)
三个返回形式:
(x,y)=( 246.05667114257812 185.529541015625 )
(MA,ma)=( 141.45005798339844 282.24273681640625 )
angle= 77.81553649902344
6. 掩模和像素点
6.1 使用Numpy函数获取轮廓像素点
cv2.drawContours()轮廓宽度参数thickness设置为“-1”,即可获取特定对象的实心轮廓,即特定对象的掩模
numpy.nonzero()
#返回数组内非零元素的位置,但其返回的是行,列分别显示的
numpy.transpose()
#处理上述返回值,则得到这些点的(x,y)形式的坐标
import numpy as np
a=np.zeros((5,5),dtype=np.uint8)
for time in range(10):
i=np.random.randint(0,5)
j=np.random.randint(0,5)
a[i,j]=1
print("a=\n",a)
loc=np.transpose(np.nonzero(a))
print("a内非零位置",loc)
a=
[[1 0 0 0 0]
[1 0 0 0 1]
[0 1 0 0 1]
[1 1 1 1 0]
[0 0 0 0 0]]
a内非零位置 [[0 0]
[1 0]
[1 4]
[2 1]
[2 4]
[3 0]
[3 1]
[3 2]
[3 3]]
使用numpy获取一个图像内的轮廓点位置
import cv2
import numpy as np
img=cv2.imread("D:/part12/part12_1.bmp")
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)
cnt=contours[0]
#-----------------------------------------绘制空心轮廓
mask1=np.zeros(gray.shape,np.uint8)
cv2.drawContours(mask1,[cnt],0,(255,255,255),2)
pixelpoints1=np.transpose(np.nonzero(mask1))
print("pixelpoints1.shape:",pixelpoints1.shape)
print("pixelpoints1:\n",pixelpoints1)
cv2.imshow("mask1",mask1)
#-----------------------------------------绘制实心轮廓
mask2=np.zeros(gray.shape,np.uint8)
cv2.drawContours(mask2,[cnt],0,(255,255,255),-1)
pixelpoints2=np.transpose(np.nonzero(mask2))
print("pixelpoints2.shape:",pixelpoints2.shape)
print("pixelpoints2:\n",pixelpoints2)
cv2.imshow("mask2",mask2)
cv2.waitKey(0)
cv2.destroyWindow()
cv2.waitKey(0)
cv2.destroyWindow()
pixelpoints1.shape: (2708, 2)
pixelpoints1:
[[111 276]
[111 277]
[111 278]
...
[275 150]
[275 151]
[275 152]]
pixelpoints2.shape: (29571, 2)
pixelpoints2:
[[112 277]
[112 278]
[112 279]
...
[274 149]
[274 150]
[274 151]]
6.1 使用Opencv函数获取轮廓像素点
import cv2
import numpy as np
a=np.zeros((5,5),dtype=np.uint8)
for time in range(5):
i=np.random.randint(0,5)
j=np.random.randint(0,5)
a[i,j]=1
print("a=\n",a)
loc=cv2.findNonZero(a)
print("a内非零值得位置:\n",loc)
a=
[[0 0 0 0 0]
[0 0 1 0 0]
[0 1 0 0 0]
[0 0 0 0 0]
[1 1 0 0 0]]
a内非零值得位置:
[[[2 1]]
[[1 2]]
[[0 4]]
[[1 4]]]
import cv2
import numpy as np
img=cv2.imread("D:/part12/part12_1.bmp")
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)
cnt=contours[0]
#----------------绘制空心轮廓
mask1=np.zeros(gray.shape,dtype=np.uint8)
cv2.drawContours(mask1,[cnt],0,255,2)
pixelpoints1=cv2.findNonZero(mask1)
print("pixelpoints.shape",pixelpoints1.shape)
print("pixelpoints",pixelpoints1)
cv2.imshow("mask1",mask1)
#----------------绘制实心轮廓
mask2=np.zeros(gray.shape,dtype=np.uint8)
cv2.drawContours(mask2,[cnt],0,255,-1)
pixelpoints2=cv2.findNonZero(mask2)
print("pixelpoints.shape",pixelpoints2.shape)
print("pixelpoints",pixelpoints2)
cv2.imshow("mask2",mask2)
cv2.waitKey(0)
cv2.destroyWindow()
最大值和最小值以及其位置
minval,maxval,minloc,maxloc=cv2.minMaxLoc(imgray,mask)
指定的对象内查找最大值,最小值以及其位置
import cv2
import numpy as np
img=cv2.imread("D:/101.bmp")
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)
cnt=contours[2]
mask=np.zeros(gray.shape,dtype=np.uint8)
mask=cv2.drawContours(mask,[cnt],-1,255,-1)
cv2.imshow("mask",mask)
minval,maxval,minloc,maxloc=cv2.minMaxLoc(gray,mask=mask)
print("minval:\n",minval)
print("maxval:\n",maxval)
print("minloc:\n",minloc)
print("maxloc:\n",maxloc)
#构造掩模获取感兴趣区域
masko=np.zeros(img.shape,dtype=np.uint8)
masko=cv2.drawContours(masko,[cnt],-1,(255,255,255),-1)
loc=cv2.bitwise_and(img,masko)
cv2.imshow("loc",loc)
cv2.waitKey(0)
cv2.destroyAllWindows()
minval:
127.0
maxval:
255.0
minloc:
(271, 148)
maxloc:
(271, 147)
6. 平均颜色及灰度
mean_val=cv2.mean(in,mask=mask)
import cv2
import numpy as np
img=cv2.imread("D:/101.bmp")
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)
cnt=contours[2]
mask=np.zeros(gray.shape,dtype=np.uint8)
cv2.drawContours(mask,[cnt],0,255,-1)
mean=cv2.mean(img,mask=mask)
print("mean=:",mean)
mask2=np.zeros(img.shape,dtype=np.uint8)
cv2.drawContours(mask2,[cnt],0,(255,255,255),-1)
loc=cv2.bitwise_and(img,mask2)
cv2.imshow("loc",loc)
cv2.waitKey(0)
cv2.destroyAllWindows()
mean=: (133.34867032503166, 133.34867032503166, 133.34867032503166, 0.0)
7. 极点
获取某个对象内的极点,例如最左端,最右端,最上端,最下端
leftmost=tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost=tuple(cnt[cnt[:,:,0].argmax()][0])
topmost=tuple(cnt[cnt[:,:,1].argmax()][0])
bottommost=tuple(cnt[cnt[:,:,1].argmin()][0])
import cv2
import numpy as np
img=cv2.imread("D:/part12/part12_6.bmp")
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)
cnt=contours[0]
mask=np.zeros(gray.shape,dtype=np.uint8)
cv2.drawContours(mask,[cnt],0,255,-1)
#---------------------------------计算极值
leftmost=tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost=tuple(cnt[cnt[:,:,0].argmax()][0])
topmost=tuple(cnt[cnt[:,:,1].argmax()][0])
bottommost=tuple(cnt[cnt[:,:,1].argmin()][0])
#---------------------------------打印极值
print("leftmost:",leftmost)
print("rightmost:",rightmost)
print("topmost",topmost)
print("bottommost",bottommost)
#---------------------------------绘制说明文字
font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'A',leftmost,font,1,(0,0,255),2)
cv2.putText(img,'B',rightmost,font,1,(0,0,255),2)
cv2.putText(img,'C',topmost,font,1,(0,0,255),2)
cv2.putText(img,'D',bottommost,font,1,(0,0,255),2)
#----------------------------------绘制图像
cv2.imshow("img",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
leftmost: (104, 159)
rightmost: (434, 111)
topmost (126, 237)
bottommost (322, 27)
网友评论