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