【python】OpenCV—Hand Detection
文章目录
- 1、功能描述
- 2、代码实现
- 3、效果展示
- 4、完整代码
- 5、参考
- 6、其它手部检测和手势识别的方案
更多有趣的代码示例,可参考【Programming】
1、功能描述
基于 opencv-python 和 mediapipe 进行手部检测
2、代码实现
导入必要的库函数
import cv2
import mediapipe as mp
进入主程序首先实例化 HandDetector()
类,读入图片,调用 find_hands
方法实现手部检测
if __name__ == "__main__":
detector = HandDetector()
img = cv2.imread("1.jpg")
img, results = detector.find_hands(img)
HandDetector
类初始化如下,主要是配置好 mediapipe
的手部关键点检测算子以及可视化工具
class HandDetector:
def __init__(self, static_mode=False, max_hands=2, detection_confidence=0.5, tracking_confidence=0.5):
self.static_mode = static_mode
self.max_hands = max_hands
self.detection_confidence = detection_confidence
self.tracking_confidence = tracking_confidence
self.mp_hands = mp.solutions.hands
self.hands = self.mp_hands.Hands(
static_image_mode=static_mode,
max_num_hands=max_hands,
min_detection_confidence=detection_confidence,
min_tracking_confidence=tracking_confidence
)
self.mp_drawing = mp.solutions.drawing_utils
self.mp_drawing_styles = mp.solutions.drawing_styles
find_hands
方法实现如下,用于检测手部关键点,并返回绘制后的图片(mediapipe绘制的)和检测结果
def find_hands(self, img, draw=True):
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.results = self.hands.process(img_rgb)
if self.results.multi_hand_landmarks and draw:
for hand_landmarks in self.results.multi_hand_landmarks:
self.mp_drawing.draw_landmarks(
img,
hand_landmarks,
self.mp_hands.HAND_CONNECTIONS,
self.mp_drawing_styles.get_default_hand_landmarks_style(),
self.mp_drawing_styles.get_default_hand_connections_style()
)
return img, self.results
接下来调用 find_positions
方法,根据手部关键点,找出手部检测框
lm_list, bbox = detector.find_positions(img, hand_index=0)
find_positions
方法实现如下,遍历手部关键点,保存最大最小横纵坐标,在此基础上,外扩(w+h)/ 2 的一定比例,返回关键点列表和手部检测框
def find_positions(self, img, hand_index=0):
h, w, c = img.shape
landmark_list = []
bbox = [0, 0, 0, 0] # x_min, y_min, x_max, y_max
# Check if any hands detected
if not self.results.multi_hand_landmarks:
return landmark_list, bbox
# Check if requested hand index exists
if hand_index >= len(self.results.multi_hand_landmarks):
return landmark_list, bbox
# Extract hand landmarks
hand = self.results.multi_hand_landmarks[hand_index]
# Initialize bounding box coordinates
x_min, y_min = w, h
x_max, y_max = 0, 0
# Process each landmark
for id, lm in enumerate(hand.landmark):
# Convert normalized coordinates to pixel coordinates
cx, cy, cz = int(lm.x * w), int(lm.y * h), lm.z
landmark_list.append([id, cx, cy, cz])
# Update bounding box
x_min = min(x_min, cx)
y_min = min(y_min, cy)
x_max = max(x_max, cx)
y_max = max(y_max, cy)
# Add padding to bounding box
padding = int((y_max - y_min + x_max - x_min) * 0.1 / 2)
bbox = [
max(0, x_min - padding),
max(0, y_min - padding),
min(w, x_max + padding),
min(h, y_max + padding)
]
return landmark_list, bbox
如果检测出来了关键点,调用 get_hand_type
获取检测出来的是左手还是右手,调用 draw_bounding_box
方法绘制手部矩形框
if lm_list:
hand_type = detector.get_hand_type(0)
img = detector.draw_bounding_box(img, bbox, hand_type)
# 绘制某一个关键点
# if len(lm_list) > 8:
# cv2.circle(img, (lm_list[8][1], lm_list[8][2]), 5, (255, 0, 255), cv2.FILLED)
get_hand_type
方法实现如下,调用 mediapipe
的接口获取左手 or 右手
def get_hand_type(self, idx=0):
if not self.results.multi_hand_landmarks:
return None
if idx >= len(self.results.multi_handedness):
return None
# Get hand type from classification
hand_type = self.results.multi_handedness[idx].classification[0].label
return hand_type
draw_bounding_box
方法实现如下,绘制矩形框,写上左手 or 右手标签
def draw_bounding_box(self, img, bbox, hand_label="Hand"):
x_min, y_min, x_max, y_max = bbox
cv2.rectangle(img, (x_min, y_min), (x_max, y_max), (0, 255, 0), 2)
cv2.putText(img, hand_label, (x_min, y_min - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
return img
最后,展示检测结果,保存检测结果,退出后关闭所有窗口
cv2.imshow("Hand Detector", img)
cv2.imwrite("result.jpg", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
3、效果展示
输入图片
输出结果
需要绘制两个手的话改改代码
detector = HandDetector()
img = cv2.imread("2.jpg")
img, results = detector.find_hands(img)
for i in range(2):
lm_list, bbox = detector.find_positions(img, hand_index=i)
if lm_list:
hand_type = detector.get_hand_type(i)
img = detector.draw_bounding_box(img, bbox, hand_type)
# 绘制某一个关键点
# if len(lm_list) > 8:
# cv2.circle(img, (lm_list[8][1], lm_list[8][2]), 5, (255, 0, 255), cv2.FILLED)
cv2.imshow("Hand Detector", img)
cv2.imwrite("result.jpg", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输入图片
输出图片
4、完整代码
import cv2
import mediapipe as mp
class HandDetector:
def __init__(self, static_mode=False, max_hands=2, detection_confidence=0.5, tracking_confidence=0.5):
self.static_mode = static_mode
self.max_hands = max_hands
self.detection_confidence = detection_confidence
self.tracking_confidence = tracking_confidence
self.mp_hands = mp.solutions.hands
self.hands = self.mp_hands.Hands(
static_image_mode=static_mode,
max_num_hands=max_hands,
min_detection_confidence=detection_confidence,
min_tracking_confidence=tracking_confidence
)
self.mp_drawing = mp.solutions.drawing_utils
self.mp_drawing_styles = mp.solutions.drawing_styles
def find_hands(self, img, draw=True):
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.results = self.hands.process(img_rgb)
if self.results.multi_hand_landmarks and draw:
for hand_landmarks in self.results.multi_hand_landmarks:
self.mp_drawing.draw_landmarks(
img,
hand_landmarks,
self.mp_hands.HAND_CONNECTIONS,
self.mp_drawing_styles.get_default_hand_landmarks_style(),
self.mp_drawing_styles.get_default_hand_connections_style()
)
return img, self.results
def find_positions(self, img, hand_index=0):
h, w, c = img.shape
landmark_list = []
bbox = [0, 0, 0, 0] # x_min, y_min, x_max, y_max
# Check if any hands detected
if not self.results.multi_hand_landmarks:
return landmark_list, bbox
# Check if requested hand index exists
if hand_index >= len(self.results.multi_hand_landmarks):
return landmark_list, bbox
# Extract hand landmarks
hand = self.results.multi_hand_landmarks[hand_index]
# Initialize bounding box coordinates
x_min, y_min = w, h
x_max, y_max = 0, 0
# Process each landmark
for id, lm in enumerate(hand.landmark):
# Convert normalized coordinates to pixel coordinates
cx, cy, cz = int(lm.x * w), int(lm.y * h), lm.z
landmark_list.append([id, cx, cy, cz])
# Update bounding box
x_min = min(x_min, cx)
y_min = min(y_min, cy)
x_max = max(x_max, cx)
y_max = max(y_max, cy)
# Add padding to bounding box
padding = int((y_max - y_min + x_max - x_min) * 0.1 / 2)
bbox = [
max(0, x_min - padding),
max(0, y_min - padding),
min(w, x_max + padding),
min(h, y_max + padding)
]
return landmark_list, bbox
def draw_bounding_box(self, img, bbox, hand_label="Hand"):
x_min, y_min, x_max, y_max = bbox
cv2.rectangle(img, (x_min, y_min), (x_max, y_max), (0, 255, 0), 2)
cv2.putText(img, hand_label, (x_min, y_min - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
return img
def get_hand_type(self, idx=0):
if not self.results.multi_hand_landmarks:
return None
if idx >= len(self.results.multi_handedness):
return None
# Get hand type from classification
hand_type = self.results.multi_handedness[idx].classification[0].label
return hand_type
if __name__ == "__main__":
detector = HandDetector()
img = cv2.imread("1.jpg")
img, results = detector.find_hands(img)
lm_list, bbox = detector.find_positions(img, hand_index=0)
if lm_list:
hand_type = detector.get_hand_type(0)
img = detector.draw_bounding_box(img, bbox, hand_type)
# 绘制某一个关键点
# if len(lm_list) > 8:
# cv2.circle(img, (lm_list[8][1], lm_list[8][2]), 5, (255, 0, 255), cv2.FILLED)
cv2.imshow("Hand Detector", img)
cv2.imwrite("result.jpg", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
5、参考
- https://github.com/Sxhail/Hand-Detection-Model/blob/main/hand_detector.py
- 【python】OpenCV—Hand Landmarks Detection
6、其它手部检测和手势识别的方案
手检测:深度图,Tiny YOLOv3
https://github.com/LadaOndris/hand-recognition
It consists of hand detection, hand pose estimation, and gesture classification.
手检测:yolov3、yolov4
https://github.com/cansik/yolo-hand-detection
数据集: CMU Hand DB dataset + Egohands dataset
手检测:检测,朝向
This project utilizes a modified MobileNet in company with the SSD framework to achieve a robust and fast detection of hand location and orientation.
https://github.com/yangli18/hand_detection
手检测:yolov4
https://github.com/ehsainit/yolo-hand-detection
训练数据集 http://vision.soic.indiana.edu/projects/egohands/
手检测:yolov5
https://github.com/siriusdemon/hand-yolov5/tree/main
手检测:多边形矩形框,yolov7,COCO-Hand data.
https://github.com/nuwandda/yolov7-hand-detection?tab=readme-ov-file
https://www3.cs.stonybrook.edu/~cvl/projects/hand_det_attention/
手检测多边形矩形框:https://github.com/SupreethN/Hand-CNN
论文 Contextual Attention for Hand Detection in the Wild, International Conference on Computer Vision (ICCV), 2019. 的源码
忍法:大坝谁修哈
https://github.com/Kazuhito00/NARUTO-HandSignDetection
手势检测:火影忍者,yolov11
https://github.com/Jannat-Javed/Naruto-Hand-Seals-Detection
更多有趣的代码示例,可参考【Programming】