使用Azure人脸API对图片进行人脸识别

人脸识别是人工智能机器学习比较成熟的一个领域。人脸识别已经应用到了很多生产场景。比如生物认证,人脸考勤,人流监控等场景。对于很多中小功能由于技术门槛问题很难自己实现人脸识别的算法。Azure人脸API对人脸识别机器学习算法进行封装提供REST API跟SDK方便用户进行自定义开发。

Azure人脸API可以对图像中的人脸进行识别,返回面部的坐标、性别、年龄、情感、愤怒还是高兴、是否微笑,是否带眼镜等等非常有意思的信息。
Azure人脸API也是一个免费服务,每个月30000次事务的免费额度。

创建人脸服务

填写实例名,选择一个区域,同样选离你近的。

获取秘钥跟终结点

选中侧边菜单“秘钥于终结点”,获取信息,这2个信息后面再sdk调用中需要用到。

新建WPF应用

新建一个WPF应用实现以下功能:

  1. 选择图片后把原图显示出来

  2. 选中后马上进行识别

  3. 识别成功后把脸部用红框描述出来

  4. 当鼠标移动到红框内的时候显示详细脸部信息

安装SDK

使用nuget安装对于的sdk包:

Install-Package Microsoft.Azure.CognitiveServices.Vision.Face -Version 2.5.0-preview.2

实现界面

编辑MainWindow.xml放置图像显示区域、文件选中、描述显示区域

<Window x:Class="FaceWpf.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:FaceWpf"mc:Ignorable="d"Title="MainWindow" Height="600" Width="800"><Grid x:Name="BackPanel"><Image x:Name="FacePhoto" Stretch="Uniform" Margin="0,0,0,50" MouseMove="FacePhoto_MouseMove" /><DockPanel DockPanel.Dock="Bottom"><Button x:Name="BrowseButton" Width="72" Height="80" VerticalAlignment="Bottom" HorizontalAlignment="Left"Content="选择图片..."Click="BrowseButton_Click" /><StatusBar VerticalAlignment="Bottom"><StatusBarItem><TextBlock Name="faceDescriptionStatusBar" Height="80" FontSize="20" Text="" Width="500" TextWrapping="Wrap"/></StatusBarItem></StatusBar></DockPanel></Grid>
</Window>

构造函数

在编辑MainWindow类的构造函数初始化FaceClient等数据

   private IFaceClient _faceClient;//检测到的人脸private IList<DetectedFace> _faceList;//人脸描述信息private string[] _faceDescriptions;private double _resizeFactor;private const string _defaultStatusBarText ="鼠标移动到面部显示描述信息.";public MainWindow(){InitializeComponent();//faceid的订阅keystring subscriptionKey = "";// faceid的终结的配置string faceEndpoint = "";_faceClient = new FaceClient(new ApiKeyServiceClientCredentials(subscriptionKey),new System.Net.Http.DelegatingHandler[] { });if (Uri.IsWellFormedUriString(faceEndpoint, UriKind.Absolute)){_faceClient.Endpoint = faceEndpoint;}else{MessageBox.Show(faceEndpoint,"Invalid URI", MessageBoxButton.OK, MessageBoxImage.Error);Environment.Exit(0);}}

图片选择并显示

  // 选择图片并上传private async void BrowseButton_Click(object sender, RoutedEventArgs e){var openDlg = new Microsoft.Win32.OpenFileDialog();openDlg.Filter = "JPEG Image(*.jpg)|*.jpg";bool? result = openDlg.ShowDialog(this);if (!(bool)result){return;}// Display the image file.string filePath = openDlg.FileName;Uri fileUri = new Uri(filePath);BitmapImage bitmapSource = new BitmapImage();bitmapSource.BeginInit();bitmapSource.CacheOption = BitmapCacheOption.None;bitmapSource.UriSource = fileUri;bitmapSource.EndInit();FacePhoto.Source = bitmapSource;// Detect any faces in the image.Title = "识别中...";_faceList = await UploadAndDetectFaces(filePath);Title = String.Format("识别完成. {0}个人脸", _faceList.Count);if (_faceList.Count > 0){// Prepare to draw rectangles around the faces.DrawingVisual visual = new DrawingVisual();DrawingContext drawingContext = visual.RenderOpen();drawingContext.DrawImage(bitmapSource,new Rect(0, 0, bitmapSource.Width, bitmapSource.Height));double dpi = bitmapSource.DpiX;// Some images don't contain dpi info._resizeFactor = (dpi == 0) ? 1 : 96 / dpi;_faceDescriptions = new String[_faceList.Count];for (int i = 0; i < _faceList.Count; ++i){DetectedFace face = _faceList[i];//画方框drawingContext.DrawRectangle(Brushes.Transparent,new Pen(Brushes.Red, 2),new Rect(face.FaceRectangle.Left * _resizeFactor,face.FaceRectangle.Top * _resizeFactor,face.FaceRectangle.Width * _resizeFactor,face.FaceRectangle.Height * _resizeFactor));_faceDescriptions[i] = FaceDescription(face);}drawingContext.Close();RenderTargetBitmap faceWithRectBitmap = new RenderTargetBitmap((int)(bitmapSource.PixelWidth * _resizeFactor),(int)(bitmapSource.PixelHeight * _resizeFactor),96,96,PixelFormats.Pbgra32);faceWithRectBitmap.Render(visual);FacePhoto.Source = faceWithRectBitmap;faceDescriptionStatusBar.Text = _defaultStatusBarText;}}

调用SDK进行识别

指定需要识别的要素,调用sdk进行图像识别

   // 上传图片使用faceclient识别private async Task<IList<DetectedFace>> UploadAndDetectFaces(string imageFilePath){IList<FaceAttributeType> faceAttributes =new FaceAttributeType[]{FaceAttributeType.Gender, FaceAttributeType.Age,FaceAttributeType.Smile, FaceAttributeType.Emotion,FaceAttributeType.Glasses, FaceAttributeType.Hair};using (Stream imageFileStream = File.OpenRead(imageFilePath)){IList<DetectedFace> faceList =await _faceClient.Face.DetectWithStreamAsync(imageFileStream, true, false, faceAttributes);return faceList;}}

显示脸部的描述

对人脸识别后的结果信息组装成字符串,当鼠标移动到人脸上的时候显示这些信息。

 /// <summary>/// 鼠标移动显示脸部描述/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void FacePhoto_MouseMove(object sender, MouseEventArgs e){if (_faceList == null)return;Point mouseXY = e.GetPosition(FacePhoto);ImageSource imageSource = FacePhoto.Source;BitmapSource bitmapSource = (BitmapSource)imageSource;var scale = FacePhoto.ActualWidth / (bitmapSource.PixelWidth / _resizeFactor);bool mouseOverFace = false;for (int i = 0; i < _faceList.Count; ++i){FaceRectangle fr = _faceList[i].FaceRectangle;double left = fr.Left * scale;double top = fr.Top * scale;double width = fr.Width * scale;double height = fr.Height * scale;if (mouseXY.X >= left && mouseXY.X <= left + width &&mouseXY.Y >= top && mouseXY.Y <= top + height){faceDescriptionStatusBar.Text = _faceDescriptions[i];mouseOverFace = true;break;}}if (!mouseOverFace) faceDescriptionStatusBar.Text = _defaultStatusBarText;}
 /// <summary>/// 脸部描述/// </summary>/// <param name="face"></param>/// <returns></returns>private string FaceDescription(DetectedFace face){StringBuilder sb = new StringBuilder();sb.Append("人脸: ");// 性别年龄sb.Append(face.FaceAttributes.Gender.Value == Gender.Female ? "女性" : "男性");sb.Append(", ");sb.Append(face.FaceAttributes.Age.ToString() + "岁");sb.Append(", ");sb.Append(String.Format("微笑 {0:F1}%, ", face.FaceAttributes.Smile * 100));// 显示超过0.1的表情sb.Append("表情: ");Emotion emotionScores = face.FaceAttributes.Emotion;if (emotionScores.Anger >= 0.1f) sb.Append(String.Format("生气 {0:F1}%, ", emotionScores.Anger * 100));if (emotionScores.Contempt >= 0.1f) sb.Append(String.Format("蔑视 {0:F1}%, ", emotionScores.Contempt * 100));if (emotionScores.Disgust >= 0.1f) sb.Append(String.Format("厌恶 {0:F1}%, ", emotionScores.Disgust * 100));if (emotionScores.Fear >= 0.1f) sb.Append(String.Format("恐惧 {0:F1}%, ", emotionScores.Fear * 100));if (emotionScores.Happiness >= 0.1f) sb.Append(String.Format("高兴 {0:F1}%, ", emotionScores.Happiness * 100));if (emotionScores.Neutral >= 0.1f) sb.Append(String.Format("自然 {0:F1}%, ", emotionScores.Neutral * 100));if (emotionScores.Sadness >= 0.1f) sb.Append(String.Format("悲伤 {0:F1}%, ", emotionScores.Sadness * 100));if (emotionScores.Surprise >= 0.1f) sb.Append(String.Format("惊喜 {0:F1}%, ", emotionScores.Surprise * 100));sb.Append(face.FaceAttributes.Glasses);sb.Append(", ");sb.Append("头发: ");if (face.FaceAttributes.Hair.Bald >= 0.01f)sb.Append(String.Format("秃头 {0:F1}% ", face.FaceAttributes.Hair.Bald * 100));IList<HairColor> hairColors = face.FaceAttributes.Hair.HairColor;foreach (HairColor hairColor in hairColors){if (hairColor.Confidence >= 0.1f){sb.Append(hairColor.Color.ToString());sb.Append(String.Format(" {0:F1}% ", hairColor.Confidence * 100));}}return sb.ToString();}

运行

到此我们的应用打造完成了。先让我们选择一张结衣的图片试试:

看看我们的结衣微笑率97.9%。

再选一张杰伦的图片试试:

嗨,杰伦就是不喜欢笑,微笑率0% 。。。

总结

通过简单的一个wpf的应用我们演示了如果使用Azure人脸API进行图片中的人脸检测,真的非常方便,识别代码只有1行而已。如果不用C# sdk还可以使用更加通用的rest api来调用,这样可以适配任何开发语言。Azure人脸API除了能对图片中的人脸进行检测,还可以对多个人脸进行比对,检测是否是同一个人,这样就可以实现人脸考勤等功能了,这个下次再说吧。

关注我的公众号一起玩转技术  

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

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

相关文章

java while do循环_c语言中,while 和 do while 循环的主要区别是( )

1、循环构造的表达式不同&#xff1a;while循环构造的表达式为&#xff1a;while(表达式)&#xff5b;循环体&#xff5d;。do&#xff0d;while循环构造表达式为&#xff1a;do&#xff5b;循环体&#xff1b;&#xff5d;while(条件表达)&#xff1b;。2、执行末尾循环体的次…

Java当中 IO(File) 操作 之 递归打印子孙级目录和文件名称

一&#xff1a;上码 package com.wyj.one;import java.io.File;/*** 列出下一级&#xff1a;* 1, list(): 列出下一级名称* 2&#xff0c; listFiles()&#xff1a;列出下一级File对象* 3, listRoots():列出盘符* author 86155**/ public class Demo8_列出下一级 {/*** p…

[NewLife.Net]单机400万长连接压力测试

目标对网络库NewLife.Net进行单机百万级长连接测试&#xff0c;并持续收发数据&#xff0c;检测网络库稳定性。【2020年8月1日晚上22点】先上源码&#xff1a;https://github.com/NewLifeX/NewLife.Net结论&#xff0c;8月1日晚达到200万&#xff0c;8月2日下午达到404万。上一…

JAVA开发需求分析套路_毕设做什么好?感觉都是套路了

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼在不考虑柯西序列的情况下&#xff1a;.1.00000000000000000……-0.9999999…….结果为 0.000…&#xff0c;也就是后面的 0 无限循环。这两个数目在这里是无限循环小数&#xff0c;小数点后五位之后还会一直填上 0&#xff0c;始终…

ABP快速开发一个.NET Core电商平台

总听.NETer羡慕Java有SSM框架&#xff0c;其实.NET也有ABP&#xff0c;极度优秀的开源应用程序框架&#xff0c;支持.NET Framework和.NET Core。羡慕Java有SpringCloud&#xff0c;其实.NET也有ABP.vNext&#xff0c;由ABP团队全新打造的.NET Core微服务架构开源框架&#xff…

Java当中 递归打印文件大小(面向不同的对象打印文件大小)

一&#xff1a;给固定的文件路径求文件大小 package com.wyj.one;import java.io.File;/*** 递归求出文件的大小* author 86155**/ public class CopyOfDemo10_递归打印子文件大小 {public static void main(String[] args) {File src new File("C:/Myjava/project12_IO…

java jlist 图标_java – 将图像添加到JList项目

您必须实现ListCellRenderer(或扩展DefaultListCellRenderer)并使用getListCellRendererComponent方法返回带有图标的Jlabel.例&#xff1a;public class IconListRenderer extends DefaultListCellRenderer {public Component getListCellRendererComponent(JList list, Objec…

Java当中编码和解码(以及出现乱编码的原因)

一&#xff1a;编码&#xff1a;字符串---->字节 package com.wyj.two;import java.io.UnsupportedEncodingException;/*** 编码&#xff1a;字符串-->字节* * * author 王永杰**/ public class Demo1_encode编码 {public static void main(String[] args) throws Unsup…

用了Dapper之后通篇还是SqlConnection,真的看不下去了

一&#xff1a;背景1. 讲故事前几天看公司一个新项目的底层使用了dapper&#xff0c;大家都知道dapper是一个非常强大的半自动化orm&#xff0c;帮程序员解决了繁琐的mapping问题&#xff0c;用起来非常爽&#xff0c;但我还是遇到了一件非常不爽的事情,如下代码所示&#xff1…

java swing 控件拖动_java swing中实现拖拽功能示例

java实现拖拽示例Swing中实现拖拽功能&#xff0c;代码很简单&#xff0c;都有注释&#xff0c;自己看&#xff0c;运行效果如下图&#xff1a;package com;import java.awt.*;import java.awt.datatransfer.DataFlavor;import java.awt.dnd.DnDConstants;import java.awt.dnd.…

7-26 Windows消息队列 (25 分)(详解+思路+超时解决)

一&#xff1a;题目 消息队列是Windows系统的基础。对于每个进程&#xff0c;系统维护一个消息队列。如果在进程中有特定事件发生&#xff0c;如点击鼠标、文字改变等&#xff0c;系统将把这个消息加到队列当中。同时&#xff0c;如果队列不是空的&#xff0c;这一进程循环地从…

一文说通C#中的异步编程补遗

前文写了关于C#中的异步编程。后台有无数人在讨论&#xff0c;很多人把异步和多线程混了。文章在这儿&#xff1a;一文说通C#中的异步编程所以&#xff0c;本文从体系的角度&#xff0c;再写一下这个异步编程。一、C#中的异步编程演变1. 异步编程模型这是C#中早期的异步模型&am…

java 视频监控 分屏ui_视频监控网页ActiveX视频分屏播放控件开发

最近在搞视频监控项目&#xff0c;需要在网页上显示实时视频&#xff0c;于是网上找了很多资料研究如何在网页上播放视频&#xff0c;一种实现方式就是开发activex控件嵌入到网页中。如下我将介绍如何开发一个可以分屏播放视频的activex控件 (部分内容也是从网上抄的&#xff0…

Java当中 文件得输入流 输出流

一&#xff1a;引言 InputStream 和 OutputStream 两个抽象类&#xff0c;我们主要用其实现类来操作 二&#xff1a;InputStream 输入流&#xff0c;从文件当中读数据到程序当中&#xff0c;我们要站在程序得角度上。 package com.wyj.two;import java.io.File; import jav…

基于.NetCore3.1系列 —— 日志记录之日志核心要素揭秘

前言在上一篇中&#xff0c;我们已经了解了内置系统的默认配置和自定义配置的方式&#xff0c;在学习了配置的基础上&#xff0c;我们进一步的对日志在程序中是如何使用的深入了解学习。所以在这一篇中&#xff0c;主要是对日志记录的核心机制进行学习说明。说明在上一篇中&…

array remove java_how to remove array from another array in javascript

可以将文章内容翻译成中文,广告屏蔽插件会导致该功能失效:问题:0: {id: 1553825061863, name: "Thai Milk Tea", qty: "1", total_amount: 9500, toppings: 500, …}1: {id: 1553825061863, name: "Thai Milk Tea", qty: "1", total_a…

Java 文件的拷贝

一&#xff1a;上码 package com.wyj.two;import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream;/*** 文件…

listview在java中的使用_我的Android开发之路——ListView的使用

在Android开发过程中&#xff0c;遇到需要列表显示的时候&#xff0c;这时候就会用到listview。1.首先创建一个ListViewTest项目&#xff0c;选择empty activity类型。修改activity_main.xml的布局文件&#xff0c;添加listview控件&#xff0c;设置宽高和id等属性此时通过预览…

如何利用NLog输出结构化日志,并在Kibana优雅分析日志?

上文我们演示了使用NLog向ElasticSearch写日志的基本过程(输出的是普通文本日志)&#xff0c;今天我们来看下如何向ES输出结构化日志、在Kibana中分析日志。什么是结构化日志&#xff1f;当前互联网、物联网、大数据突飞猛进&#xff0c;软件越复杂&#xff0c;查找任何给定问题…

C++中字符串的截取 str.substr(a,b);

C中字符串的截取 str.substr(a,b); #include<bits/stdc.h> using namespace std;int main() {//str.substr(a,b);a表示截取字符串的下标&#xff0c;b表示要截取的长度不填则为截取的到最后 string str "aaaabc";cout << str.substr(3) << endl;…