在本教程中,我們將使用MediaPipePython 庫(kù)來(lái)檢測(cè)我們的手勢(shì)并使用它來(lái)控制 Raspberry Pi 媒體播放器。在這里,我們將使用總共六個(gè)手勢(shì),即開(kāi)合拳和手的上、下、左、右移動(dòng)。打開(kāi)和關(guān)閉拳頭手勢(shì)用于播放和暫停視頻。上下手勢(shì)用于增大和減小音量,左右手勢(shì)用于快進(jìn)和倒退視頻。
構(gòu)建手勢(shì)控制媒體播放器所需的組件
樹(shù)莓派 4
Pi 相機(jī)模塊
在這里,我們只需要安裝了 OpenCV 和 MediaPipe 的 Raspberry Pi 4 和 Pi 攝像頭模塊。 OpenCV 用于 數(shù)字圖像處理,而 MediaPipe 用于手部跟蹤。數(shù)字圖像處理最常見(jiàn)的應(yīng)用是 物體檢測(cè)、 人臉識(shí)別和 人數(shù)統(tǒng)計(jì)。
什么是媒體管道?
MediaPipe是一個(gè)框架,用于構(gòu)建跨平臺(tái)(即 Android、iOS、Web、邊緣設(shè)備)多模式(例如視頻、音頻、任何時(shí)間序列數(shù)據(jù))應(yīng)用機(jī)器學(xué)習(xí)管道,包括快速 ML 推理、經(jīng)典計(jì)算機(jī)視覺(jué)和媒體處理(例如視頻解碼)。MediaPipe 發(fā)布了各種預(yù)構(gòu)建的 python 和其他語(yǔ)言包,例如:
物體檢測(cè)
人臉檢測(cè)
手部追蹤
姿勢(shì)估計(jì)
多手追蹤
頭發(fā)分割
MediaPipe Python 包在適用于 Linux、macOS 和 Windows 的 PyPI 上可用。使用以下命令在 Raspberry Pi 4 上安裝 MediaPipe:
?
須藤 pip3 安裝 mediapipe-rpi4
?
如果您沒(méi)有 Pi 4,則可以使用以下命令將其安裝在 Raspberry Pi 3 上:
?
須藤 pip3 安裝 mediapipe-rpi3
?
在樹(shù)莓派上安裝 OpenCV
在安裝 OpenCV 和其他依賴(lài)項(xiàng)之前,Raspberry Pi 需要完全更新。使用以下命令將 Raspberry Pi 更新到其最新版本:
?
sudo apt-get 更新
?
然后使用以下命令安裝在 Raspberry Pi 上安裝 OpenCV 所需的依賴(lài)項(xiàng)。
?
sudo apt-get install libhdf5-dev -y sudo apt-get install libhdf5-serial-dev –y sudo apt-get install libatlas-base-dev –y sudo apt-get install libjasper-dev -y sudo apt-get install libqtgui4 –y sudo apt-get install libqt4-test –y
?
之后,使用以下命令在您的 Raspberry Pi 上安裝 OpenCV。
?
pip3 安裝 opencv-contrib-python==4.1.0.25
?
在樹(shù)莓派上安裝PyAutoGUI
PyAutoGUI 是一個(gè)跨平臺(tái)的 GUI 自動(dòng)化 Python 模塊,可讓您的 Python 腳本控制鼠標(biāo)和鍵盤(pán)以自動(dòng)與其他應(yīng)用程序交互。PyAutoGUI 適用于 Windows、macOS 和 Linux,并在 Python 2 和 3 上運(yùn)行。要在 Raspberry Pi 上安裝 PyAutoGUI,請(qǐng)運(yùn)行:
?
pip3 安裝 pyautogui
?
文檔末尾給出了使用手勢(shì)控制媒體播放器的完整代碼。在這里,我們將解釋代碼的重要部分,以便更好地解釋。
通過(guò)導(dǎo)入 OpenCV、MediaPipe 和 PyAutoGUI 包來(lái)啟動(dòng)代碼。如前所述,MediaPipe 是手部跟蹤的核心包,而 OpenCV 用于圖像處理。PyAutoGUI 用于根據(jù)手勢(shì)控制鍵盤(pán)。
?
導(dǎo)入簡(jiǎn)歷2 將媒體管道導(dǎo)入為 mp 導(dǎo)入pyautogui
?
在接下來(lái)的幾行中,我們創(chuàng)建了兩個(gè)新變量。第一個(gè)是mp_drawing,它將用于從 MediaPipe python 包中獲取所有繪圖實(shí)用程序,第二個(gè)是mp_hands,用于導(dǎo)入手部跟蹤模型。
?
mp_drawing = mp.solutions.drawing_utils mp_hands = mp.solutions.hands
?
之后定義一個(gè)名為findPosition() 的函數(shù)。顧名思義,它用于查找食指、中指、無(wú)名指和小指的 X、Y 坐標(biāo)。所有指尖的坐標(biāo)都將存儲(chǔ)在一個(gè)名為lmList[]的變量中。
?
def 手指位置(圖像,handNo=0): lmList = [] 如果結(jié)果.multi_hand_landmarks: myHand = results.multi_hand_landmarks[handNo] 對(duì)于 id, lm in enumerate(myHand.landmark): # 打?。╥d,lm) h, w, c = image.shape cx, cy = int(lm.x * w), int(lm.y * h) lmList.append([id, cx, cy]) 返回 lmList
?
然后從 Raspberry Pi 相機(jī)開(kāi)始視頻流,幀高和寬分別為 720、640。
?
上限 = cv2.VideoCapture(0) cap.set(3, wCam) cap.set(4, hCam)
?
然后在下一行中為 mediapipe 提要設(shè)置一個(gè)新實(shí)例,以訪問(wèn)我們之前導(dǎo)入的手部追蹤模型。我們還傳遞了兩個(gè)關(guān)鍵字參數(shù),即最小檢測(cè)置信度和最小跟蹤置信度。接下來(lái),我們將讀取視頻幀并將它們存儲(chǔ)在圖像變量中。
用 mp_hands.Hands(min_detection_confidence=0.8, min_tracking_confidence=0.5) 作為手:
?
而 cap.isOpened(): 成功,圖像 = cap.read()
?
我們從視頻源獲得的圖像最初是 BGR 格式。因此,在這一行中,我們將首先水平翻轉(zhuǎn)圖像以供稍后的自拍視圖顯示,然后將 BGR 圖像轉(zhuǎn)換為 RGB。圖像可寫(xiě)標(biāo)志設(shè)置為假。?
?
圖像 = cv2.cvtColor(cv2.flip(圖像, 1), cv2.COLOR_BGR2RGB) image.flags.writeable = False
?
?之后,我們將通過(guò)手部跟蹤模型傳遞圖像以進(jìn)行檢測(cè)并將結(jié)果存儲(chǔ)在一個(gè)名為“結(jié)果”的變量中。
?
結(jié)果=hands.process(圖像)
?
檢測(cè)完成后,我們將圖像可寫(xiě)標(biāo)志設(shè)置為 true,并將 RGB 圖像轉(zhuǎn)換為 BGR。
?
image.flags.writeable = True 圖像 = cv2.cvtColor(圖像,cv2.COLOR_RGB2BGR)
?
現(xiàn)在,當(dāng)我們得到檢測(cè)結(jié)果時(shí),我們將調(diào)用mp_drawing?變量在圖像上繪制這些檢測(cè),并使用我們之前導(dǎo)入的繪圖實(shí)用程序連接所有檢測(cè)。
?
如果結(jié)果.multi_hand_landmarks: 對(duì)于 results.multi_hand_landmarks 中的 hand_landmarks: mp_drawing.draw_landmarks( 圖片、hand_landmarks、mp_hands.HAND_CONNECTIONS)
?
之后,我們將調(diào)用findPosition()函數(shù)來(lái)獲取所有檢測(cè)的 id 和坐標(biāo)。這些值將存儲(chǔ)在名為 lmList 的變量中。
?
lmList = findPosition(圖像,繪制=真)
?
現(xiàn)在我們有了所有手部標(biāo)志的坐標(biāo),我們將使用它們來(lái)檢測(cè)不同的手勢(shì),其中第一個(gè)是檢測(cè)拳頭是張開(kāi)還是閉合。為此,我們將比較指尖 [8, 12, 16, 20] 和中點(diǎn) [6, 10, 14, 19] 的坐標(biāo),如果指尖低于中點(diǎn),則拳頭閉合,反之亦然反之亦然。
對(duì)于范圍內(nèi)的 id(1, 5):
?
如果 lmList[tipIds[id]][2] < lmList[tipIds[id] - 2][2]: 手指.append(1) 如果(lmList[tipIds[id]][2] > lmList[tipIds[id] - 2][2]): 手指.append(0)
?
然后在接下來(lái)的幾行中,獲取計(jì)數(shù)的手指總數(shù)并將其保存在一個(gè)名為totalFingers的變量中。
?
totalFingers = Fingers.count(1) 打?。偸种福?/pre>?
現(xiàn)在我們得到了手指的數(shù)量,我們將使用它們來(lái)播放和暫停視頻。
?
如果 totalFingers == 4: 狀態(tài) = “播放” 如果 totalFingers == 0 并且 state == "Play": 狀態(tài) = “暫?!? pyautogui.press('空格') 打?。ā翱臻g”)?
然后我們要檢測(cè)的下一個(gè)手勢(shì)是向左、向右、向上和向下移動(dòng)。為了檢測(cè)左右移動(dòng),首先我們將獲取食指尖的 X 坐標(biāo),如果值小于 300 則為左滑,如果值大于 400 則為右滑。
?
如果 totalFingers == 1: 如果 lmList[8][1]<300: 打印(“左”) pyautogui.press('左') 如果 lmList[8][1]>400: 打?。ā罢_”) pyautogui.press('對(duì)')?
同理,檢測(cè)上下手勢(shì),我們會(huì)得到中指的 Y 坐標(biāo),如果值小于 210 則為上滑,如果值大于 230 則為下滑.
?
如果 totalFingers == 2: 如果 lmList[9][2] < 210: 打印(“向上”) pyautogui.press('向上') 如果 lmList[9][2] > 230: 打印(“向下”) pyautogui.press('向下')?
測(cè)試我們的手勢(shì)控制媒體控制器腳本
現(xiàn)在媒體計(jì)數(shù)器腳本已經(jīng)準(zhǔn)備好了,讓我們繼續(xù)測(cè)試它。因此,將 Raspberry Pi 攝像頭模塊與 Pi 連接,如下所示:
現(xiàn)在,檢查 Pi 相機(jī)是否正常工作。查看相機(jī)后,啟動(dòng) Python 腳本,您會(huì)發(fā)現(xiàn)彈出一個(gè)窗口,其中包含視頻源?,F(xiàn)在,您可以通過(guò)手勢(shì)控制視頻播放器。您可以在下面找到該項(xiàng)目的工作視頻。您可以將視頻源更改為您選擇的任何視頻,并享受通過(guò)手勢(shì)控制它的樂(lè)趣。
導(dǎo)入簡(jiǎn)歷2
將媒體管道導(dǎo)入為 mp
導(dǎo)入pyautogui
mp_drawing = mp.solutions.drawing_utils
mp_hands = mp.solutions.hands
##################################
tipIds = [4, 8, 12, 16, 20]
狀態(tài) = 無(wú)
手勢(shì) = 無(wú)
wCam, hCam = 720, 640
############################
def 手指位置(圖像,handNo=0):
lmList = []
如果結(jié)果.multi_hand_landmarks:
myHand = results.multi_hand_landmarks[handNo]
對(duì)于 id, lm in enumerate(myHand.landmark):
# 打?。╥d,lm)
h, w, c = image.shape
cx, cy = int(lm.x * w), int(lm.y * h)
lmList.append([id, cx, cy])
返回 lmList
# 對(duì)于網(wǎng)絡(luò)攝像頭輸入:
上限 = cv2.VideoCapture(0)
cap.set(3, wCam)
cap.set(4, hCam)
與 mp_hands.Hands(
min_detection_confidence=0.8,
min_tracking_confidence=0.5) 作為手牌:
而 cap.isOpened():
成功,圖像 = cap.read()
如果不成功:
print("忽略空相機(jī)幀。")
# 如果加載視頻,請(qǐng)使用“break”而不是“continue”。
繼續(xù)
# 水平翻轉(zhuǎn)圖像以供稍后自拍視圖顯示,并轉(zhuǎn)換
# 將 BGR 圖像轉(zhuǎn)為 RGB。
圖像 = cv2.cvtColor(cv2.flip(圖像, 1), cv2.COLOR_BGR2RGB)
image.flags.writeable = False
結(jié)果=hands.process(圖像)
# 在圖像上繪制手部注釋。
image.flags.writeable = True
圖像 = cv2.cvtColor(圖像,cv2.COLOR_RGB2BGR)
如果結(jié)果.multi_hand_landmarks:
對(duì)于 results.multi_hand_landmarks 中的 hand_landmarks:
mp_drawing.draw_landmarks(
圖片、hand_landmarks、mp_hands.HAND_CONNECTIONS)
lmList = 手指位置(圖像)
#打印(lmList)
如果 len(lmList) != 0:
手指 = []
對(duì)于范圍內(nèi)的 id(1, 5):
如果 lmList[tipIds[id]][2] < lmList[tipIds[id] - 2][2]:
#state = "播放"
手指.append(1)
如果 (lmList[tipIds[id]][2] > lmList[tipIds[id] - 2][2] ):
# state = "暫停"
# pyautogui.press('空格')
# print("空格")
手指.append(0)
totalFingers = Fingers.count(1)
打?。偸种福?br /> #print(lmList[9][2])
如果 totalFingers == 4:
狀態(tài) = “播放”
# finger.append(1)
如果 totalFingers == 0 并且 state == "Play":
狀態(tài) = “暫停”
pyautogui.press('空格')
打?。ā翱臻g”)
如果 totalFingers == 1:
如果 lmList[8][1]<300:
打印(“左”)
pyautogui.press('左')
如果 lmList[8][1]>400:
打?。ā罢_”)
pyautogui.press('對(duì)')
如果 totalFingers == 2:
如果 lmList[9][2] < 210:
打印(“向上”)
pyautogui.press('向上')
如果 lmList[9][2] > 230:
打?。ā跋蛳隆保?br /> pyautogui.press('向下')
#cv2.putText(image, str("Gesture"), (10,40), cv2.FONT_HERSHEY_SIMPLEX,
# 1, (255, 0, 0), 2)
cv2.imshow("媒體控制器", image)
鍵 = cv2.waitKey(1) & 0xFF
# 如果 `q` 鍵被按下,則退出循環(huán)
如果鍵 == ord("q"):
休息
cv2.destroyAllWindows()
評(píng)論
查看更多