免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2150 | 回复: 0
打印 上一主题 下一主题

[互操作系统] 转发分享【Win10 应用开发】人脸识别 [复制链接]

论坛徽章:
2
操作系统版块每日发帖之星
日期:2015-06-26 22:20:00每日论坛发贴之星
日期:2015-06-26 22:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-06-25 11:07 |只看该作者 |倒序浏览
可能你会认为人脸识别用起来会很复杂,老周当初也这么想,但通过实际操作后,我发现非然。

经过微软封装的东西,向来都是复杂问题简单化,只要用得舒心,代码越少越好,用最少的代码做最多的事情,此为大师境界也。

好,屁话不说,先介绍一下如何完成人脸识别(或者叫人脸检测,随你怎么翻译,反正知道是怎么一回事就行)。核心的类是FaceDetector,不要问我这个类在哪里,自己打开对象浏览器搜索。

第一步,访问静态属性IsSupported,看看当前平台是不是支持人脸识别,如果返回false,那就没戏了。

第二步,调用静态方法CreateAsync得到一个FaceDetector实例,所以该类不需要手动实例化,初始化过程由运行库来完成,然后把初始化好的实例返回给咱们,然后就可以用它来干活了。

第三步,调用实例方法DetectFacesAsync进行识别,识别完后会返回一个DetectedFace列表,每个DetectedFace表示一张脸,因为你用来识别的照片中可能包含N张脸。FaceBox属性包含了人脸的矩形区域,就是人脸位于整张照片的哪个位置,可通过X,Y坐标描述矩形的左上角位置,并用宽度和高度来表明那张脸的大小。

DetectFacesAsync方法需要一个SoftwareBitmap类型的参数,该参数就是你要用来识别人脸的图像。

可能大家已经知道,通过BitmapDecoder类的GetSoftwareBitmapAsync方法可以返回一个SoftwareBitmap实例,不过要注意的是,FaceDetector在进行检测时并不是所有像素格式都支持,可以调用GetSupportedBitmapPixelFormats方法来获取所有受支持的像素格式列表,经老周测试,该方法返回Nv12和Gray8,也就是当前只支持这两种格式。当然,你也可以通过IsBitmapPixelFormatSupported方法来验证一下某个像素格式是否被支持。



好了,基本用法已经说完了,确实不是很复杂。下面,老周给大家演示一个例子,该例子允许你选择一张照片,然后识别出照片上的人脸,并用一个矩形来标记。

先看看UI的设计,主要的XAML如下:
  1. <Grid>
  2.             <Grid.RowDefinitions>
  3.                 <RowDefinition Height="auto"/>
  4.                 <RowDefinition Height="*"/>
  5.                 <RowDefinition Height="auto"/>
  6.             </Grid.RowDefinitions>
  7.             <Button Content="选择要识别的照片" Click="OnClick"/>
  8.             <Viewbox  Grid.Row="1" Margin="5" Stretch="Uniform" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
  9.                 <Canvas Name="cv" Width="{x:Bind img.Width,Mode=OneWay}" Height="{x:Bind img.Height,Mode=OneWay}" >
  10.                     <Image Name="img" Stretch="None"/>
  11.                 </Canvas>
  12.             </Viewbox>
  13.             
  14.             <TextBlock Name="tbMessage" Foreground="Red" FontSize="16" Grid.Row="2"/>
  15.         </Grid>
复制代码
为啥我要用一个ViewBox呢,因为这个控件有一个好处,就是会自动将它里面的可视化对象进行缩放,待会儿我要在Image上显示图片,而且还要用到Rectangle元素来标记人脸的位置,为了让绝对坐标计算起来能与原图相等,就把这些内容都放在ViewBox中,让Viewbox来进行缩放,这样一来,就能够根据窗口的大小自动调整显示区域了。

之所以用Canvas,是因它是绝对坐标定位的,这方便我稍后放置Rectangle元素。



处理按钮事件,通过OpenFilePicker来打开图像文件。
  1. FileOpenPicker picker = new FileOpenPicker();
  2.             picker.FileTypeFilter.Add(".jpg");
  3.             picker.FileTypeFilter.Add(".jpeg");
  4.             picker.FileTypeFilter.Add(".png");

  5.             StorageFile file = await picker.PickSingleFileAsync();
复制代码
记得以前跟大家讲过,picker调用后要挂起当前应用,并通过响应应用激活来处理获取的文件,这是在WP 8.1的文章中说过,但是,现在不用了,很简单,因为Windows Phone App和Windows App已经完全统一了,所以不必再考虑平台隔离的代码了。

下面代码完成两件事:1、在Image控件上显示图像;2、进行识别,并用矩形标记人脸位置。
  1. if (file != null)
  2.             {
  3.                 using (IRandomAccessStream streamIn= await file.OpenReadAsync())
  4.                 {
  5.                     // 对图像文件进行解码
  6.                     BitmapDecoder decoder = await BitmapDecoder.CreateAsync(streamIn);
  7.                     // 获取图像内容
  8.                     SoftwareBitmap sbmp = await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight);

  9.                     WriteableBitmap bmp = new WriteableBitmap(sbmp.PixelWidth, sbmp.PixelHeight);
  10.                     sbmp.CopyToBuffer(bmp.PixelBuffer);
  11.                     this.img.Source = bmp;
  12.                     img.Width = bmp.PixelWidth;
  13.                     img.Height = bmp.PixelHeight;

  14.                     // 通过循环,尝试以各种受支持的格式来进行识别
  15.                     // 如果识别顺利,就跳出循环
  16.                     // 否则进入下一轮循环
  17.                     int n = 0;
  18.                     while (n < formats.Count)
  19.                     {
  20.                         if (FaceDetector.IsBitmapPixelFormatSupported(formats[n]))
  21.                         {
  22.                             FaceDetector detector = await FaceDetector.CreateAsync();
  23.                             try
  24.                             {
  25.                                 // 转换图像像素格式
  26.                                 SoftwareBitmap sbmp2 = SoftwareBitmap.Convert(sbmp, formats[n]);
  27.                                 // 进行检测
  28.                                 IList<DetectedFace> results = await detector.DetectFacesAsync(sbmp2);

  29.                                 // 清理Canvas中的矩形
  30.                                 while (cv.Children.Count > 1)
  31.                                     cv.Children.RemoveAt(cv.Children.Count - 1);
  32.                                 // 在界面上添加矩形
  33.                                 for (int i = 0; i < results.Count; i++)
  34.                                 {
  35.                                     DetectedFace dface = results[i];
  36.                                     Rectangle rect = new Rectangle();

  37.                                     rect.Stroke = new SolidColorBrush(Colors.Yellow);
  38.                                     rect.StrokeThickness = 5d;
  39.                                     // 定位矩形
  40.                                     Canvas.SetLeft(rect, dface.FaceBox.X);
  41.                                     Canvas.SetTop(rect, dface.FaceBox.Y);
  42.                                     rect.Width = dface.FaceBox.Width;
  43.                                     rect.Height = dface.FaceBox.Height;
  44.                                     cv.Children.Add(rect);
  45.                                 }
  46.                                 tbMessage.Text = "人脸识别完成。";
  47.                                 break;
  48.                             }
  49.                             catch
  50.                             {
  51.                                 tbMessage.Text = "人脸识别失败。";
  52.                                 n++;
  53.                             }
  54.                             //cv.InvalidateArrange();
  55.                         }
  56.                     }

  57.                 }
复制代码
因为我要在Image上显示图像,所以从decoder中得到的SoftwareBitmap不能直接用于识别,原因是我刚才说了,目前SDK的人脸识别只支持少量的像素格式,Bgra8是不受支持的,所以可以用SoftwareBitmap的Convert方法转换格式,并返回转换后的SoftwareBitmap对象。

这里我用一个while循环来完成识别:
  1. int n = 0;
  2.                     while (n < formats.Count)
  3.                     {
  4.                         if (FaceDetector.IsBitmapPixelFormatSupported(formats[n]))
  5.                         {
  6.                             FaceDetector detector = await FaceDetector.CreateAsync();
  7.                             try
  8.                             {
  9.                                 ……
  10.                                 break;
  11.                             }
  12.                             catch
  13.                             {
  14.                                 ……
  15.                                 n++;
  16.                             }
  17.                         }
复制代码
意思是,我用FaceDetector所支持的所有像素格式都去尝试进行识别,只要其中有一种格式能够顺利完成识别,就终止循环(break);如果第一种格式不能识别,就把n++来使用第二种格式来识别。

=============================================

示例的大致情况就是这样,做完后我们当然要来试试效果了。

首先,来检测一下八戒的猪脸。

很显然,猪脸也能检测出来,不错。



转载自:http://www.cnblogs.com/tcjiaan/p/4599307.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP