当前位置: 首页 > article >正文

【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】


http://www.kler.cn/a/599218.html

相关文章:

  • 内网(域)渗透测试流程和模拟测试day--1--信息收集阶段
  • 具身系列——NLP工程师切入机器人和具身智能方向
  • 如何让机器像人类一样感知声调颤抖与嘴角抽动的同步情感表达?
  • MySQL InnoDB行锁等待时间是怎么引起的?
  • 腾讯云HAI1元体验:DeepSeek-R1模型助力个人博客快速搭建
  • 使用python numpy计算并显示音频数据的频谱信息
  • 内核编程十:进程的虚拟地址空间
  • 机器学习之条件概率
  • 金牛区国际数字影像产业园:文创核心功能深度剖析
  • 【科研工具使用】latex如何插入图片、分段落、插入公式
  • Python实现MySQL数据库对象的血缘分析
  • 智慧路灯杆:点亮未来城市的科技基石
  • 架构思维:通用系统设计方法论_从复杂度分析到技术实现指南
  • mysql入门操作
  • 多线程 --- 进程和线程的基本知识
  • 图解AUTOSAR_SWS_WatchdogInterface
  • Bash语言的物联网
  • python基础之--包和模块
  • 【简单学习】Prompt Engineering 提示词工程
  • FACTR赋能Franka机器人:触觉-视觉融合决策的颠覆性突破