实现基于Mediapipe的手部关键点三维实时检测

释放双眼,带上耳机,听听看~!
学习如何使用Mediapipe实现基于三维手部关键点的实时检测,探索计算机视觉和深度学习在手势控制中的应用。

本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!

beginning

   
不知道小伙伴们有没有用手势控制各种智能设备的体验,例如,通过手势来控制智能电视的界面、音量和频道;在虚拟现实游戏中,使用手势释放技能、抓取物品等;在医疗康复中,通过手势帮助康复患者进行手部运动训练,这些都是三维手部关键点检测技术在我们生活中的应用。今天呢就带领大家从零上手,实现基于Mediapipe的手部关键点三维实时检测,通过计算机视觉和深度学习,智能定位出21个手部关键点的三维坐标,实现手势控制、手语翻译、动作捕捉、穴位定位、增强现实人机交互等高大上的前沿黑科技。废话不多说啦,如果你也对此感兴趣,想一睹它的风采,让我们一起愉快的学习叭🎈🎈🎈

本文盆友们能学到:

  • 体验Web网页三维手部关键点实时检测的Demo
  • 读取图像文件,输入模型,获取21个关键点和手部骨骼,可视化
  • 用电脑摄像头实时检测,获取21个关键点和手部骨骼,可视化。

实现基于Mediapipe的手部关键点三维实时检测

1.Web网页Demo体验

   
今儿咱们要学的三维手部关键点检测是基于Mediapipe实现滴,那什么是MediaPipe腻🧐🧐🧐MediaPipe是谷歌开源的工具包,它功能非常强大,有很多内置的solution,比如人脸检测、眼球运动检测、手部关键点检测、人体姿态估计、头发分割、目标检测等等。它让我们可以很方便地实现这些个功能,而不需要从零开始编写代码。这么强大灵活的工具,赶紧放个链接:Mediapipe主页Github主页

实现基于Mediapipe的手部关键点三维实时检测

   
说到这,你是不是迫不及待地想试一试手部检测啦,这里给盆友们提供一个Web网页➡codepen.io/tommyzihao/…
可以直接把链接复制在自己的浏览器里面就可以运行啦,不需要安装配置环境,直接调用摄像头在浏览器前端就可以看到检测效果辽(有些盆友打开页面可能会一直显示Loading,关闭再打开试试,玄学)🧸🧸🧸如下所示:

实现基于Mediapipe的手部关键点三维实时检测

   
效果是很不错滴,你可以试试把大拇指藏起来看算法会不会兼容。不仅如此,它还有三维效果腻。三维效果是说关键点离手腕越远并且越靠近摄像头,那么它的关键点的半径就越大,越远离摄像头就越小,也就是说它可以获得深度信息。你也可以在页面的左侧修改置信度阈值,当阈值特别小的时候呢,它会把人的脸也当成是手,所以置信度阈值不能设置的太小,0.7就很合适。除此之外,还可以分左右手,颜色等设置的信息可以在上面显示的代码中修改。心动不如行动,赶紧动手玩玩叭🌻🌻🌻(再给小伙伴们提供一个官网里的擦冰花游戏:趣味擦冰花)

   
现在咱们来看看三维手部关键点检测到底是一个什么问题,下图是一个最终的效果。为什么叫三维关键点呢?除了xy坐标,每一个关键点还会获得相对于手腕的深度信息,也就是z坐标(就像下图中类似铜钱那样,相对于手腕的距离越远且越靠近摄像头,铜钱就越大)。MediaPipe的手部关键点能够返回21个手部关键点的信息,这21个关键点分别是手腕一个点,其他五根指头每根指头上有四个点。由这21个关键点的连线就可以构建整个手的骨架,并且根据这21个点之间的关系可以建模,构建出一个手势识别的功能。在它的论文里呢还展示出了一个增强现实的功能,为人机交互提供了新的渠道(关于它的论文和原理,下次安排上)🌟🌟🌟

实现基于Mediapipe的手部关键点三维实时检测

2.单张图片检测

Mediapipe手部关键点检测官方教程:google.github.io/mediapipe/s…

   
体验过demo之后,下面让我们自己学着动手实现三维手部检测叭🎈🎈🎈进行检测前需要安装配置环境,在已有python环境的前提下,打开windows命令提示符,输入以下命令安装第三方库:

pip install mediapipe opencv-python numpy matplotlib tqdm jupyter notebook -i https://pypi.tuna.tsinghua.edu.cn/simple

1.导入工具包:color{blue}{1. 导入工具包:}

import cv2
import mediapipe as mp
from tqdm import tqdm
import time
import matplotlib.pyplot as plt
# 使用ipython魔法方法,将绘制出的图像直接嵌入在notebook单元格中
%matplotlib inline
# 定义可视化图像函数
def look_img(img):
    '''opencv读入图像格式为BGR,matplotlib可视化格式为RGB,因此需将BGR转RGB'''
    img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    plt.imshow(img_RGB)
    plt.show()

   
上述命令先导入各种工具包——opencv-python、mediapipe、进度条库、时间库、matplotlib(画图库),最后的百分号是一个ipython魔法方法,将matplotlib绘制出的图像直接嵌入在notebook单元格中。运行之后再定义一个可视化图像函数,这个函数输入的是数组形式的图像,它会把这个图像展示出来,仅此而已。

2.导入手部关键点检测模型:color{blue}{2. 导入手部关键点检测模型:}

# 导入solution
mp_hands = mp.solutions.hands
# 导入模型
hands = mp_hands.Hands(static_image_mode=False,        # 是静态图片还是连续视频帧
                       max_num_hands=4,                # 最多检测几只手
                       min_detection_confidence=0.5,   # 置信度阈值
                       min_tracking_confidence=0.5)    # 追踪阈值

# 导入绘图函数
mpDraw = mp.solutions.drawing_utils 

   
首先从mediapipe的solution里面选择hands,再导入模型,从mp.hands里面定义一个模型实例Hands,这里就需要配置一下模型的四个参数。第一个参数是静态图片还是连续视频帧,如果是False的话表明是连续视频帧,它就会按照连续视频帧那样从上一帧关键点推断出手部的位置,再送给下一帧用于预测;如果是True的话,表明你处理的帧与帧之间的图片是不一样的,它会每一次先过一遍手掌检测,然后再把手掌检测的结果喂给关键点检测模型(这里涉及到原理部分,暂时听不懂没关系滴),很明显会比较慢。第二个参数是最多检测几只手,2或4都可,如果太大的话算法可能就会不太稳定,检测的结果可能会抖动的比较厉害。第三个参数是置信度阈值,这里推荐0.7最合适;第四个参数是追踪阈值,这个阈值越大,它追踪的效果就会好,算法就会越鲁棒(but速度会变慢),这里选择默认值就可以🌈🌈🌈

3.读入图像:color{blue}{3. 读入图像:}

# 从图片文件读入图像,opencv读入为BGR格式
img = cv2.imread('./images/camera1.jpg')

# 水平镜像翻转图像,使图中左右手与真实左右手对应
# 参数 1:水平翻转,0:竖直翻转,-1:水平和竖直都翻转
img = cv2.flip(img, 1)
look_img(img)

   
在images文件夹里有一个camera1图像(这里设置你自己的图片即可),我们用opencv-python中的cv2.imread把它读入进来。为了让左右手能够跟预测结果对应上,需要把图像水平翻转一下,这里用的是opencv的flip,1表示水平翻转,0表示竖直翻转,-1表示都翻转。运行就会看到一个翻转后的图像。

4.将图像输入模型,获取预测结果:color{blue}{4. 将图像输入模型,获取预测结果:}

# BGR转RGB
img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 将RGB图像输入模型,获取预测结果
results = hands.process(img_RGB)
# 预测出手的个数
len(results.multi_hand_landmarks)

   
这个模型只接受RGB格式的,但是opencv读入的时候进来的是BGR格式,所以我们需要先把BGR格式转成RGB,就相当于把它第一个通道和第三个通道互换一下。然后把RGB格式的数据喂到模型里面,获取了results,所有的预测结果都在这个results里边。比如用len()看看它的长度,运行一下,结果是2,就代表检测出两只手。

5.可视化检测结果:color{blue}{5. 可视化检测结果:}

if results.multi_hand_landmarks: # 如果有检测到手
    # 遍历每一只检测出的手
    for hand_idx in range(len(results.multi_hand_landmarks)):
        hand_21 = results.multi_hand_landmarks[hand_idx] # 获取该手的所有关键点坐标
        mpDraw.draw_landmarks(img, hand_21, mp_hands.HAND_CONNECTIONS) # 可视化
look_img(img)

   
下面就可视化检测结果了。代码第一行的if results.multi_hand_landmarks:这个变量的结果非空,那么就继续下面的操作。这时候你可能会问,那我能不能写成if 它的长度大于0呢🤔🤔🤔理论上是可以滴,但是如果它没有检测出任何手的话,那这个变量并不具备len,就不能用len()来操作它,所以没有手的话就会报错辽,倒不如直接看这个变量是不是空就可以啦(真妙哇)。如果它检测到有手的话,就遍历变量里的每一只手,获取该手的所有关键点坐标。最后用刚开始导入的mpDraw画关键点。其中draw_landmarks()接收三个参数,第一个是要画的图,第二个是关键点,第三个为是否要绘制骨架,也就是关键点之间的连线。运行后就画出了最终的效果啦🎉🎉🎉

实现基于Mediapipe的手部关键点三维实时检测

3.摄像头实时检测

   
学完图片检测之后,摄像头实时检测就非常简单啦➡调用电脑的摄像头实时地获取一帧一帧的画面,每一帧画面呢都是一个静态的图像,每一帧画面就用上一节讲过单帧图像的处理方法来处理和可视化,再把这些处理过的可视化图像连成一个视频,并且实时的展示出来。理论上是这样,但是代码可能会更加复杂,因为牵涉到摄像头的读入。不过,有难度才有挑战性嘛,一起继续看看叭🍭🍭🍭

1.导入工具包和模型color{blue}{1. 导入工具包和模型}

这里和上节检测单张图片的代码块一样一样滴,就不赘述啦

2.处理单帧的函数color{blue}{2. 处理单帧的函数}

def process_frame(img):
    # 水平镜像翻转图像,使图中左右手与真实左右手对应
    # 参数 1:水平翻转,0:竖直翻转,-1:水平和竖直都翻转
    img = cv2.flip(img, 1)
    # BGR转RGB
    img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    # 将RGB图像输入模型,获取预测结果
    results = hands.process(img_RGB)
    
    if results.multi_hand_landmarks: # 如果有检测到手
        # 遍历每一只检测出的手
        for hand_idx in range(len(results.multi_hand_landmarks)):
            hand_21 = results.multi_hand_landmarks[hand_idx] # 获取该手的所有关键点坐标
            mpDraw.draw_landmarks(img, hand_21, mp_hands.HAND_CONNECTIONS) # 可视化
        # 在三维坐标系中可视化索引为0的手
        # mpDraw.plot_landmarks(results.multi_hand_landmarks[0], mp_hands.HAND_CONNECTIONS)
    return img

   
这里定义了一个处理单帧的函数,输入的是摄像头捕获的画面,输出的是可视化处理之后的图像。函数里面的代码是不是看着很眼熟腻,没戳,和上节代码也是一样滴(这不就大大减少了工作量)🌴🌴🌴

3.调用摄像头获取每帧(模板)color{blue}{3. 调用摄像头获取每帧(模板)}

# 不需修改任何代码,只需修改process_frame函数即可

# 导入opencv-python
import cv2
import time

# 获取摄像头,传入0表示获取系统默认摄像头
cap = cv2.VideoCapture(1)

# 打开cap
cap.open(0)

# 无限循环,直到break被触发
while cap.isOpened():
    # 获取画面
    success, frame = cap.read()
    if not success:
        print('Error')
        break
    
    ## !!!处理帧函数
    frame = process_frame(frame)
    
    # 展示处理后的三通道图像
    cv2.imshow('my_window',frame)

    if cv2.waitKey(1) in [ord('q'),27]: # 按键盘上的q或esc退出(在英文输入法下)
        break
    
# 关闭摄像头
cap.release()

# 关闭图像窗口
cv2.destroyAllWindows()

   
上述代码调用摄像头获取每一帧,然后再把每一帧喂到上次定义的处理单帧函数process_frame()里面,把这个函数返回的可视化结果实时地展示在电脑屏幕my_window上。其实上述这个函数是一个通用的模板,你以后不管做任何任务,只要是opencv调用摄像头实时的获取画面来处理,都可以用这个模板腻⛳⛳⛳运行之后就可以实现摄像头实时三维手部关键点检测啦,快快来试试叭

实现基于Mediapipe的手部关键点三维实时检测

4.潜在应用

   
除了技术本身之外,那么三维手部关键点检测有哪些潜在应用呢?这里盆友们可以大开一下脑洞嗷🌟🌟🌟:

  • 手势控制:隔空截屏翻页、无人机控制、智能家居控制
  • 动作捕捉:电影拍摄、短视频特效、增强现实
  • 手部穴位按摩机器人、手部针灸机器人、康复精准医疗
  • 手语翻译、手势翻译
  • 是否天生适合学钢琴、吉他……

实现基于Mediapipe的手部关键点三维实时检测

   
我感觉这些好好用喔,其中有些应该已经实现了🌈🌈🌈就像第一个隔空截屏翻页,比如你正在吃小龙虾,手黏黏糊糊的不方便碰手机,那么可以用隔空握拳截屏或者翻页这样的功能来操控;比如说无人机控制,你可以挥挥手,它就离你远去啦;再比如动作捕捉,因为我们能把手部的骨架提取出来,那把这个骨架再包上一层野兽或者外星人的皮囊,就可以获取它的动作,再结合物理引擎实现增强现实,这在电影拍摄、短视频特效里面是非常重要滴;应用在医疗领域的手势识别,掉包速成,模型非常快,cpu跑起来的速度也不差,是一个真正好的落地场景;另外有的钢琴家,他的手就天生长得很适合弹钢琴,手大到可以横跨14个键,天生就适合弹跨音高的曲……

   
对于游戏爱好者来说,三维手部关键点检测也有很大用处,比如用在VR设备替换掉手柄(或者做游戏主机waigua),这种技术在游戏设计尤其是手游上倒是能打破不少操作空间上的局限,进而开拓游戏设计玩法🧐🧐🧐

ending

   
看到这里相信盆友们都能实现三维手部关键点检测啦,是不是满满的成就感🌴🌴🌴不过可能也有小伙伴说“这不就是调包而已”,咦咦咦,此言差矣,你是省略了要调包之前的学习成本,要调这个包之前是要学很多东西滴,咱又不是用机器语言写代码的大佬。况且,有没有这么一种可能,咱们的互联网大厂,本质上也是在“调包”腻(狗头保命)🧐🧐🧐学完了代码之后,下一期就和盆友们分享三维手部关键点检测背后的原理,尽请期待叭

   
很开心能把学到的知识以文章的形式分享给大家。如果你也觉得我的分享对你有所帮助,please一键三连嗷!!!下期见

实现基于Mediapipe的手部关键点三维实时检测

本网站的内容主要来自互联网上的各种资源,仅供参考和信息分享之用,不代表本网站拥有相关版权或知识产权。如您认为内容侵犯您的权益,请联系我们,我们将尽快采取行动,包括删除或更正。
AI教程

DeepSpeed分布式训练工具详解

2023-11-19 21:54:14

AI教程

RAG技术:利用检索机制获取相关信息,指导并增强下游生成模块的输出质量

2023-11-19 23:23:14

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索