使用 MediaPipe 实现实时手部追踪和手势识别 | Rerun展示

news2024/11/18 1:22:36

点击下方卡片,关注“小白玩转Python”公众号

在本文中,我将展示一个使用 MediaPipe Python 和 Rerun SDK 进行手部追踪和手势识别的示例。如果您有兴趣深入了解并扩展您的知识,我将指导您如何安装 MediaPipe Python 和 Rerun SDK 来进行手部追踪、识别不同手势并可视化数据。因此,您将学习到:

  • 如何安装 MediaPipe Python 和 Rerun

  • 如何使用 MediaPipe 进行手部追踪和手势识别

  • 如何在 Rerun Viewer 中可视化手部追踪和手势识别的结果


手部追踪和手势识别技术

在开始之前,让我们感谢使这一技术成为可能的科技。手部追踪和手势识别技术旨在使设备能够将手部动作和手势解释为命令或输入。这项技术的核心是一个预训练的机器学习模型,它分析视觉输入并识别手部标志和手势。这种技术的实际应用非常广泛,因为手部动作和手势可以用于控制智能设备。人机交互、机器人技术、游戏和增强现实是该技术最有前途的应用领域之一。

然而,我们应始终注意如何使用这项技术。在敏感和关键系统中使用它非常具有挑战性,因为模型可能会误解手势,并且产生误报的可能性并不小。利用这项技术会带来伦理和法律挑战,因为用户可能不希望他们的手势在公共场所被记录。如果您打算在实际场景中实现这项技术,务必要考虑任何伦理和法律问题。

先决条件与设置

首先,您需要安装必要的库,包括 OpenCV、MediaPipe 和 Rerun。MediaPipe Python 是一个方便的工具,适合开发者在设备上集成计算机视觉和机器学习解决方案,而 Rerun 是一个可视化随时间变化的多模态数据的 SDK。

# Install the required Python packages specified in the requirements file
pip install -r examples/python/gesture_detection/requirements.txt

然后,您需要从这里下载预定义模型:HandGestureClassifier。

使用 MediaPipe 进行手部追踪和手势识别

05b935717d05652109037dcd9f273aa5.png

根据 Google 的手势识别任务指南:“MediaPipe 手势识别任务可以让您实时识别手势,并提供识别的手势结果以及检测到的手部标志。您可以使用此任务从用户那里识别特定手势,并调用与这些手势对应的应用程序功能。”

现在,让我们尝试使用 MediaPipe 预训练模型进行手势识别的示例图像。总体来说,下面的代码为初始化和配置 MediaPipe 手势识别解决方案奠定了基础。

from mediapipe.tasks.python import vision
from mediapipe.tasks import python


class GestureDetectorLogger:


    def __init__(self, video_mode: bool = False):
        self._video_mode = video_mode


        base_options = python.BaseOptions(
            model_asset_path='gesture_recognizer.task'
        )
        options = vision.GestureRecognizerOptions(
            base_options=base_options,
            running_mode=mp.tasks.vision.RunningMode.VIDEO if self._video_mode else mp.tasks.vision.RunningMode.IMAGE
        )
        self.recognizer = vision.GestureRecognizer.create_from_options(options)




    def detect(self, image: npt.NDArray[np.uint8]) -> None:
          image = mp.Image(image_format=mp.ImageFormat.SRGB, data=image)


          # Get results from Gesture Detection model
          recognition_result = self.recognizer.recognize(image)


          for i, gesture in enumerate(recognition_result.gestures):
              # Get the top gesture from the recognition result
              print("Top Gesture Result: ", gesture[0].category_name)


          if recognition_result.hand_landmarks:
              # Obtain hand landmarks from MediaPipe
              hand_landmarks = recognition_result.hand_landmarks
              print("Hand Landmarks: " + str(hand_landmarks))


              # Obtain hand connections from MediaPipe
              mp_hands_connections = mp.solutions.hands.HAND_CONNECTIONS
              print("Hand Connections: " + str(mp_hands_connections))

GestureDetectorLogger 类中的 detect 函数接受一张图片作为其参数,并打印出模型的结果,突出显示识别出的顶部手势和检测到的手部标志点。有关模型的更多详细信息,请参考其模型卡。

您可以使用以下代码自行尝试:

def run_from_sample_image(path)-> None:
    image = cv2.imread(str(path))
    show_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    logger = GestureDetectorLogger(video_mode=False)
    logger.detect_and_log(show_image)


# Run the gesture recognition on a sample image
run_from_sample_image(SAMPLE_IMAGE_PATH)


使用 Rerun 进行验证、调试和演示

这一步允许您确保解决方案的可靠性和有效性。现在模型已经准备好,可以可视化结果以验证准确性、调试潜在问题,并展示其功能。使用 Rerun SDK 可视化结果既简单又快速。

如何使用 Rerun?

  1. 使用 Rerun SDK 从代码中记录多模态数据流

  2. 可视化并与本地或远程的实时或录制的流进行交互

  3. 交互式构建布局和自定义可视化

  4. 在需要时扩展 Rerun

在编写代码之前,您应该访问安装 Rerun Viewer 页面以安装 Viewer。然后,我强烈建议通过阅读 Python 快速入门和在 Python 中记录数据的指南来熟悉 Rerun SDK。这些初始步骤将确保设置顺利,并帮助您开始即将进行的代码实现。

从视频或实时运行

对于视频流,我们使用 OpenCV。您可以选择特定视频的文件路径,或通过提供参数 0 或 1 访问自己的摄像头(使用 0 表示默认摄像头;在 Mac 上,您可能需要使用 1)。

特别要强调的是时间线的引入。Rerun 时间线功能使得能够将数据与一个或多个时间线相关联。因此,视频的每一帧都与其对应的时间戳相关联。

def run_from_video_capture(vid: int | str, max_frame_count: int | None) -> None:
    """
    Run the detector on a video stream.


    Parameters
    ----------
    vid:
        The video stream to run the detector on. Use 0/1 for the default camera or a path to a video file.
    max_frame_count:
        The maximum number of frames to process. If None, process all frames.
    """
    cap = cv2.VideoCapture(vid)
    fps = cap.get(cv2.CAP_PROP_FPS)


    detector = GestureDetectorLogger(video_mode=True)


    try:
        it: Iterable[int] = itertools.count() if max_frame_count is None else range(max_frame_count)


        for frame_idx in tqdm.tqdm(it, desc="Processing frames"):
            ret, frame = cap.read()
            if not ret:
                break


            if np.all(frame == 0):
                continue


            frame_time_nano = int(cap.get(cv2.CAP_PROP_POS_MSEC) * 1e6)
            if frame_time_nano == 0:
                frame_time_nano = int(frame_idx * 1000 / fps * 1e6)


            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)


            rr.set_time_sequence("frame_nr", frame_idx)
            rr.set_time_nanos("frame_time", frame_time_nano)
            detector.detect_and_log(frame, frame_time_nano)
            rr.log(
                "Media/Video",
                rr.Image(frame)
            )


    except KeyboardInterrupt:
        pass


    cap.release()
    cv2.destroyAllWindows()

记录数据进行可视化

ccaa7dab95ccf81a9b9ee20183252177.png

在 Rerun Viewer 中可视化数据,使用 Rerun SDK 记录数据至关重要。之前提到的指南提供了这个过程的见解。在这种情况下,我们提取手部标志点作为规范化值,然后使用图像的宽度和高度将其转换为图像坐标。这些坐标随后作为 2D 点记录到 Rerun SDK 中。此外,我们识别标志点之间的连接,并将它们作为 2D 线段记录。

对于手势识别,结果会打印到控制台。然而,在源代码中,您可以探索一种使用 TextDocument 和表情符号将这些结果呈现给查看器的方法。

class GestureDetectorLogger:


    def detect_and_log(self, image: npt.NDArray[np.uint8], frame_time_nano: int | None) -> None:
        # Recognize gestures in the image
        height, width, _ = image.shape
        image = mp.Image(image_format=mp.ImageFormat.SRGB, data=image)


        recognition_result = (
            self.recognizer.recognize_for_video(image, int(frame_time_nano / 1e6))
            if self._video_mode
            else self.recognizer.recognize(image)
        )


        # Clear the values
        for log_key in ["Media/Points", "Media/Connections"]:
            rr.log(log_key, rr.Clear(recursive=True))


        for i, gesture in enumerate(recognition_result.gestures):
            # Get the top gesture from the recognition result
            gesture_category = gesture[0].category_name if recognition_result.gestures else "None"
            print("Gesture Category: ", gesture_category) # Log the detected gesture


        if recognition_result.hand_landmarks:
            hand_landmarks = recognition_result.hand_landmarks


            # Convert normalized coordinates to image coordinates
            points = self.convert_landmarks_to_image_coordinates(hand_landmarks, width, height)


            # Log points to the image and Hand Entity
            rr.log(
               "Media/Points",
                rr.Points2D(points, radii=10, colors=[255, 0, 0])
            )


            # Obtain hand connections from MediaPipe
            mp_hands_connections = mp.solutions.hands.HAND_CONNECTIONS
            points1 = [points[connection[0]] for connection in mp_hands_connections]
            points2 = [points[connection[1]] for connection in mp_hands_connections]


            # Log connections to the image and Hand Entity 
            rr.log(
               "Media/Connections",
                rr.LineStrips2D(
                   np.stack((points1, points2), axis=1),
                   colors=[255, 165, 0]
                )
             )


    def convert_landmarks_to_image_coordinates(hand_landmarks, width, height):
        return [(int(lm.x * width), int(lm.y * height)) for hand_landmark in hand_landmarks for lm in hand_landmark]


3D 点

最后,我们检查如何将手部标志呈现为 3D 点。我们首先在 init 函数中使用 Annotation Context 定义点之间的连接,然后将它们记录为 3D 点。

class GestureDetectorLogger:
–


  def __init__(self, video_mode: bool = False):
      # ... existing code ...
      rr.log(
            "/",
            rr.AnnotationContext(
                rr.ClassDescription(
                    info=rr.AnnotationInfo(id=0, label="Hand3D"),
                    keypoint_connections=mp.solutions.hands.HAND_CONNECTIONS
                )
            ),
            timeless=True,
        )
       rr.log("Hand3D", rr.ViewCoordinates.RIGHT_HAND_X_DOWN, timeless=True)




   def detect_and_log(self, image: npt.NDArray[np.uint8], frame_time_nano: int | None) -> None:
      # ... existing code ...


      if recognition_result.hand_landmarks:
         hand_landmarks = recognition_result.hand_landmarks


         landmark_positions_3d = self.convert_landmarks_to_3d(hand_landmarks)
         if landmark_positions_3d is not None:
              rr.log(
                 "Hand3D/Points",
                 rr.Points3D(landmark_positions_3d, radii=20, class_ids=0, keypoint_ids=[i for i in range(len(landmark_positions_3d))]),
              )


      # ... existing code ...

详细代码可以参考:https://github.com/rerun-io/rerun

·  END  ·

HAPPY LIFE

db1829df6e622c882be54077c5554486.png

本文仅供学习交流使用,如有侵权请联系作者删除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1864283.html

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

相关文章

web前端课程大作业-高校学生事务中心

文章目录 概述代码页面截图代码链接 概述 仿制高校的学生事务中心&#xff0c;一个登录和注册页面 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" conten…

计算机毕业设计Thinkphp/Laravel智能道路交通管理系统4ir8r

Laravel非常的简洁并且是开源的&#xff0c;Laravel 是一个具有表现力、优雅语法的 Web 应用程序框架. Laravel 是构建现代全栈 Web 应用程序的最佳选择. 它的语法更富有表现力&#xff0c;拥有高质量的文档和丰富的扩展包&#xff0c;技术上它有Bundle扩展包、Eloquent ORM、反…

报道 | 2024年7月-2024年9月国际运筹优化会议汇总

封面图来源&#xff1a; https://www.pexels.com/zh-cn/photo/1181406/ 2024年7月-2024年9月召开会议汇总&#xff1a; 2024 INFORMS Advances in Decision Analysis Conference (ADA) Location: Finland Important Dates: Conference: July 10-12, 2024 Details:https://w…

聚星文社官网

推文工具可以帮助你将小说内容简洁明了地转化为推文形式&#xff0c;以便更好地在社交媒体上进行宣传和推广。以下是一些建议的小说推文工具&#xff1a; 聚星文社 字数统计工具&#xff1a;使用字数统计工具&#xff0c;如Microsoft Word或在线字数统计器&#xff0c;来确保你…

【AIGC】《AI-Generated Content (AIGC): A Survey》

文章目录 相关概念What is AI-generated content?Necessary conditions of AIGCHow can AI make the content better?The industrial chain of AIGCAdvantages of large-scale pre-trained modelsGeneration of smart textPros of AIGCCons of AIGCAIGC and Metaverse 挑战潜…

第 11 课:组件介绍与自定义开发

本讲主要介绍了隐语的组件标准、已有的组件能力以及进一步的自定义开发流程。经过本讲的学习&#xff0c;可以为将隐语集成到任意调度系统&#xff0c;基于Kusica/SecretPad进行二次开发&#xff0c;以及参与隐语开放标准共建建立基础。 一、隐语开放标准 隐语提出的适用于隐私…

Sora:探索AI视频模型的无限可能

随着人工智能技术的飞速发展&#xff0c;AI在视频处理和生成领域的应用正变得越来越广泛。Sora&#xff0c;作为新一代AI视频模型&#xff0c;展示了前所未有的潜力和创新能力。本文将深入探讨Sora的功能、应用场景以及它所带来的革命性变化。 一、Sora的核心功能 1.1 视频生…

java类的加载 ,类加载器以及双亲委派机制详细介绍

1_类的加载 路径 类的加载过程类的加载时机 类的加载 当程序在运行后&#xff0c;第一次使用某个类的时候&#xff0c;会将此类的class文件读取到内存&#xff0c;并将此类的所有信息存储到一个Class对象中 说明&#xff1a;Class对象是指java.lang.Class类的对象&#xff0c…

Orangepi Zero2使用外设驱动库wiringOP驱动蜂鸣器

目录 一、安装外设驱动库 1.1 wiringPi外设SDK安装&#xff1a; 二、使用wiringOP库驱动蜂鸣器 2.1 蜂鸣器的硬件连接&#xff1a; 2.2 使用wiringOP库实现蜂鸣器滴滴响&#xff1a; 2.3 设置vim代码显示格式&#xff1a; 一、安装外设驱动库 1.1 wiringPi外设SDK安装&a…

讨论stl链表

讨论链表 list迭代器失效list的模拟实现创建结点类链表迭代器完成实现代码 list与vector 链表是一个序列容器&#xff0c;在任意位置都可以用常数时间插入或者删除&#xff0c;并且可以在两个方向进行迭代。 list迭代器失效 迭代器失效指迭代器所指向的结点无效&#xff0c;即该…

windows@局域网或蓝牙文件传输@共享文件夹@就近共享

文章目录 windows系统下的简单共享文件方案&#x1f47a;就近共享设置共享文件夹(推荐)方法1:使用shrpubw程序引导创建方法2:使用图形界面创建右键设置共享文件夹 查看所有已经共享的文件夹&#x1f47a;停止某个文件的共享 共享文件夹的访问控制补充匿名访问问题&#x1f60a;…

JFrame和JScrollPanel布局初步使用

还不是很了解&#xff0c;做了几个程序&#xff1b; import java.awt.Container; import java.awt.Color; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.border.EmptyBorder;public class pa1 {public static void main(String[] agrs){JF…

一个多文件工程的例子

代码; main.c #include <stdio.h> #include "add.h" #include "sub.h"int main(void) {int a10,b12;float x1.23456,y9.87654321;printf("int ab IS :%d\n",add_int(a,b));printf("int a-b IS :%d\n",sub_int(a,b));printf(&q…

STM32 中断和事件的区别

原文 简述 上图蓝线为中断的处理过程&#xff0c;红线是事件处理过程。 区别 中断&#xff08;Interrupts&#xff09;&#xff1a; 简述&#xff1a;当发生中断请求后&#xff0c;CPU暂停当前任务&#xff0c;进入对应的中断服务函数&#xff0c;完成后再回到原来暂停的地方…

IP地址专用SSL证书申请指南

IP地址SSL证书是一种专门设计用于IP地址的SSL/TLS证书&#xff0c;部署IP地址SSL证书可以实现IP地址HTTPS加密。 一&#xff1a;前提条件 1&#xff1a;申请IP地址SSL证书,必须拥有这个IP地址的管理权限 2 &#xff1a;80、443、22、端口中任一个可以短暂开放 二&#xff1…

rtthread stm32h743的使用(十)i2c设备使用

我们要在rtthread studio 开发环境中建立stm32h743xih6芯片的工程。我们使用一块stm32h743及fpga的核心板完成相关实验&#xff0c;核心板如图&#xff1a; 1.建立新工程&#xff0c;选择相应的芯片型号及debug引脚及调试器 2.打开cubemux&#xff0c;设置外部时钟及串口外设…

Java文件操作小项目-带GUI界面统计文件夹内文件类型及大小

引言 在Java编程中&#xff0c;文件操作是一项基本且常见的任务。我们经常需要处理文件和文件夹&#xff0c;例如读取、写入、删除文件&#xff0c;或者遍历文件夹中的文件等。本文将介绍如何使用Java的File类和相关API来统计一个文件夹中不同类型文件的数量和大小。 准备工作…

气膜体育馆的使用年限有多少—轻空间

气膜体育馆作为一种新兴的建筑形式&#xff0c;因其独特的结构和功能而备受青睐。它不仅在建设速度、成本控制和环保方面具有显著优势&#xff0c;还在使用年限上展现出良好的性能。轻空间将探讨气膜体育馆的使用年限及其影响因素。 气膜体育馆的基本结构 气膜体育馆主要由膜材…

我教你做不花钱的SEO

我教你做不花钱的SEO **SEO&#xff08;搜索引擎优化&#xff09;投入不一定有产出**不花钱的SEO标题标签元描述标题标签URL结构图片优化内容优化内部链接外部链接结构化数据页面速度优化移动友好性社交媒体整合 结论 SEO&#xff08;搜索引擎优化&#xff09;投入不一定有产出…

Sql审核平台Archery的搭建和简单配置

Sql审核平台Archery的搭建和简单配置 Archery是一个开源的Web应用&#xff0c;基于Python开发&#xff0c;利用Flask作为后端框架&#xff0c;前端采用Vue.js&#xff0c;构建了一个现代化的数据操作界面。提供了SQL审核、数据查询、报表生成等功能&#xff0c;同时支持多种数据…