首頁>技術>

利用餘弦定理使用OpenCV-Python實現手指計數與手掌檢測。

手檢測和手指計數

接下來讓我們一起探索以下這個功能是如何實現的。

OpenCV

OpenCV(開源計算機視覺庫)是一個開源計算機視覺和機器學習軟體庫。OpenCV的構建旨在為計算機視覺應用程式提供通用的基礎結構,並加速在商業產品中使用機器感知。

匯入庫

cv2: opencv [pip install opencv]

numpy:用於處理陣列和數學[pip install numpy]

import cv2 as cvimport numpy as np

匯入影象

img_path = "data/palm.jpg"img = cv.imread(img_path)cv.imshow('palm image',img)

手掌影象

面板Mask

• 用於突出顯示影象上的特定顏色。

• hsvim:將BGR(藍色,綠色,紅色)影象更改為HSV(色相,飽和度,值)。

• 較低:HSV中的膚色範圍較小。

• upper:HSV中面板顏色的上限。

• skinRegionHSV:在HSV色彩空間的上下畫素值範圍內檢測面板。

• 模糊:使影象模糊以改善遮罩。

• 脫粒:脫粒。

hsvim = cv.cvtColor(img, cv.COLOR_BGR2HSV)lower = np.array([0, 48, 80], dtype = "uint8")upper = np.array([20, 255, 255], dtype = "uint8")skinRegionHSV = cv.inRange(hsvim, lower, upper)blurred = cv.blur(skinRegionHSV, (2,2))ret,thresh = cv.threshold(blurred,0,255,cv.THRESH_BINARY)cv.imshow("thresh", thresh)

處理結果

輪廓線繪製

現在讓我們在影象上找到輪廓。

contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)contours = max(contours, key=lambda x: cv.contourArea(x))cv.drawContours(img, [contours], -1, (255,255,0), 2)cv.imshow("contours", img)

手掌輪廓線

凸包檢測

hull = cv.convexHull(contours)cv.drawContours(img, [hull], -1, (0, 255, 255), 2)cv.imshow("hull", img)

檢測結果

凸缺陷檢測

手掌與凸包檢測輪廓線的任何偏離的地方都可以視為凸度缺陷。

hull = cv.convexHull(contours, returnPoints=False)defects = cv.convexityDefects(contours, hull)

凸缺陷示例

餘弦定理

現在,這是數學時間!讓我們瞭解餘弦定理。

在三角學中,餘弦定律將三角形邊的長度與其角度之一的餘弦相關。使用如圖1所示的符號表示,餘弦定律表明,其中γ表示長度a和b的邊之間的長度以及與長度c的邊相對的角度。

圖1

式:

透過現在看這個公式,我們知道如果有的話;a,b和gama然後我們也找到c以及是否有c ; a,b,c然後我們也找到伽瑪(反之亦然)

為了找到伽瑪,使用以下公式:

使用餘弦定理識別手指

圖2

在圖2中,我畫了一個Side:a,b,c和angle:gamma。現在,該伽馬始終小於90度,因此可以說:如果伽馬小於90度或pi / 2,則將其視為手指。

手指個數計算

注意:如果您不熟悉凸出缺陷,可以閱讀以下文章。

https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.html

凸缺陷返回一個數組,其中每一行都包含以下值:

起點

終點

最遠點

到最遠點的大概距離

透過這一點,我們可以輕鬆得出Sides:a,b,c(請參見CODE),並且根據餘弦定理,我們還可以得出兩根手指之間的伽馬或角度。如前所述,如果伽瑪小於90度,我們會將其視為手指。知道伽瑪後,我們只需畫一個半徑為4的圓,到最遠點的近似距離即可。在將文字簡單地放入影象中之後,我們就表示手指數(cnt)。

if defects is not None:cnt = 0for i in range(defects.shape[0]): # calculate the angles, e, f, d = defects[i][0]start = tuple(contours[s][0])end = tuple(contours[e][0])far = tuple(contours[f][0])a = np.sqrt((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2)b = np.sqrt((far[0] - start[0]) ** 2 + (far[1] - start[1]) ** 2)c = np.sqrt((end[0] - far[0]) ** 2 + (end[1] - far[1]) ** 2)angle = np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)) # cosine theoremif angle <= np.pi / 2: # angle less than 90 degree, treat as fingerscnt += 1cv.circle(img, far, 4, [0, 0, 255], -1)if cnt > 0:cnt = cnt+1cv.putText(img, str(cnt), (0, 50), cv.FONT_HERSHEY_SIMPLEX,1, (255, 0, 0) , 2, cv.LINE_AA)

讓我們看看最終結果

cv.imshow('final_result',img)

我們也可以透過呼叫“ cv.VideoCapture()”來對影片執行此操作。

全部程式碼如下

import numpy as npimport cv2 as cvdef skinmask(img):    hsvim = cv.cvtColor(img, cv.COLOR_BGR2HSV)    lower = np.array([0, 48, 80], dtype = "uint8")    upper = np.array([20, 255, 255], dtype = "uint8")    skinRegionHSV = cv.inRange(hsvim, lower, upper)    blurred = cv.blur(skinRegionHSV, (2,2))    ret, thresh = cv.threshold(blurred,0,255,cv.THRESH_BINARY)    return threshdef getcnthull(mask_img):    contours, hierarchy = cv.findContours(mask_img, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)    contours = max(contours, key=lambda x: cv.contourArea(x))    hull = cv.convexHull(contours)    return contours, hulldef getdefects(contours):    hull = cv.convexHull(contours, returnPoints=False)    defects = cv.convexityDefects(contours, hull)    return defectscap = cv.VideoCapture("your_video_path") # '0' for webcamwhile cap.isOpened():    _, img = cap.read()    try:        mask_img = skinmask(img)        contours, hull = getcnthull(mask_img)        cv.drawContours(img, [contours], -1, (255,255,0), 2)        cv.drawContours(img, [hull], -1, (0, 255, 255), 2)        defects = getdefects(contours)        if defects is not None:            cnt = 0            for i in range(defects.shape[0]):  # calculate the angle                s, e, f, d = defects[i][0]                start = tuple(contours[s][0])                end = tuple(contours[e][0])                far = tuple(contours[f][0])                a = np.sqrt((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2)                b = np.sqrt((far[0] - start[0]) ** 2 + (far[1] - start[1]) ** 2)                c = np.sqrt((end[0] - far[0]) ** 2 + (end[1] - far[1]) ** 2)                angle = np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c))  #      cosine theorem                if angle <= np.pi / 2:  # angle less than 90 degree, treat as fingers                    cnt += 1                    cv.circle(img, far, 4, [0, 0, 255], -1)            if cnt > 0:                cnt = cnt+1            cv.putText(img, str(cnt), (0, 50), cv.FONT_HERSHEY_SIMPLEX,1, (255, 0, 0) , 2, cv.LINE_AA)        cv.imshow("img", img)    except:        pass    if cv.waitKey(1) & 0xFF == ord('q'):        breakcap.release()cv.destroyAllWindows()

程式碼連結如下https://github.com/madhav727/medium/blob/master/finger_counting_video.py

11
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • NAT轉換之Basic NTA