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

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

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

创建人脸服务

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

获取秘钥跟终结点

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

新建WPF应用

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

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

  2. 选中后马上进行识别

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

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

安装SDK

使用nuget安装对于的sdk包:

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

实现界面

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

 
  1. <Window x:Class="FaceWpf.MainWindow"

  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

  6. xmlns:local="clr-namespace:FaceWpf"

  7. mc:Ignorable="d"

  8. Title="MainWindow" Height="600" Width="800">

  9. <Grid x:Name="BackPanel">

  10. <Image x:Name="FacePhoto" Stretch="Uniform" Margin="0,0,0,50" MouseMove="FacePhoto_MouseMove" />

  11. <DockPanel DockPanel.Dock="Bottom">

  12. <Button x:Name="BrowseButton" Width="72" Height="80" VerticalAlignment="Bottom" HorizontalAlignment="Left"

  13. Content="选择图片..."

  14. Click="BrowseButton_Click" />

  15. <StatusBar VerticalAlignment="Bottom">

  16. <StatusBarItem>

  17. <TextBlock Name="faceDescriptionStatusBar" Height="80" FontSize="20" Text="" Width="500" TextWrapping="Wrap"/>

  18. </StatusBarItem>

  19. </StatusBar>

  20. </DockPanel>

  21. </Grid>

  22. </Window>

构造函数

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

 
  1. private IFaceClient _faceClient;

  2. //检测到的人脸

  3. private IList<DetectedFace> _faceList;

  4. //人脸描述信息

  5. private string[] _faceDescriptions;

  6. private double _resizeFactor;

  7. private const string _defaultStatusBarText =

  8. "鼠标移动到面部显示描述信息.";

  9. public MainWindow()

  10. {

  11. InitializeComponent();

  12. //faceid的订阅key

  13. string subscriptionKey = "";

  14. // faceid的终结的配置

  15. string faceEndpoint = "";

  16. _faceClient = new FaceClient(

  17. new ApiKeyServiceClientCredentials(subscriptionKey),

  18. new System.Net.Http.DelegatingHandler[] { });

  19. if (Uri.IsWellFormedUriString(faceEndpoint, UriKind.Absolute))

  20. {

  21. _faceClient.Endpoint = faceEndpoint;

  22. }

  23. else

  24. {

  25. MessageBox.Show(faceEndpoint,

  26. "Invalid URI", MessageBoxButton.OK, MessageBoxImage.Error);

  27. Environment.Exit(0);

  28. }

  29. }

图片选择并显示

 
  1. // 选择图片并上传

  2. private async void BrowseButton_Click(object sender, RoutedEventArgs e)

  3. {

  4. var openDlg = new Microsoft.Win32.OpenFileDialog();

  5. openDlg.Filter = "JPEG Image(*.jpg)|*.jpg";

  6. bool? result = openDlg.ShowDialog(this);

  7. if (!(bool)result)

  8. {

  9. return;

  10. }

  11. // Display the image file.

  12. string filePath = openDlg.FileName;

  13. Uri fileUri = new Uri(filePath);

  14. BitmapImage bitmapSource = new BitmapImage();

  15. bitmapSource.BeginInit();

  16. bitmapSource.CacheOption = BitmapCacheOption.None;

  17. bitmapSource.UriSource = fileUri;

  18. bitmapSource.EndInit();

  19. FacePhoto.Source = bitmapSource;

  20. // Detect any faces in the image.

  21. Title = "识别中...";

  22. _faceList = await UploadAndDetectFaces(filePath);

  23. Title = String.Format(

  24. "识别完成. {0}个人脸", _faceList.Count);

  25. if (_faceList.Count > 0)

  26. {

  27. // Prepare to draw rectangles around the faces.

  28. DrawingVisual visual = new DrawingVisual();

  29. DrawingContext drawingContext = visual.RenderOpen();

  30. drawingContext.DrawImage(bitmapSource,

  31. new Rect(0, 0, bitmapSource.Width, bitmapSource.Height));

  32. double dpi = bitmapSource.DpiX;

  33. // Some images don't contain dpi info.

  34. _resizeFactor = (dpi == 0) ? 1 : 96 / dpi;

  35. _faceDescriptions = new String[_faceList.Count];

  36. for (int i = 0; i < _faceList.Count; ++i)

  37. {

  38. DetectedFace face = _faceList[i];

  39. //画方框

  40. drawingContext.DrawRectangle(

  41. Brushes.Transparent,

  42. new Pen(Brushes.Red, 2),

  43. new Rect(

  44. face.FaceRectangle.Left * _resizeFactor,

  45. face.FaceRectangle.Top * _resizeFactor,

  46. face.FaceRectangle.Width * _resizeFactor,

  47. face.FaceRectangle.Height * _resizeFactor

  48. )

  49. );

  50. _faceDescriptions[i] = FaceDescription(face);

  51. }

  52. drawingContext.Close();

  53. RenderTargetBitmap faceWithRectBitmap = new RenderTargetBitmap(

  54. (int)(bitmapSource.PixelWidth * _resizeFactor),

  55. (int)(bitmapSource.PixelHeight * _resizeFactor),

  56. 96,

  57. 96,

  58. PixelFormats.Pbgra32);

  59. faceWithRectBitmap.Render(visual);

  60. FacePhoto.Source = faceWithRectBitmap;

  61. faceDescriptionStatusBar.Text = _defaultStatusBarText;

  62. }

  63. }

调用SDK进行识别

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

 
  1. // 上传图片使用faceclient识别

  2. private async Task<IList<DetectedFace>> UploadAndDetectFaces(string imageFilePath)

  3. {

  4. IList<FaceAttributeType> faceAttributes =

  5. new FaceAttributeType[]

  6. {

  7. FaceAttributeType.Gender, FaceAttributeType.Age,

  8. FaceAttributeType.Smile, FaceAttributeType.Emotion,

  9. FaceAttributeType.Glasses, FaceAttributeType.Hair

  10. };

  11. using (Stream imageFileStream = File.OpenRead(imageFilePath))

  12. {

  13. IList<DetectedFace> faceList =

  14. await _faceClient.Face.DetectWithStreamAsync(

  15. imageFileStream, true, false, faceAttributes);

  16. return faceList;

  17. }

  18. }

显示脸部的描述

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

 
  1. /// <summary>

  2. /// 鼠标移动显示脸部描述

  3. /// </summary>

  4. /// <param name="sender"></param>

  5. /// <param name="e"></param>

  6. private void FacePhoto_MouseMove(object sender, MouseEventArgs e)

  7. {

  8. if (_faceList == null)

  9. return;

  10. Point mouseXY = e.GetPosition(FacePhoto);

  11. ImageSource imageSource = FacePhoto.Source;

  12. BitmapSource bitmapSource = (BitmapSource)imageSource;

  13. var scale = FacePhoto.ActualWidth / (bitmapSource.PixelWidth / _resizeFactor);

  14. bool mouseOverFace = false;

  15. for (int i = 0; i < _faceList.Count; ++i)

  16. {

  17. FaceRectangle fr = _faceList[i].FaceRectangle;

  18. double left = fr.Left * scale;

  19. double top = fr.Top * scale;

  20. double width = fr.Width * scale;

  21. double height = fr.Height * scale;

  22. if (mouseXY.X >= left && mouseXY.X <= left + width &&

  23. mouseXY.Y >= top && mouseXY.Y <= top + height)

  24. {

  25. faceDescriptionStatusBar.Text = _faceDescriptions[i];

  26. mouseOverFace = true;

  27. break;

  28. }

  29. }

  30. if (!mouseOverFace) faceDescriptionStatusBar.Text = _defaultStatusBarText;

  31. }

 
  1. /// <summary>

  2. /// 脸部描述

  3. /// </summary>

  4. /// <param name="face"></param>

  5. /// <returns></returns>

  6. private string FaceDescription(DetectedFace face)

  7. {

  8. StringBuilder sb = new StringBuilder();

  9. sb.Append("人脸: ");

  10. // 性别年龄

  11. sb.Append(face.FaceAttributes.Gender.Value == Gender.Female ? "女性" : "男性");

  12. sb.Append(", ");

  13. sb.Append(face.FaceAttributes.Age.ToString() + "岁");

  14. sb.Append(", ");

  15. sb.Append(String.Format("微笑 {0:F1}%, ", face.FaceAttributes.Smile * 100));

  16. // 显示超过0.1的表情

  17. sb.Append("表情: ");

  18. Emotion emotionScores = face.FaceAttributes.Emotion;

  19. if (emotionScores.Anger >= 0.1f) sb.Append(

  20. String.Format("生气 {0:F1}%, ", emotionScores.Anger * 100));

  21. if (emotionScores.Contempt >= 0.1f) sb.Append(

  22. String.Format("蔑视 {0:F1}%, ", emotionScores.Contempt * 100));

  23. if (emotionScores.Disgust >= 0.1f) sb.Append(

  24. String.Format("厌恶 {0:F1}%, ", emotionScores.Disgust * 100));

  25. if (emotionScores.Fear >= 0.1f) sb.Append(

  26. String.Format("恐惧 {0:F1}%, ", emotionScores.Fear * 100));

  27. if (emotionScores.Happiness >= 0.1f) sb.Append(

  28. String.Format("高兴 {0:F1}%, ", emotionScores.Happiness * 100));

  29. if (emotionScores.Neutral >= 0.1f) sb.Append(

  30. String.Format("自然 {0:F1}%, ", emotionScores.Neutral * 100));

  31. if (emotionScores.Sadness >= 0.1f) sb.Append(

  32. String.Format("悲伤 {0:F1}%, ", emotionScores.Sadness * 100));

  33. if (emotionScores.Surprise >= 0.1f) sb.Append(

  34. String.Format("惊喜 {0:F1}%, ", emotionScores.Surprise * 100));

  35. sb.Append(face.FaceAttributes.Glasses);

  36. sb.Append(", ");

  37. sb.Append("头发: ");

  38. if (face.FaceAttributes.Hair.Bald >= 0.01f)

  39. sb.Append(String.Format("秃头 {0:F1}% ", face.FaceAttributes.Hair.Bald * 100));

  40. IList<HairColor> hairColors = face.FaceAttributes.Hair.HairColor;

  41. foreach (HairColor hairColor in hairColors)

  42. {

  43. if (hairColor.Confidence >= 0.1f)

  44. {

  45. sb.Append(hairColor.Color.ToString());

  46. sb.Append(String.Format(" {0:F1}% ", hairColor.Confidence * 100));

  47. }

  48. }

  49. return sb.ToString();

  50. }

运行

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

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

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

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

总结

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

  • 26
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xifenglie123321

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值