使用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、执行末尾循环体的次…

[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万。上一…

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 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;这一进程循环地从…

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

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

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

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

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;查找任何给定问题…

java打印设备集中管理_Kafka+Log4j实现日志集中管理

记录如何使用KafkaLog4j实现集中日志管理的过程。引言前面写的《SpringLog4jActiveMQ实现远程记录日志——实战分析》得到了许多同学的认可&#xff0c;在认可的同时&#xff0c;也有同学提出可以使用Kafka来集中管理日志&#xff0c;于是今天就来学习一下。特别说明&#xff0…

7-27 家谱处理 (30 分)(详解+map做法)map真香啊

一&#xff1a;题目 人类学研究对于家族很感兴趣&#xff0c;于是研究人员搜集了一些家族的家谱进行研究。实验中&#xff0c;使用计算机处理家谱。为了实现这个目的&#xff0c;研究人员将家谱转换为文本文件。下面为家谱文本文件的实例&#xff1a; John Robert Frank Andr…

微软开源基于 Envoy 的服务网格 Open Service Mesh

原文地址&#xff1a;https://techcrunch.com/2020/08/05/microsoft-launches-open-service-mesh/Open Service Mesh&#xff08;OSM&#xff09;是一个轻量级的、可扩展的、云原生的服务网格&#xff0c;它允许用户对高度动态的微服务环境进行统一管理、安全保护&#xff0c;并…

java servlet jsp javabean关系图_Servlet+JSP+JavaBean开发模式(MVC)介绍

好伤心...写登陆注册之前看见一篇很好的博文&#xff0c;没有收藏&#xff0c;然后找不到了。前几天在知乎上看见一个问题&#xff0c;什么时候感觉最无力。前两天一直想回答&#xff1a;尝试过google到的所有solve case&#xff0c;结果bug依然在。今天想回答&#xff1a;明明…

7-28 搜索树判断 (25 分)(思路加详解) just easy!

一&#xff1a;题目 对于二叉搜索树&#xff0c;我们规定任一结点的左子树仅包含严格小于该结点的键值&#xff0c;而其右子树包含大于或等于该结点的键值。如果我们交换每个节点的左子树和右子树&#xff0c;得到的树叫做镜像二叉搜索树。 现在我们给出一个整数键值序列&…

Azure DevOps+Docker+Asp.NET Core 实现CI/CD(一 .简介与创建自己的代理池)

前言本文主要是讲解如何使用Azure DevOpsDocker 来实现持续集成Asp.NET Core项目(当然 也可以是任意项目).打算用三个篇幅来记录完整的全过程觉得有帮助的朋友~可以左上角点个关注,右下角点个推荐CI/CD简介首先,我们先来简单的介绍一下什么是CI/CDCI全拼Continuous Integration…

7-31 笛卡尔树(25分)(题目分析+简单算法+详解+思路)

一&#xff1a;题目 7-31 笛卡尔树 (25 分) 笛卡尔树是一种特殊的二叉树&#xff0c;其结点包含两个关键字K1和K2。首先笛卡尔树是关于K1的二叉搜索树&#xff0c;即结点左子树的所有K1值都比该结点的K1值小&#xff0c;右子树则大。其次所有结点的K2关键字满足优先队列&#…

不仅性能秒杀Hadoop,现在连分布式集群功能也开源了

就在昨天&#xff08;2020年8月3日&#xff09;&#xff0c;涛思数据团队正式宣布&#xff0c;物联网大数据平台TDengine集群版开源。此次开源&#xff0c;我们在GitHub上传了23.9万行源代码&#xff0c;1198个源文件&#xff0c;包含我自己疫情期间写的一万余行C代码&#xff…

7-32 哥尼斯堡的“七桥问题” (25 分)(思路+详解+题目分析)两种做法任选其一

一&#xff1a;题目&#xff1a; 哥尼斯堡是位于普累格河上的一座城市&#xff0c;它包含两个岛屿及连接它们的七座桥&#xff0c;如下图所示。 可否走过这样的七座桥&#xff0c;而且每桥只走过一次&#xff1f;瑞士数学家欧拉(Leonhard Euler&#xff0c;1707—1783)最终解…

一次简单的服务器 cpu 占用率高的快速排查实战

前两天&#xff0c;朋友遇到一个线上 cpu 占用率很高的问题&#xff0c;我们俩一起快速定位并解决了这个问题。在征求朋友同意后&#xff0c;特发此文分享整个过程。本文以对话的形式展开&#xff0c;加上我的内心独白。文中对话与实际对话略有出入。友&#xff1a; 在吗&#…

7-33 地下迷宫探索 (30 分)(思路加详解)

一&#xff1a;题目 7-33 地下迷宫探索 (30 分)地道战是在抗日战争时期&#xff0c;在华北平原上抗日军民利用地道打击日本侵略者的作战方式。地道网是房连房、街连街、村连村的地下工事&#xff0c;如下图所示。 我们在回顾前辈们艰苦卓绝的战争生活的同时&#xff0c;真心钦…