從零開發(fā)一個 Python 項目,手勢識別!
最近開發(fā)了一個手勢處理的項目(零基礎(chǔ)也可以學,就是針對零基礎(chǔ)的),我在這兒簡單的復(fù)述一下原理,總體來說還是比較簡單的,主要運用的知識就是opencv,python基本語法,圖像處理基礎(chǔ)知識。
最終實現(xiàn)結(jié)果:
獲取視頻(攝像頭)
這部分沒啥說的,就是獲取攝像頭。
cap?=?cv2.VideoCapture("C:/Users/lenovo/Videos/1.mp4")#讀取文件
#cap?=?cv2.VideoCapture(0)#讀取攝像頭
while(True):
????ret,?frame?=?cap.read()????key?=?cv2.waitKey(50)?&?0xFF
????if?key?==?ord('q'):
??????break
cap.release()
cv2.destroyAllWindows()
膚色檢測
這里使用的是橢圓膚色檢測模型。
在RGB空間里人臉的膚色受亮度影響相當大,所以膚色點很難從非膚色點中分離出來,也就是說在此空間經(jīng)過處理后,膚色點是離散的點,中間嵌有很多非膚色,這為膚色區(qū)域標定(人臉標定、眼睛等)帶來了難題。
如果把RGB轉(zhuǎn)為YCrCb空間的話,可以忽略Y(亮度)的影響,因為該空間受亮度影響很小,膚色會產(chǎn)生很好的類聚。
這樣就把三維的空間將為二維的CrCb,膚色點會形成一定得形狀,如:人臉的話會看到一個人臉的區(qū)域,手臂的話會看到一條手臂的形態(tài)。
def?A(img):
????YCrCb?=?cv2.cvtColor(img,?cv2.COLOR_BGR2YCR_CB)?#轉(zhuǎn)換至YCrCb空間
????(y,cr,cb)?=?cv2.split(YCrCb)?#拆分出Y,Cr,Cb值
????cr1?=?cv2.GaussianBlur(cr,?(5,5),?0)
????_,?skin?=?cv2.threshold(cr1,?0,?255,?cv2.THRESH_BINARY?+?cv2.THRESH_OTSU)?#Ostu處理
????res?=?cv2.bitwise_and(img,img,?mask?=?skin)
????return?res
輪廓處理
輪廓處理的話主要用到兩個函數(shù),cv2.findContours和cv2.drawContours,這兩個函數(shù)的使用使用方法很容易搜到就不說了,這部分主要的問題是提取到的輪廓有很多個,但是我們只需要手的輪廓,所以我們要用sorted函數(shù)找到最大的輪廓。
def?B(img):
????#binaryimg?=?cv2.Canny(Laplacian,?50,?200)?#二值化,canny檢測
????h?=?cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)?#尋找輪廓
????contour?=?h[0]
????contour?=?sorted(contour,?key?=?cv2.contourArea,?reverse=True)#已輪廓區(qū)域面積進行排序
????#contourmax?=?contour[0][:,?0,?:]#保留區(qū)域面積最大的輪廓點坐標
????bg?=?np.ones(dst.shape,?np.uint8)?*255#創(chuàng)建白色幕布
????ret?=?cv2.drawContours(bg,contour[0],-1,(0,0,0),3)?#繪制黑色輪廓
????return?ret
全部代碼
"""?從視頻讀取幀保存為圖片"""
import?cv2
import?numpy?as?np
cap?=?cv2.VideoCapture("C:/Users/lenovo/Videos/1.mp4")#讀取文件
#cap?=?cv2.VideoCapture(0)#讀取攝像頭
#皮膚檢測
def?A(img):
????YCrCb?=?cv2.cvtColor(img,?cv2.COLOR_BGR2YCR_CB)?#轉(zhuǎn)換至YCrCb空間
????(y,cr,cb)?=?cv2.split(YCrCb)?#拆分出Y,Cr,Cb值
????cr1?=?cv2.GaussianBlur(cr,?(5,5),?0)
????_,?skin?=?cv2.threshold(cr1,?0,?255,?cv2.THRESH_BINARY?+?cv2.THRESH_OTSU)?#Ostu處理
????res?=?cv2.bitwise_and(img,img,?mask?=?skin)
????return?res
def?B(img):
????#binaryimg?=?cv2.Canny(Laplacian,?50,?200)?#二值化,canny檢測
????h?=?cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)?#尋找輪廓
????contour?=?h[0]
????contour?=?sorted(contour,?key?=?cv2.contourArea,?reverse=True)#已輪廓區(qū)域面積進行排序
????#contourmax?=?contour[0][:,?0,?:]#保留區(qū)域面積最大的輪廓點坐標
????bg?=?np.ones(dst.shape,?np.uint8)?*255#創(chuàng)建白色幕布
????ret?=?cv2.drawContours(bg,contour[0],-1,(0,0,0),3)?#繪制黑色輪廓
????return?ret
while(True):
????ret,?frame?=?cap.read()
????#下面三行可以根據(jù)自己的電腦進行調(diào)節(jié)
????src?=?cv2.resize(frame,(400,350),?interpolation=cv2.INTER_CUBIC)#窗口大小
????cv2.rectangle(src,?(90,?60),?(300,?300?),?(0,?255,?0))#框出截取位置
????roi?=?src[60:300?,?90:300]??#?獲取手勢框圖
????res?=?A(roi)??#?進行膚色檢測
????cv2.imshow("0",roi)
????gray?=?cv2.cvtColor(res,?cv2.COLOR_BGR2GRAY)
????dst?=?cv2.Laplacian(gray,?cv2.CV_16S,?ksize?=?3)
????Laplacian?=?cv2.convertScaleAbs(dst)
????contour?=?B(Laplacian)#輪廓處理
????cv2.imshow("2",contour)
????key?=?cv2.waitKey(50)?&?0xFF
????if?key?==?ord('q'):
????????????break
cap.release()
cv2.destroyAllWindows()
來源:網(wǎng)絡(luò)