前言

之前有用这个MediaPipe.NET .NET包装库搞了手势识别,丰富了稚晖君的ElectronBot机器人的第三方上位机软件的功能,MediaPipe作为谷歌开源的机器视觉库,功能很丰富了,于是就开始整活了,来体验了一把人体姿态关键点检测。

WinUI(WASDK)使用MediaPipe检查人体姿态关键点-LMLPHP

所用框架介绍

1. WASDK

这个框架是微软最新的应用开发框架,我是用来开发程序的主体,做一些交互和功能的承载,本质上和wpf,uwp这类程序没什么太大的区别,区别就是一些工具链的不同。

2. MediaPipe

我主要使用MediaPipe进行人体姿态关键点坐标的提取,我的需求是将人体关键点坐标实时提取,并且同步到模型机器人的骨骼上,来实现同步的功能,但是这个博客只展示关键点的获取。

官方文档地址

WinUI(WASDK)使用MediaPipe检查人体姿态关键点-LMLPHP

推荐文档

MediaPipe 集成人脸识别,人体姿态评估,人手检测模型

代码讲解(干货篇)

1. 项目介绍

项目地址

项目结构如下图:

WinUI(WASDK)使用MediaPipe检查人体姿态关键点-LMLPHP

注意

由于MSIX打包的WASDK的路径访问为虚拟文件系统所以我们需要在项目里加入VFS目录,将引用的mediapipe的模块和dll放进去,不然会导致代码无法使用。

详情见如下文档:
打包的 VFS 位置

还有经过本人的测试,模型需要下载【Pose landmarker (Heavy)】的,不然检查不到坐标点。

WinUI(WASDK)使用MediaPipe检查人体姿态关键点-LMLPHP

特别注意的点,记得下载mediapipe的源码,将对应的模块依赖下载复制到对应的的目录,如果模型解压之后的名称和图片的不匹配记得修改文件名称之后复制到对应的目录,代码仓库就不上传模型文件了。

WinUI(WASDK)使用MediaPipe检查人体姿态关键点-LMLPHP

软件处理过程如下:

=>WinUI(WASDK)项目打开图片

=>OpencvSharp处理图片数据

=>转换成ImageFrame

=>MediaPipe处理返回人体姿态关键点坐标数据

=>软件通过win2d将坐标绘制到图片上

2.核心代码讲解

核心代码如下:

这段代码是将图片读取处理并且通过mediapipe获取坐标返回

  private async void StartButton_Click(object sender, RoutedEventArgs e)
    {
        var matData = new OpenCvSharp.Mat(Package.Current.InstalledLocation.Path + $"\\Assets\\pose.jpg");

        var mat2 = matData.CvtColor(OpenCvSharp.ColorConversionCodes.BGR2RGB);

        var dataMeta = mat2.Data;

        var length = mat2.Width * mat2.Height * mat2.Channels();

        var data = new byte[length];

        Marshal.Copy(dataMeta, data, 0, length);

        var widthStep = (int)mat2.Step();

        var imgframe = new ImageFrame(ImageFormat.Types.Format.Srgb, mat2.Width, mat2.Height, widthStep, data);

        PoseOutput handsOutput = calculator.Compute(imgframe);

        if (handsOutput.PoseLandmarks != null)
        {
            _poseOutput = handsOutput;

            CanvasControl1.Invalidate();
            var landmarks = handsOutput.PoseLandmarks.Landmark;
            Console.WriteLine($"Got pose output with {landmarks.Count} landmarks");
        }
        else
        {
            Console.WriteLine("No pose landmarks");
        }
    }

将结果绘制到图片上的代码如下,采用win2d绘制

    private void CanvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args)
    {
        if (_image != null)
        {
            // Draw the image
            args.DrawingSession.DrawImage(_image);

        }

        if (_poseOutput != null)
        {


            var poseLineList = _poseOutput.GetPoseLines(_image.Size.Width, _image.Size.Height);
            foreach (var postLine in poseLineList)
            {
                args.DrawingSession.DrawLine(postLine.StartVector2, postLine.EndVector2, Microsoft.UI.Colors.Green, 4);
            }
            foreach (var Landmark in _poseOutput?.PoseLandmarks?.Landmark)
            {

                var x = (int)_image.Size.Width * Landmark.X;
                var y = (int)_image.Size.Height * Landmark.Y;
                // Draw a point at (100, 100)
                args.DrawingSession.DrawCircle(x, y, 2, Microsoft.UI.Colors.Red, 2);
            }
        }
    }

效果如下:

WinUI(WASDK)使用MediaPipe检查人体姿态关键点-LMLPHP

人体点对应关系如图:

WinUI(WASDK)使用MediaPipe检查人体姿态关键点-LMLPHP

0 - nose
1 - left eye (inner)
2 - left eye
3 - left eye (outer)
4 - right eye (inner)
5 - right eye
6 - right eye (outer)
7 - left ear
8 - right ear
9 - mouth (left)
10 - mouth (right)
11 - left shoulder
12 - right shoulder
13 - left elbow
14 - right elbow
15 - left wrist
16 - right wrist
17 - left pinky
18 - right pinky
19 - left index
20 - right index
21 - left thumb
22 - right thumb
23 - left hip
24 - right hip
25 - left knee
26 - right knee
27 - left ankle
28 - right ankle
29 - left heel
30 - right heel
31 - left foot index
32 - right foot index

特别感谢的项目就是这个MediaPipe.NET了,没有它就没有我的这篇文章,更没有我的项目了。

个人感悟

又到了个人感悟环节,这次感觉舒服多了,因为看着wasdk框架的版本号越来越高,功能也越来越完善了。

总之是朝着好的方向发展了,希望别步了uwp的后尘,喜欢的话记得star一下了。

参考推荐文档如下

demo地址

WASDK文档地址

MediaPipe

MediaPipe.NET

ElectronBot

ElectronBot.DotNet

07-13 22:08