MediaPipe+UNO手勢控制伺服馬達
tags: mediapipe
arduino
servo
參考視頻網址:
MediaPipe
簡單來說是google跨平台而且開源的機器學習運用
MediaPipe是一款由Google開發並開源的數據流處理機器學習應用開發框架。它是一個基於圖的數據處理管線,用於構建使用了多種形式的數據源,如視頻、音頻、傳感器數據以及任何時間序列數據。 MediaPipe是跨平台的,可以運行在嵌入式平台(樹莓派等),移動設備(iOS和Android),工作站和服務器上,並支持移動端GPU加速。使用MediaPipe,可以將機器學習任務構建為一個圖形的模塊表示的數據流管道,可以包括推理模型和流媒體處理功能。
pinpong
pinpong庫是一套控制開源硬件主控板的Python庫
,基於Firmata協議並兼容MicroPython語法,5分鐘即可讓你上手使用Python控制開源硬件。
有興趣可以到pinpong官網看一下,
我是使用pycharm,所以首先安裝opencv-python,mediapipe和pinpong這兩個主要的程式庫
步驟1:
先把這個程式庫命名為handutil.py和主程式放一起
import cv2
import mediapipe as mp
class HandDetector():
'''
手势识别类
'''
def _init_(self, mode=False, max_hands=2, detection_con=0.5, track_con=0.5):
'''
初始化
:param mode: 是否静态图片,默认为False
:param max_hands: 最多几只手,默认为2只
:param detection_con: 最小检测信度值,默认为0.5
:param track_con: 最小跟踪信度值,默认为0.5
'''
self.mode = mode
self.max_hands = max_hands
self.detection_con = detection_con
self.track_con = track_con
self.hands = mp.solutions.hands.Hands(self.mode, self.max_hands, self.detection_con, self.track_con)
def find_hands(self, img, draw=True):
'''
检测手势
:param img: 视频帧图片
:param draw: 是否画出手势中的节点和连接图
:return: 处理过的视频帧图片
''' imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 处理图片,检测是否有手势,将数据存进self.results中
self.results = self.hands.process(imgRGB)
if draw:
if self.results.multi_hand_landmarks:
for handlms in self.results.multi_hand_landmarks:
mp.solutions.drawing_utils.draw_landmarks(img, handlms, mp.solutions.hands.HAND_CONNECTIONS)
return img
def find_positions(self, img, hand_no=0):
'''
获取手势数据
:param img: 视频帧图片
:param hand_no: 手编号(默认第1只手)
:return: 手势数据列表,每个数据成员由id, x, y组成,代码这个手势位置编号以及在屏幕中的位置
'''
self.lmslist = []
if self.results.multi_hand_landmarks:
hand = self.results.multi_hand_landmarks[hand_no]
for id, lm in enumerate(hand.landmark):
h, w, c = img.shape
cx, cy = int(lm.x * w), int(lm.y * h)
self.lmslist.append([id, cx, cy])
return self.lmslist
步驟2:
複制貼上主程式
*這裡留意一下計算斜角轉成角度的公式
算出角度:
假如两点坐标分别是(x1,y1)(x2,y2)
那么斜率是:(y2-y1)/(x2-x1)
k=(y2-y1)/(x2-x1) 其中(x1,y1),(x2,y2) 是已知两点的坐标
已知A(x1,y1),B(x2,y2)
1、若x1=x2,则斜率不存在;
2、若x1≠x2,则斜率k=(y2-y1)/(x2-x1)
算出弧度:
import math
math.degrees(x)
**x為一個值**
import cv2
from HandTrackingMoudle import handDetector
import math
import numpy as np
from pinpong.board import Board, Pin, Servo
import time
Board("uno").begin()
myServo = Servo(Pin(Pin.A0))
cap = cv2.VideoCapture(0)
detector = handDetector()
angle = 0
while True:
success, img = cap.read()
img = detector.findHands(img, draw=True)
lmList = detector.findPosition(img, personDraw=False)
if len(lmList) > 0:
print(lmList[4], lmList[8])
x1, y1 = lmList[4][1], lmList[4][2]
x2, y2 = lmList[8][1], lmList[8][2]
cv2.circle(img, (x1, y1), 15, (200, 10, 100), cv2.FILLED)
cv2.circle(img, (x2, y2), 15, (200, 10, 100), cv2.FILLED)
cv2.line(img, (x1, y1), (x2, y2), (200, 10, 100), 4)
if (x1 - x2) != 0:
angle = math.degrees(np.arctan((y2 - y1)/(x2 - x1)))
a = 180 - angle
myServo.write_angle(int(a))
print(int(a))
if angle < 0:
angle = abs(angle)
myServo.write_angle(int(angle))
print(int(angle))
cv2.imshow("Image", img)
cv2.waitKey(1)