首先我们先来说说这个ONNX

ONNX是一种针对机器学习所设计的开放式的文件格式,用于存储训练好的模型。它使得不同的人工智能框架(如Pytorch, MXNet)可以采用相同格式存储模型数据并交互。 ONNX的规范及代码主要由微软,亚马逊 ,Facebook 和 IBM 等公司共同开发,以开放源代码的方式托管在Github上。目前官方支持加载ONNX模型并进行推理的深度学习框架有: Caffe2, PyTorch, MXNet,ML.NET,TensorRT 和 Microsoft CNTK,并且 TensorFlow 也非官方的支持ONNX。---维基百科

看了上面的引用 大家应该知道了 这个其实是个文件格式用来存储训练好的模型,所以我这篇帖子既然是做表情识别那肯定是需要有个能识别表情的模型。有了这个模型我们就可以根据图片上的人物,进行表情的识别判断了。

刚好微软对机器学习这块也挺上心的,所以我也趁着疫情比较闲,就来学习学习了。UWP的机器学习的api微软已经切成正式了,所以大家可以放心使用。

这就是uwp api文档 开头就是AI的

我其实是个小白 所以我就直接拿官方的一个demo的简化版来进行讲解了,官方的demo演示如下。

这个app就是通过摄像头读取每一帧 进行和模型匹配得出结果的

下面是机器学习的微软的github地址

Emoji8的git地址

我今天要说的就是这个demo的简化代码大致运行流程

下面是项目结构图

我把官方项目简化了 所以只留下了识别后的文本移除了一些依赖的库

核心代码在IntelligenceService类里的Current_SoftwareBitmapFrameCaptured方法里

 private async void Current_SoftwareBitmapFrameCaptured(object sender, SoftwareBitmapEventArgs e){Debug.WriteLine("FrameCaptured");Debug.WriteLine($"Frame evaluation started {DateTime.Now}" );if (e.SoftwareBitmap != null){BitmapPixelFormat bpf = e.SoftwareBitmap.BitmapPixelFormat;var uncroppedBitmap = SoftwareBitmap.Convert(e.SoftwareBitmap, BitmapPixelFormat.Nv12);var faces = await _faceDetector.DetectFacesAsync(uncroppedBitmap);if (faces.Count > 0){//crop image to focus on face portionvar faceBox = faces[0].FaceBox;VideoFrame inputFrame = VideoFrame.CreateWithSoftwareBitmap(e.SoftwareBitmap);VideoFrame tmp = null;tmp = new VideoFrame(e.SoftwareBitmap.BitmapPixelFormat, (int)(faceBox.Width + faceBox.Width % 2) - 2, (int)(faceBox.Height + faceBox.Height % 2) - 2);await inputFrame.CopyToAsync(tmp, faceBox, null);//crop image to fit model input requirementsVideoFrame croppedInputImage = new VideoFrame(BitmapPixelFormat.Gray8, (int)_inputImageDescriptor.Shape[3], (int)_inputImageDescriptor.Shape[2]);var srcBounds = GetCropBounds(tmp.SoftwareBitmap.PixelWidth,tmp.SoftwareBitmap.PixelHeight,croppedInputImage.SoftwareBitmap.PixelWidth,croppedInputImage.SoftwareBitmap.PixelHeight);await tmp.CopyToAsync(croppedInputImage, srcBounds, null);ImageFeatureValue imageTensor = ImageFeatureValue.CreateFromVideoFrame(croppedInputImage);_binding = new LearningModelBinding(_session);TensorFloat outputTensor = TensorFloat.Create(_outputTensorDescriptor.Shape);List<float> _outputVariableList = new List<float>();// Bind inputs + outputs_binding.Bind(_inputImageDescriptor.Name, imageTensor);_binding.Bind(_outputTensorDescriptor.Name, outputTensor);// Evaluate resultsvar results = await _session.EvaluateAsync(_binding, new Guid().ToString());Debug.WriteLine("ResultsEvaluated: " + results.ToString());var outputTensorList = outputTensor.GetAsVectorView();var resultsList = new List<float>(outputTensorList.Count);for (int i = 0; i < outputTensorList.Count; i++){resultsList.Add(outputTensorList[i]);}var softMaxexOutputs = SoftMax(resultsList);double maxProb = 0;int maxIndex = 0;// Comb through the evaluation resultsfor (int i = 0; i < Constants.POTENTIAL_EMOJI_NAME_LIST.Count(); i++){// Record the dominant emotion probability & its locationif (softMaxexOutputs[i] > maxProb){maxIndex = i;maxProb = softMaxexOutputs[i];}                      }Debug.WriteLine($"Probability = {maxProb}, Threshold set to = {Constants.CLASSIFICATION_CERTAINTY_THRESHOLD}, Emotion = {Constants.POTENTIAL_EMOJI_NAME_LIST[maxIndex]}");// For evaluations run on the MainPage, update the emoji carouselif (maxProb >= Constants.CLASSIFICATION_CERTAINTY_THRESHOLD){Debug.WriteLine("first page emoji should start to update");IntelligenceServiceEmotionClassified?.Invoke(this, new ClassifiedEmojiEventArgs(CurrentEmojis._emojis.Emojis[maxIndex]));}// Dispose of resourcesif (e.SoftwareBitmap != null){e.SoftwareBitmap.Dispose();e.SoftwareBitmap = null;}}}IntelligenceServiceProcessingCompleted?.Invoke(this, null);Debug.WriteLine($"Frame evaluation finished {DateTime.Now}");}//WinML team functionprivate List<float> SoftMax(List<float> inputs){List<float> inputsExp = new List<float>();float inputsExpSum = 0;for (int i = 0; i < inputs.Count; i++){var input = inputs[i];inputsExp.Add((float)Math.Exp(input));inputsExpSum += inputsExp[i];}inputsExpSum = inputsExpSum == 0 ? 1 : inputsExpSum;for (int i = 0; i < inputs.Count; i++){inputsExp[i] /= inputsExpSum;}return inputsExp;}public static BitmapBounds GetCropBounds(int srcWidth, int srcHeight, int targetWidth, int targetHeight){var modelHeight = targetHeight;var modelWidth = targetWidth;BitmapBounds bounds = new BitmapBounds();// we need to recalculate the crop bounds in order to correctly center-crop the input imagefloat flRequiredAspectRatio = (float)modelWidth / modelHeight;if (flRequiredAspectRatio * srcHeight > (float)srcWidth){// clip on the y axisbounds.Height = (uint)Math.Min((srcWidth / flRequiredAspectRatio + 0.5f), srcHeight);bounds.Width = (uint)srcWidth;bounds.X = 0;bounds.Y = (uint)(srcHeight - bounds.Height) / 2;}else // clip on the x axis{bounds.Width = (uint)Math.Min((flRequiredAspectRatio * srcHeight + 0.5f), srcWidth);bounds.Height = (uint)srcHeight;bounds.X = (uint)(srcWidth - bounds.Width) / 2; ;bounds.Y = 0;}return bounds;}

感兴趣的朋友可以把官方的代码和我的代码都克隆下来看一看,玩一玩。

我的简化版的代码 地址如下

简化版表情识别代码地址

特别感谢 Windows Community Toolkit Sample App提供的摄像头辅助类

商店搜索 Windows Community Toolkit Sample App就能下载

讲的不好的地方 希望大家给与批评

UWP通过机器学习加载ONNX进行表情识别相关推荐

  1. Lable加载 类似QQ表情 (unicode emoji字符集)

    Lable加载 类似QQ表情 (unicode emoji字符集) 偶然看到一篇文,发现竟然可以在iPhone中显示类似qq表情的符号.原来很简单,是iPhone支持unicodeemoji字符集缘故 ...

  2. 记录 | PC端微信无法加载头像和表情包的解决

    目录 问题描述 解决 问题描述 换了一台新的电脑,登录微信后发现无法加载表情包和头像 解决 参考了如下链接:https://developers.weixin.qq.com/community/dev ...

  3. linux无法加载蓝牙设备,Linux 无法识别蓝牙适配器解决办法

    蓝牙适配器(USB):胜为 UDC-321Linux 2.6.29首先查看USB是否识别:#lsusbBus 005 Device 004: ID 0402:5602 ALi Corp. Video ...

  4. 【Scikit-Learn 中文文档】数据集加载工具 - 用户指南 | ApacheCN

    中文文档: http://sklearn.apachecn.org/cn/stable/datasets/index.html 英文文档: http://sklearn.apachecn.org/en ...

  5. Scikit-Learn 中文文档】数据集加载工具 - 用户指南 | ApacheCN

    中文文档: http://sklearn.apachecn.org/cn/stable/datasets/index.html 英文文档: http://sklearn.apachecn.org/en ...

  6. 【Scikit-Learn 中文文档】40 数据集加载工具 - 用户指南 | ApacheCN

    中文文档: http://sklearn.apachecn.org/cn/stable/datasets/index.html 英文文档: http://sklearn.apachecn.org/en ...

  7. 【Scikit-Learn 中文文档】四十:数据集加载工具 - 用户指南 | ApacheCN

    中文文档: http://sklearn.apachecn.org/cn/stable/datasets/index.html 英文文档: http://sklearn.apachecn.org/en ...

  8. android 动态 dex,Android 动态加载dex

    首先如果仅仅是因为64K method的问题可以直接看这里DexGuard.Proguard.Multi-dex给出的解决方案. 本文主要讨论从编译层面,dex动态加载器选择层面以及安全层面讨论dex ...

  9. DSP6678加载数据

    开发环境:DSP6678开发板+CCS5.5+win7. 因为项目需要把81M的数据放入DDR3中处理,所以第一步就是如何加载数据.DSP6678识别的数据类型是dat.bin.raw.yuv. 加载 ...

最新文章

  1. springboot 整合redis 实现KeySpaceNotification 键空间通知
  2. EfficientNetV2:更小,更快,更好的EfficientNet
  3. MySQL的Found_ROWS函数介绍
  4. Swagger在header中添加token
  5. C# Span 源码解读和应用实践
  6. java其他进程,Java进程优先于其他Windows进程
  7. tcp关闭连接:挥手讨论
  8. Java Singleton类中的线程安全
  9. Android TabActivity与Activity之间的动画跳转(主要Tabhost中跳转出来的动画效果解决)...
  10. 经济学和哲学_边做边学的哲学
  11. m4s格式转换mp3_音频格式转换器哪个好,推荐几款免费的mp3格式转换器
  12. 保研杂记(上)心灵鸡汤篇
  13. 十二个一的宠物倾向分析
  14. eggs和egg是什么意思_egg是什么
  15. python数据分析案例分析题_Python数据分析-案例分析
  16. NOI 题目 试题 目录 信奥 历年
  17. 七款好用的Linux防火墙
  18. 去中心化身份一般见解
  19. 【selenium3+JAVA】界面自动化测试教程(一)——浏览器启动之firefox浏览器的启动
  20. WordPress内核 模板下载源码论坛全站源码带会员下载+DUX主题

热门文章

  1. 关于vue3.0中的this.$router.replace({ path: '/'})刷新无效果问题
  2. 秒级快速批量创建kvm虚拟机并指定IP地址和主机名
  3. Python——PyCharm常用快捷键
  4. 媒体控件的暂停与播放 0130 winform
  5. 小货车DataAdapter对象 1129
  6. 配置jdk1.7的环境变量
  7. celery-01-异步任务模块-解决发送邮件的延时问题
  8. Linux通过进程号查询占用的端口
  9. U盘容量显示错误修正
  10. 浏览器推送 comet技术