請將「首次接觸就上手」的LED燈,用Grove的連接線另外接到Arduino開發板的D3,因為D3腳位才支援PWM 控制 (預設的D4 無法 PWM)。當然也可以另外找一顆LED來接。
p.s. PWM腳位除可以接D3外,還有D5、D6、D9、D10、D11,但Arduino程式要改腳位。
#主要程式來源來自:https://www.youtube.com/c/MurtazasWorkshopRoboticsandAI/featured
import serial
import argparse
import cv2
import time
import numpy as np
import math
import mediapipe as mp
########## 手部追蹤偵測 #############
class handDetector():
def __init__(self, mode=False, maxHands=2, detectionCon=0.5, trackCon=0.5):
self.mode = mode
self.maxHands = maxHands
self.detectionCon = detectionCon
self.trackCon = trackCon
self.mpHands = mp.solutions.hands
self.hands = self.mpHands.Hands(self.mode, self.maxHands,
self.detectionCon, self.trackCon)
self.mpDraw = mp.solutions.drawing_utils
def findHands(self, img, draw=True):
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.results = self.hands.process(imgRGB)
# print(results.multi_hand_landmarks)
if self.results.multi_hand_landmarks:
for handLms in self.results.multi_hand_landmarks:
if draw:
self.mpDraw.draw_landmarks(img, handLms,
self.mpHands.HAND_CONNECTIONS)
return img
def findPosition(self, img, handNo=0, draw=True):
lmList = []
if self.results.multi_hand_landmarks:
myHand = self.results.multi_hand_landmarks[handNo]
for id, lm in enumerate(myHand.landmark):
# print(id, lm)
h, w, c = img.shape
cx, cy = int(lm.x * w), int(lm.y * h)
# print(id, cx, cy)
lmList.append( [id, cx, cy])
if draw:
cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
return lmList
def main():
############## 各參數設定 ##################
pTime = 0
minPwm = 0
maxPwm = 255
briArd = 0
briBar = 400
briPer = 0
############## 指定WEBCAM和Arduino Serial Port編號的指令 ##################
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
'--video', help='Video number', required=False, type=int, default=0)
parser.add_argument(
'--com', help='Number of UART prot.', required=True)
args = parser.parse_args()
COM_PORT = 'COM'+str(args.com)
BAUD_RATES = 9600
ser = serial.Serial(COM_PORT, BAUD_RATES)
args = parser.parse_args()
############## WEBCAM相關參數定義 ##################
wCam, hCam = 640, 480
cap = cv2.VideoCapture(args.video) # 攝影機編號預設為0,也可以輸入其他編號!
cap.set(3, wCam)
cap.set(4, hCam)
detector = handDetector(detectionCon=0.7)
try:
while True:
success, img = cap.read()
img = detector.findHands(img)
lmList = detector.findPosition(img, draw=False)
#print(lmList)
if len(lmList) != 0:
x1, y1 = lmList[4][1], lmList[4][2]
x2, y2 = lmList[8][1], lmList[8][2]
cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)
#計算大拇指和食指的直線中點距離
cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)
cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
#計算大拇指和食指的直線距離
length = math.hypot(x2 - x1, y2 - y1)
#print(length)
#將大拇指和食指的直線距離換算成0~255,Arduino PWM控制數值亦為0~255
brightness = np.interp(length, [50, 300], [minPwm, maxPwm])
briBar = np.interp(length, [50, 300], [400, 150])
briArd = np.around(brightness,2)
if length < 50:
cv2.circle(img, (cx, cy), 15, (0, 255, 0), cv2.FILLED)
#畫出直方圖
cv2.rectangle(img,(50,150),(85,400),(255, 0, 255),3)
cv2.rectangle(img,(50, int(briBar)),(85,400),(255, 0, 255),cv2.FILLED)
cv2.putText(img, f'brightness: {int(briArd)}', (15, 140), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 0, 255), 3)
#送出數值給Arduino
ser.write(str(briArd).encode())
#計算每秒跑幾張
cTime = time.time()
fps = 1 / (cTime - pTime)
pTime = cTime
cv2.putText(img, f'FPS: {int(fps)}', (40, 50), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 0, 0), 3)
#顯示畫面
cv2.imshow("HandDetector", img)
#按q停止程式
if cv2.waitKey(10) & 0xFF == ord('q'):
break
except KeyboardInterrupt:
ser.close()
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__' :
main()