ジェスチャ認識シリーズ記事ディレクトリ
ジェスチャー認識とは、人間のジェスチャーを認識することで、コンピューターやスマートフォン、スマートテレビなどの機器の操作・制御を実現する、人間とコンピューターのインタラクション技術です。
1. Opencv はハンド トラッキング (手のキー ポイントの位置を特定) を実装します。
2. opencv実戦プロジェクトはジェスチャートラッキングを実現し位置情報を返す(カプセル化呼び出し)
3.ジェスチャー認識 - ジェスチャー音量制御 (opencv)
4. OpenCV実践プロジェクト ジェスチャ認識 - ジェスチャ制御マウス
5. opencv 戦闘プロジェクト ジェスチャー認識 - 手の距離測定
つづく
このプロジェクトでは、Google のオープンソース フレームワークmediapipeを使用します。これには、顔検出、身体検出、手の検出など、使用できるモデルが多数あります。
コードでは、opencv HandTraqckModule モジュール mediapipe モジュールを使用する必要があります。
1 つ、HandTraqckModule モジュール
今回も引き続き、HandTraqckModule モジュールに新しいコンテンツを追加していきます。すでに知っている場合はスキップして、コピーして貼り付けるだけです。
import cv2
import mediapipe as mp
import math
クラスを定義しますHandDetector
。
class HandDetector:
def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon=0.5):
# 初始化参数
self.mode = mode
self.maxHands = maxHands
self.detectionCon = detectionCon
self.minTrackCon = minTrackCon
# 初始化 Mediapipe 的手部检测模块和绘制工具
self.mpHands = mp.solutions.hands
self.hands = self.mpHands.Hands(static_image_mode=self.mode, max_num_hands=self.maxHands,
min_detection_confidence=self.detectionCon, min_tracking_confidence=self.minTrackCon)
self.mpDraw = mp.solutions.drawing_utils
self.tipIds = [4, 8, 12, 16, 20]
self.fingers = []
self.lmList = []
findHands
画像内の手を検出する方法を定義します。
def findHands(self, img, draw=True, flipType=True):
# 将图像从 BGR 转换为 RGB 格式
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 使用 Mediapipe 进行手部检测
self.results = self.hands.process(imgRGB)
allHands = []
h, w, c = img.shape
if self.results.multi_hand_landmarks:
for handType, handLms in zip(self.results.multi_handedness, self.results.multi_hand_landmarks):
myHand = {}
# 提取关键点的像素坐标并存储在 mylmList 中
mylmList = []
xList = []
yList = []
for id, lm in enumerate(handLms.landmark):
px, py = int(lm.x * w), int(lm.y * h)
mylmList.append([px, py])
xList.append(px)
yList.append(py)
# 计算边界框信息
xmin, xmax = min(xList), max(xList)
ymin, ymax = min(yList), max(yList)
boxW, boxH = xmax - xmin, ymax - ymin
bbox = xmin, ymin, boxW, boxH
cx, cy = bbox[0] + (bbox[2] // 2), bbox[1] + (bbox[3] // 2)
myHand["lmList"] = mylmList
myHand["bbox"] = bbox
myHand["center"] = (cx, cy)
if flipType:
if handType.classification[0].label == "Right":
myHand["type"] = "Left"
else:
myHand["type"] = "Right"
else:
myHand["type"] = handType.classification[0].label
allHands.append(myHand)
# 在图像上绘制手部信息
if draw:
self.mpDraw.draw_landmarks(img, handLms, self.mpHands.HAND_CONNECTIONS)
cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20),
(bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),
(255, 0, 255), 2)
cv2.putText(img, myHand["type"], (bbox[0] - 30, bbox[1] - 30), cv2.FONT_HERSHEY_PLAIN,
2, (255, 0, 255), 2)
if draw:
return allHands, img # 返回检测到的手部信息和绘制后的图像
else:
return allHands # 只返回检测到的手部信息,不进行绘制
fingersUp
開いている指の数を検出するメソッドを定義します。
def fingersUp(self, myHand):
# 获取手部信息
myHandType = myHand["type"]
myLmList = myHand["lmList"]
if self.results.multi_hand_landmarks:
fingers = []
# 检测拇指
if myHandType == "Right":
if myLmList[self.tipIds[0]][0] > myLmList[self.tipIds[0] - 1][0]:
fingers.append(1)
else:
fingers.append(0)
else:
if myLmList[self.tipIds[0]][0] < myLmList[self.tipIds[0] - 1][0]:
fingers.append(1)
else:
fingers.append(0)
# 检测其他手指
for id in range(1, 5):
if myLmList[self.tipIds[id]][1] < myLmList[self.tipIds[id] - 2][1]:
fingers.append(1)
else:
fingers.append(0)
return fingers
最後に、main
関数はHandDetector
クラスを使用して手を検出し、画像内に検出をプロットします。
def main():
cap = cv2.VideoCapture(0)
detector = HandDetector(detectionCon=0.8, maxHands=2)
while True:
# 获取图像帧
success, img = cap.read()
# 检测手部并获取手部信息和绘制后的图像
hands, img = detector.findHands(img)
if hands:
# 处理检测到的手部信息,如关键点、边界框、手型等
# ...
# 显示图像
cv2.imshow("Image", img)
cv2.waitKey(1)
if __name__ == "__main__":
main()
このループでは、プログラムはカメラから画像フレームをキャプチャし、HandDetector
クラスを使用して手を検出し、検出結果をプロットします。コードを追加して手の情報を取得し、必要に応じて処理できます。
すべてのコード
"""
Hand Tracking Module
By: Computer Vision Zone
Website: https://www.computervision.zone/
"""
import cv2
import mediapipe as mp
import math
class HandDetector:
"""
Finds Hands using the mediapipe library. Exports the landmarks
in pixel format. Adds extra functionalities like finding how
many fingers are up or the distance between two fingers. Also
provides bounding box info of the hand found.
"""
def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon=0.5):
"""
:param mode: In static mode, detection is done on each image: slower
:param maxHands: Maximum number of hands to detect
:param detectionCon: Minimum Detection Confidence Threshold
:param minTrackCon: Minimum Tracking Confidence Threshold
"""
self.mode = mode
self.maxHands = maxHands
self.detectionCon = detectionCon
self.minTrackCon = minTrackCon
self.mpHands = mp.solutions.hands
self.hands = self.mpHands.Hands(static_image_mode=self.mode, max_num_hands=self.maxHands,
min_detection_confidence=self.detectionCon, min_tracking_confidence = self.minTrackCon)
self.mpDraw = mp.solutions.drawing_utils
self.tipIds = [4, 8, 12, 16, 20]
self.fingers = []
self.lmList = []
def findHands(self, img, draw=True, flipType=True):
"""
Finds hands in a BGR image.
:param img: Image to find the hands in.
:param draw: Flag to draw the output on the image.
:return: Image with or without drawings
"""
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.results = self.hands.process(imgRGB)
allHands = []
h, w, c = img.shape
if self.results.multi_hand_landmarks:
for handType,handLms in zip(self.results.multi_handedness,self.results.multi_hand_landmarks):
myHand={}
## lmList
mylmList = []
xList = []
yList = []
for id, lm in enumerate(handLms.landmark):
px, py = int(lm.x * w), int(lm.y * h)
mylmList.append([px, py])
xList.append(px)
yList.append(py)
## bbox
xmin, xmax = min(xList), max(xList)
ymin, ymax = min(yList), max(yList)
boxW, boxH = xmax - xmin, ymax - ymin
bbox = xmin, ymin, boxW, boxH
cx, cy = bbox[0] + (bbox[2] // 2), \
bbox[1] + (bbox[3] // 2)
myHand["lmList"] = mylmList
myHand["bbox"] = bbox
myHand["center"] = (cx, cy)
if flipType:
if handType.classification[0].label =="Right":
myHand["type"] = "Left"
else:
myHand["type"] = "Right"
else:myHand["type"] = handType.classification[0].label
allHands.append(myHand)
## draw
if draw:
self.mpDraw.draw_landmarks(img, handLms,
self.mpHands.HAND_CONNECTIONS)
cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20),
(bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),
(255, 0, 255), 2)
cv2.putText(img,myHand["type"],(bbox[0] - 30, bbox[1] - 30),cv2.FONT_HERSHEY_PLAIN,
2,(255, 0, 255),2)
if draw:
return allHands,img
else:
return allHands
def fingersUp(self,myHand):
"""
Finds how many fingers are open and returns in a list.
Considers left and right hands separately
:return: List of which fingers are up
"""
myHandType =myHand["type"]
myLmList = myHand["lmList"]
if self.results.multi_hand_landmarks:
fingers = []
# Thumb
if myHandType == "Right":
if myLmList[self.tipIds[0]][0] > myLmList[self.tipIds[0] - 1][0]:
fingers.append(1)
else:
fingers.append(0)
else:
if myLmList[self.tipIds[0]][0] < myLmList[self.tipIds[0] - 1][0]:
fingers.append(1)
else:
fingers.append(0)
# 4 Fingers
for id in range(1, 5):
if myLmList[self.tipIds[id]][1] < myLmList[self.tipIds[id] - 2][1]:
fingers.append(1)
else:
fingers.append(0)
return fingers
def main():
cap = cv2.VideoCapture(0)
detector = HandDetector(detectionCon=0.8, maxHands=2)
while True:
# Get image frame
success, img = cap.read()
# Find the hand and its landmarks
hands, img = detector.findHands(img) # with draw
# hands = detector.findHands(img, draw=False) # without draw
if hands:
# Hand 1
hand1 = hands[0]
lmList1 = hand1["lmList"] # List of 21 Landmark points
bbox1 = hand1["bbox"] # Bounding box info x,y,w,h
centerPoint1 = hand1['center'] # center of the hand cx,cy
handType1 = hand1["type"] # Handtype Left or Right
fingers1 = detector.fingersUp(hand1)
if len(hands) == 2:
# Hand 2
hand2 = hands[1]
lmList2 = hand2["lmList"] # List of 21 Landmark points
bbox2 = hand2["bbox"] # Bounding box info x,y,w,h
centerPoint2 = hand2['center'] # center of the hand cx,cy
handType2 = hand2["type"] # Hand Type "Left" or "Right"
fingers2 = detector.fingersUp(hand2)
# Find Distance between two Landmarks. Could be same hand or different hands
length, info, img = detector.findDistance(lmList1[8], lmList2[8], img) # with draw
# length, info = detector.findDistance(lmList1[8], lmList2[8]) # with draw
# Display
cv2.imshow("Image", img)
cv2.waitKey(1)
if __name__ == "__main__":
main()
- - - - - - - - - - - - - - - - - - - - 分割線 - - - - ---------------------
今回の手検出モジュールでは、位置検出を最適化し、手検出モジュールに統合しました。
2.メインモジュール
アイデアは次のとおりです: 2 つのキーポイント 5 と 17 の位置情報を計算し、2 点間のユークリッド距離を計算します。この距離は手の動きと図に示すピクセル距離によって変化します。部品を測定します。位置変化情報を順番に取得し、位置変化関係に合わせて関数を設計します。(もちろん、人によって手のひらは異なります。これはおおよその距離であり、誤差は約 3% です)
次はメインモジュールのコードです
必要なライブラリとモジュールをインポートします。
import cv2
from HandTrackingModule import HandDetector
import math
import numpy as np
import cvzone
カメラパラメータと手検出器を設定します。
cap = cv2.VideoCapture(0)
cap.set(3, 1280) # 设置摄像头宽度
cap.set(4, 720) # 设置摄像头高度
detector = HandDetector(detectionCon=0.8, maxHands=1) # 创建 HandDetector 实例
手の距離をセンチメートル値にマッピングする関数を定義します。
# Find Function
x = [300, 245, 200, 170, 145, 130, 112, 103, 93, 87, 80, 75, 70, 67, 62, 59, 57]
y = [20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]
coff = np.polyfit(x, y, 2) # 使用二次多项式拟合数据,得到系数 A, B, C
メイン ループに入り、リアルタイム カメラ画像を処理します。
while True:
success, img = cap.read()
hands = detector.findHands(img, draw=False) # 在图像中检测手部,不进行绘制
if hands:
# 获取手部信息
lmList = hands[0]['lmList'] # 关键点列表
x, y, w, h = hands[0]['bbox'] # 边界框坐标和尺寸
x1, y1 = lmList[5] # 大拇指第一个关键点的坐标
x2, y2 = lmList[17] # 小指最后一个关键点的坐标
# 计算两点之间的欧几里得距离
distance = int(math.sqrt((y2 - y1) ** 2 + (x2 - x1) ** 2))
# 将距离映射到厘米值
A, B, C = coff
distanceCM = A * distance ** 2 + B * distance + C
# 在图像中绘制边界框和距离信息
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 255), 3)
cvzone.putTextRect(img, f'{int(distanceCM)} cm', (x+5, y-10))
cv2.imshow("Image", img)
cv2.waitKey(1) # 按下任意按键退出循环
このコード ブロックの主な目的は、カメラを使用してリアルタイムで画像をキャプチャし、クラスを使用してHandDetector
手を検出し、2 つのキーポイント間の距離を計算し、距離をセンチメートル値にマッピングして、境界ボックスと距離を描画することです。画像の情報。最後に、cv2.imshow
ウィンドウに描画結果を表示することで、 を使用してcv2.waitKey
キーボード入力を待機して処理し、プログラムの実行を継続できます。
すべてのコード
import cv2
from HandTrackingModule import HandDetector
import math
import numpy as np
import cvzone
# Webcam
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)
# Hand Detector
detector = HandDetector(detectionCon=0.8, maxHands=1)
# Find Function
# x is the raw distance y is the value in cm
x = [300, 245, 200, 170, 145, 130, 112, 103, 93, 87, 80, 75, 70, 67, 62, 59, 57]
y = [20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]
coff = np.polyfit(x, y, 2) # y = Ax^2 + Bx + C
# Loop
while True:
success, img = cap.read()
hands = detector.findHands(img, draw=False)
if hands:
lmList = hands[0]['lmList']
x, y, w, h = hands[0]['bbox']
x1, y1 = lmList[5]
x2, y2 = lmList[17]
distance = int(math.sqrt((y2 - y1) ** 2 + (x2 - x1) ** 2))
A, B, C = coff
distanceCM = A * distance ** 2 + B * distance + C
# print(distanceCM, distance)
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 255), 3)
cvzone.putTextRect(img, f'{int(distanceCM)} cm', (x+5, y-10))
cv2.imshow("Image", img)
cv2.waitKey(1)
問題がある場合は、コメント欄にメッセージを残してください