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

前言

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

pose

所用框架介绍

1. WASDK

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

2. MediaPipe

MediaPipe offers open source cross-platform, customizable ML solutions for live and streaming media.

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

官方文档地址

pose-doc

推荐文档

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

代码讲解(干货篇)

1. 项目介绍

项目地址

项目结构如下图:

img

注意

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

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

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

img

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

model

软件处理过程如下:

=>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");
}
}
  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");
        }
    }
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);
}
}
}
    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);
            }
        }
    }
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); } } }

效果如下:

img

人体点对应关系如图:

img

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

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYQiwqI3' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片