簡單的手勢識別,基本思路是基於皮膚檢測,皮膚的顏色在HSV顏色空間下與周圍環境的區分度更高,從RGB轉換到HSV顏色空間下針對皮膚顏色進行二值化,得到mask:
def HSVBin(img): hsv = cv2.cvtColor(img,cv2.COLOR_RGB2HSV) lower_skin = np.array([100,50,0]) upper_skin = np.array([125,255,255]) mask = cv2.inRange(hsv,lower_skin,upper_skin) return mask
其中:
cvtColor用於顏色空間轉換。
inRange中,lower指圖像中低於這個值,圖像值會變成0;upper指圖像中高於這個值,圖像值會變成0,而在這之間的值變為255。
然后通過腐蝕與膨脹等形態學變化去除一些噪點,得到更完整的白色(皮膚)色塊,最后找出色塊的輪廓,並通過色塊大小排除一些面積較小的噪點:
def getContours(img): kernel = np.ones((5,5),np.uint8) closed = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel) closed = cv2.morphologyEx(closed,cv2.MORPH_CLOSE,kernel) _,contours,h = cv2.findContours(closed,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) vaildContours = [] for cont in contours: if cv2.contourArea(cont)>9000: vaildContours.append(cv2.convexHull(cont)) return vaildContours
膨脹:dilate,進行膨脹操作時,將內核 B划過圖像,將內核B覆蓋區域的最大像素值提取,並代替錨點位置的像素,這一最大化操作會導致圖像中的亮區開始“擴展”。
腐蝕:erode,將最小像素值提取原始圖片里的一個像素(1或者0)只有在核下的所有像素都是1的時候才被認為是1.否則它就被腐蝕掉了(變成0)。根據核的大小來決定在邊界附近的多少像素會被丟棄掉,所以前景物體的厚度或大小會縮小,或者說白色區域會減小。這個在移除小的白色噪點時很有用。
ones(shape[,dtype,order]) 依據一個給定的形狀和類型返回一個新的元素全部為1的數組。
data type :uint8 -->range:0~255,一張圖片的數據類型默認為unit8
開:腐蝕之后再膨脹的另一個名字。我們使用函數cv2.morphologyEx()。
閉:膨脹之后再腐蝕,在用來關閉前景對象里的小洞或小黑點很有用。
輪廓檢測 cv2.findContours,接收參數為二值圖。
def main(): cap = cv2.VideoCapture(0) while(cap.isOpened()): ret,img = cap.read() skinMask = HSVBin(img) contours = getContours(skinMask) cv2.drawContours(img,contours,-1,(0,255,0),2) cv2.imshow('capture',img) k = cv2.waitKey(10) if k == 27: break
cv2.waitKey()--waitKey()函數的功能是不斷刷新圖像,頻率時間為delay,單位為ms。返回值為當前鍵盤按鍵值。
完整代碼如下:
import cv2 import numpy as np def main(): cap = cv2.VideoCapture(0) while(cap.isOpened()): ret,img = cap.read() skinMask = HSVBin(img) contours = getContours(skinMask) cv2.drawContours(img,contours,-1,(0,255,0),2) cv2.imshow('capture',img) k = cv2.waitKey(10) if k == 27: break def getContours(img): kernel = np.ones((5,5),np.uint8) closed = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel) closed = cv2.morphologyEx(closed,cv2.MORPH_CLOSE,kernel) _,contours,h = cv2.findContours(closed,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) vaildContours = [] for cont in contours: if cv2.contourArea(cont)>9000: #x,y,w,h = cv2.boundingRect(cont) #if h/w >0.75: #filter face failed vaildContours.append(cv2.convexHull(cont)) #rect = cv2.minAreaRect(cont) #box = cv2.cv.BoxPoint(rect) #vaildContours.append(np.int0(box)) return vaildContours def HSVBin(img): hsv = cv2.cvtColor(img,cv2.COLOR_RGB2HSV) lower_skin = np.array([100,50,0]) upper_skin = np.array([125,255,255]) mask = cv2.inRange(hsv,lower_skin,upper_skin) #res = cv2.bitwise_and(img,img,mask=mask) return mask if __name__ =='__main__': main()
效果: