【python】OpenCV—Hand Detection

news2025/3/31 16:44:20

在这里插入图片描述

文章目录

  • 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.coloradmin.cn/o/2323495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flink中聚合算子介绍

前言 在flink api中,聚合算子是非常常用的。所谓的聚合就是在分组的基础上做比较计算的操作。下面通过几个简单案例来说明聚合算子的用法和注意事项。 聚合算子案例 因为flink的api操作流程比较固定,从获取执行环境》获取数据源》执行数据转换操作》输…

【基础】Windows 中通过 VSCode 使用 GCC 编译调试 C++

准备 安装 VSCode 及 C 插件。通过 MSYS2 安装 MinGW-w64 工具链,为您提供必要的工具来编译代码、调试代码并配置它以使用IntelliSense。参考:Windows 中的 Linux 开发工具链 验证安装: gcc --version g --version gdb --version三个核心配…

知识就是力量——物联网应用技术

基础知识篇 一、常用电子元器件1——USB Type C 接口引脚详解特点接口定义作用主从设备关于6P引脚的简介 2——常用通信芯片CH343P概述特点引脚定义 CH340概述特点封装 3——蜂鸣器概述类型驱动电路原文链接 二、常用封装介绍贴片电阻电容封装介绍封装尺寸与功率关系&#xff1…

(windows)conda虚拟环境下open-webui安装与启动

一、创建conda环境 重点强调下,如果用python pip安装,一定要选择python3.11系列版本,我选的3.11.9。 如果你的版本不是这个系列,将会出现一些未知的问题。 conda create -n open-webui python3.11 -y如下就创建好了 二、安装o…

资本运营:基于Python实现的资本运作模拟

基于Python实现的一个简单的资本运营框架; ​企业生命周期演示:观察初创→成长→上市→并购全流程 ​行业对比分析:不同行业的财务特征和估值差异 ​资本运作策略:体验IPO定价、投资决策、并购整合等操作 ​市场动态观察&#xff…

当EFISH-SBC-RK3576遇上区块链:物联网安全与可信数据网络‌

在工业物联网场景中,设备身份伪造与数据篡改是核心安全隐患。‌EFISH-SBC-RK3576‌ 通过 ‌硬件安全模块 区块链链上验证‌,实现设备身份可信锚定与数据全生命周期加密,安全性能提升10倍以上。 1. 安全架构:从芯片到链的端到端防…

分布式系统面试总结:3、分布式锁(和本地锁的区别、特点、常见实现方案)

仅供自学回顾使用,请支持javaGuide原版书籍。 本篇文章涉及到的分布式锁,在本人其他文章中也有涉及。 《JUC:三、两阶段终止模式、死锁的jconsole检测、乐观锁(版本号机制CAS实现)悲观锁》:https://blog.…

【VSCode的安装与配置】

目录: 一:下载 VSCode二:安装 VSCode三:配置 VSCode 一:下载 VSCode 下载地址:https://code.visualstudio.com/download 下载完成之后,在对应的下载目录中可以看到安装程序。 二:安装…

脱围机制-react18废除forwardRef->react19直接使用ref的理解

采用ref&#xff0c;可以在父组件调用到子组件的功能 第一步&#xff1a;在父组件声明ref并传递ref interface SideOptsHandle {refreshData: () > Promise<void> }const sideOptsRef useRef<SideOptsHandle>(null) // 创建 ref<SideOpts ref{sideOptsRef…

Windows中安装git工具

下载好git安装包 点击next 选择安装目录 根据需要去勾选 点击next 点击next PATH环境选择第二个【Git...software】即可&#xff0c;再点击【Next】。 第一种配置是“仅从Git Bash使用Git”。这是最安全的选择&#xff0c;因为您的PATH根本不会被修改。您只能使用 Git Bash 的…

【CSS】CSS 使用全教程

CSS 使用全教程 介绍 CSS&#xff08;层叠样式表&#xff0c;Cascading Style Sheets&#xff09;是一种样式表语言&#xff0c;用于描述 HTML 或 XML 文档的布局和外观&#xff0c;它允许开发者将文档的内容结构与样式表现分离&#xff0c;通过定义一系列的样式规则来控制网页…

全分辨率免ROOT懒人精灵-自动化编程思维-设计思路-实战训练

全分辨率免ROOT懒人精灵-自动化编程思维-设计思路-实战训练 1.2025新版懒人精灵-实战红果搜索关键词刷视频&#xff1a;https://www.bilibili.com/video/BV1eK9kY7EWV 2.懒人精灵-全分辨率节点识别&#xff08;红果看广告领金币小实战&#xff09;&#xff1a;https://www.bili…

如何在IDEA中借助深度思考模型 QwQ 提高编码效率?

通义灵码上新模型选择功能&#xff0c;不仅引入了 DeepSeek 满血版 V3 和 R1 这两大 “新星”&#xff0c;Qwen2.5-Max 和 QWQ 也强势登场&#xff0c;正式加入通义灵码的 “豪华阵容”。开发者只需在通义灵码智能问答窗口的输入框中&#xff0c;单击模型选择的下拉菜单&#x…

LVS的 NAT 模式实验

文章目录 目录 文章目录 概要 IP规划与题目分析 实验步骤 一、nginx配置&#xff08;rs1、rs2、rs3&#xff09; 二、LVS配置 三、客户端配置 四、防火墙和selinux配置 实验结果 痛点解答 概要 LVS/NAT lvs/nat网络地址转换模式&#xff0c;进站/出站的数据流量经过分发器(IP负…

【MacOS】2025年硬核方法清理MacOS中的可清除空间(Purgeable space)

背景 MacOS使用一段时间之后&#xff0c;硬盘空间会越来越少&#xff0c;但自己的文件没有存储那么多&#xff0c;在储存空间中可以发现可用空间明明还剩很多&#xff0c;但磁盘工具却显示已满&#xff0c;见下图。 尝试解决 df -h 命令却发现磁盘已经被快被占满。使用du命…

ue材质学习感想总结笔记

2025 - 3 - 27 1.1 加法 对TexCoord上的每一个像素加上一个值&#xff0c;如果加上0.1&#xff0c;0.1&#xff0c; 那么左上角原来0,0的位置变成了0.1,0.1 右上角就变成了1.1,1.1&#xff0c;那么原来0,0的位置就去到了左上角左上边&#xff0c;所以图像往左上偏移。 总而言…

信而泰PFC/ECN流量测试方案:打造智能无损网络的关键利器

导语&#xff1a; AI算力爆发的背后&#xff0c;如何保障网络“零丢包”&#xff1f; 在当今数据中心网络中&#xff0c;随着AI、高性能计算&#xff08;HPC&#xff09;和分布式存储等应用的飞速发展&#xff0c;网络的无损传输能力变得至关重要。PFC&#xff08;基于优先级的…

CNN和LSTM的计算复杂度分析

前言&#xff1a;今天做边缘计算的时候&#xff0c;在评估模型性能的时候发现NPU计算的大部分时间都花在了LSTM上&#xff0c;使用的是Bi-LSTM&#xff08;耗时占比98%&#xff09;&#xff0c;CNN耗时很短&#xff0c;不禁会思考为什么LSTM会花费这么久时间。 首先声明一下实…

UniApp 表单校验两种方式对比:命令式与声明式

目录 前言1. 实战2. Demo 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 以下主要针对Demo讲解&#xff0c;从实战中的体会 何为命令式 何为声明式 命令式的体验&#xff0c;随时都会有提交的按钮&#xff…

LCR 187. 破冰游戏(python3解法)

难度&#xff1a;简单 社团共有 num 位成员参与破冰游戏&#xff0c;编号为 0 ~ num-1。成员们按照编号顺序围绕圆桌而坐。社长抽取一个数字 target&#xff0c;从 0 号成员起开始计数&#xff0c;排在第 target 位的成员离开圆桌&#xff0c;且成员离开后从下一个成员开始计数…