【MediaPipe】(1) AI视觉,手部关键点实时跟踪,附python完整代码
各位同學好,今天和大家分享一下如何使用MediaPipe完成手部關鍵點實時檢測跟蹤。先放張圖看效果,15代表FPS值。
1. 導入工具包
# 安裝opencv
pip install opencv-contrib-python
# 安裝mediapipe
pip install mediapipe
# pip install mediapipe --user #有user報錯的話試試這個# 安裝之后導入各個包
import cv2 #opencv
import mediapipe as mp
import time
MediaPipe 是一款由 Google Research 開發并開源的多媒體機器學習模型應用框架。它能夠完成人臉識別,虹膜檢測,體態跟蹤等。今天我們介紹一下手部關鍵點檢測,剩下的后續章節講述,感興趣的點個關注呦。
2. 顯示手部關鍵點及連線
2.1 相關函數解釋
(1)cv2.VideoCapture(0)? 獲取電腦自帶的攝像頭,修改參數1代表外接攝像頭
(2)mediapipe.solutions.hands.Hands()? 手部關鍵點檢測方法
參數:
static_image_mode: 默認為 False,將輸入圖像視為視頻流。它將嘗試在第一個輸入圖像中檢測手,并在成功檢測后進一步定位手的坐標。在隨后的圖像中,一旦檢測到所有 max_num_hands 手并定位了相應的手的坐標,它就會跟蹤這些坐標,而不會調用另一個檢測,直到它失去對任何一只手的跟蹤。這減少了延遲,非常適合處理視頻幀。如果設置為 True,則在每個輸入圖像上運行手部檢測,用于處理一批靜態的、可能不相關的圖像。
max_num_hands: 最多檢測幾只手,默認為2
min_detection_confidence: 手部檢測模型的最小置信值(0-1之間),超過閾值則檢測成功。默認為 0.5
min_tracking_confidence: 坐標跟蹤模型的最小置信值 (0-1之間),用于將手部坐標視為成功跟蹤,不成功則在下一個輸入圖像上自動調用手部檢測。將其設置為更高的值可以提高解決方案的穩健性,但代價是更高的延遲。如果 static_image_mode 為真,則忽略這個參數,手部檢測將在每個圖像上運行。默認為 0.5
返回值:
MULTI_HAND_LANDMARKS: 被檢測/跟蹤的手的集合,其中每只手被表示為21個手部地標的列表,每個地標由x, y, z組成。x和y分別由圖像的寬度和高度歸一化為[0,1]。Z表示地標深度。
MULTI_HANDEDNESS:?被檢測/追蹤的手是左手還是右手的集合。每只手由label(標簽)和score(分數)組成。 label?是 'Left' 或 'Right' 值的字符串。 score 是預測左右手的估計概率。
(3)mediapipe.solutions.drawing_utils.draw_landmarks()? 繪制手部關鍵點的連線
參數:?
image: 需要畫圖的原始圖片
landmark_list: 檢測到的手部關鍵點坐標
connections: 連接線,需要把那些坐標連接起來
landmark_drawing_spec: 坐標的顏色,粗細
connection_drawing_spec: 連接線的粗細,顏色等
(4)手部標記點如圖所示
2.2 只繪制手部關鍵點和連線
由于讀入視頻圖像通道一般為RGB,而opencv中圖像通道的格式為BGR,因此需要cv2.cvtColor()函數將opencv讀入的視頻圖像轉為RGB格式。results中存放每個關鍵點的xyz坐標,通過.multi_hand_landmarks讀取出來。
#(1)視頻捕獲
cap = cv2.VideoCapture(0) # 0代表電腦自帶的攝像頭#(2)創建檢測手部關鍵點的方法
mpHands = mp.solutions.hands #接收方法
hands = mpHands.Hands(static_image_mode=False, #靜態追蹤,低于0.5置信度會再一次跟蹤max_num_hands=2, # 最多有2只手min_detection_confidence=0.5, # 最小檢測置信度min_tracking_confidence=0.5) # 最小跟蹤置信度 # 創建檢測手部關鍵點和關鍵點之間連線的方法
mpDraw = mp.solutions.drawing_utils# 查看時間
pTime = 0 #處理一張圖像前的時間
cTime = 0 #一張圖處理完的時間#(3)處理視頻圖像
while True: # 對每一幀視頻圖像處理# 返回是否讀取成功和讀取的圖像success, img = cap.read()# 在循環中發送rgb圖像到hands中,opencv中圖像默認是BGR格式imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 把圖像傳入檢測模型,提取信息results = hands.process(imgRGB)# 檢查是否檢測到什么東西了,沒有檢測到手就返回None# print(results.multi_hand_landmarks)# 檢查每幀圖像是否有多只手,一一提取它們if results.multi_hand_landmarks: #如果沒有手就是Nonefor handlms in results.multi_hand_landmarks:# 繪制每只手的關鍵點mpDraw.draw_landmarks(img, handlms, mpHands.HAND_CONNECTIONS) #傳入想要繪圖畫板img,單只手的信息handlms# mpHands.HAND_CONNECTIONS繪制手部關鍵點之間的連線# 記錄執行時間 cTime = time.time() # 計算fpsfps = 1/(cTime-pTime)# 重置起始時間pTime = cTime# 把fps顯示在窗口上;img畫板;取整的fps值;顯示位置的坐標;設置字體;字體比例;顏色;厚度cv2.putText(img, str(int(fps)), (10,70), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)# 顯示圖像cv2.imshow('Image', img) #窗口名,圖像變量if cv2.waitKey(1) & 0xFF==27: #每幀滯留1毫秒后消失;ESC鍵退出break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()
這里設置了最大可識別2只手,如果有需要可通過result.multi_handedness,分別處理左右手的坐標。
3. 編輯關鍵點坐標,更改顯示圖像
上面我們通過results.multi_hand_landmarks得到的xyz坐標是歸一化后的比例坐標,即某一像素點在圖像的某一比例位置[0.5, 0.5]。我們需要將其轉為像素坐標,如[200,200],像素坐標一定是整數。通過圖像寬度乘以比例即可得到像素長度。為了能更明顯的顯示關鍵點,把關鍵點畫的大一些,只需以關鍵點的像素坐標為圓心畫圓cv2.circle()即可。
因此我們在上面的代碼中補充
#(1)視頻捕獲
cap = cv2.VideoCapture(0) # 0代表電腦自帶的攝像頭#(2)創建檢測手部關鍵點的方法
mpHands = mp.solutions.hands #接收方法
hands = mpHands.Hands(static_image_mode=False, #靜態追蹤,低于0.5置信度會再一次跟蹤max_num_hands=2, # 最多有2只手min_detection_confidence=0.5, # 最小檢測置信度min_tracking_confidence=0.5) # 最小跟蹤置信度 # 創建檢測手部關鍵點和關鍵點之間連線的方法
mpDraw = mp.solutions.drawing_utils# 查看時間
pTime = 0 #處理一張圖像前的時間
cTime = 0 #一張圖處理完的時間# 存放坐標信息
lmList = []#(3)處理視頻圖像
# 文件設為True,對每一幀視頻圖像處理
while True:# 返回是否讀取成功和讀取的圖像success, img = cap.read()# 在循環中發送rgb圖像到hands中,opencv中圖像默認是BGR格式imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 把圖像傳入檢測模型,提取信息results = hands.process(imgRGB)# 檢查每幀圖像是否有多只手,一一提取它們if results.multi_hand_landmarks: #如果沒有手就是Nonefor handlms in results.multi_hand_landmarks:# 獲取每個關鍵點的索引和坐標for index, lm in enumerate(handlms.landmark):# 索引為0代表手底部中間部位,為4代表手指關鍵或指尖# print(index, lm) # 輸出21個手部關鍵點的xyz坐標(0-1之間),是相對于圖像的長寬比例# 只需使用x和y查找位置信息# 將xy的比例坐標轉換成像素坐標h, w, c = img.shape # 分別存放圖像長\寬\通道數# 中心坐標(小數),必須轉換成整數(像素坐標)cx ,cy = int(lm.x * w), int(lm.y * h) #比例坐標x乘以寬度得像素坐標# 打印顯示21個關鍵點的像素坐標print(index, cx, cy)# 存儲坐標信息lmList.append([index, cx, cy])# 在21個關鍵點上換個圈,img畫板,坐標(cx,cy),半徑5,藍色填充cv2.circle(img, (cx,cy), 12, (0,0,255), cv2.FILLED)# 繪制每只手的關鍵點mpDraw.draw_landmarks(img, handlms, mpHands.HAND_CONNECTIONS) #傳入想要繪圖畫板img,單只手的信息handlms# mpHands.HAND_CONNECTIONS繪制手部關鍵點之間的連線# 記錄執行時間 cTime = time.time() # 計算fpsfps = 1/(cTime-pTime)# 重置起始時間pTime = cTime# 把fps顯示在窗口上;img畫板;取整的fps值;顯示位置的坐標;設置字體;字體比例;顏色;厚度cv2.putText(img, str(int(fps)), (10,70), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)# 顯示圖像cv2.imshow('Image', img) #窗口名,圖像變量if cv2.waitKey(1) & 0xFF==27: #每幀滯留1毫秒后消失break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()
得到的結果如下,fps=19,右下輸出框中打印每幀圖像的21個手部關鍵點xy坐標,并保存在列表中。
總結
以上是生活随笔為你收集整理的【MediaPipe】(1) AI视觉,手部关键点实时跟踪,附python完整代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【yolo目标检测】(1) yolov3
- 下一篇: 【MediaPipe】(2) AI视觉,