.NET做人脸识别并分类的实现示例(3)

var cache = new Cache<List<DetectedFace>>(); // 重点 Dictionary<Guid, (string file, DetectedFace face)> faces = GetFiles(inFolder) .AsParallel() .Select(file => (file: file, faces: cache.GetOrCreate(file, () => // 重点 { byte[] bytes = CompressImage(file); var result = (file, faces: fc.Face.DetectWithStreamAsync(new MemoryStream(bytes)).GetAwaiter().GetResult()); (result.faces.Count == 0 ? $"{file} not detect any face!!!" : $"{file} detected {result.faces.Count}.").Dump(); return result.faces.ToList(); }))) .SelectMany(x => x.faces.Select(face => (x.file, face))) .ToDictionary(x => x.face.FaceId.Value, x => (file: x.file, face: x.face));

将人脸框起来

照片太多,如果活动很大,或者合影中有好几十个人,分出来的组,将长这个样子:

.NET做人脸识别并分类的实现示例

完全不知道自己的脸在哪,因此需要将检测到的脸框起来。

注意框起来的过程,也很有技巧,回忆一下,上传时的照片本来就是压缩和旋转过的,因此返回的DetectedFace对象值,它也是压缩和旋转过的,如果不进行压缩和旋转,找到的脸的位置会完全不正确,因此需要将之前的计算过程重新演算一次:

using var bmp = Bitmap.FromFile(item.info.file); HandleOrientation(bmp, bmp.PropertyItems); using (var g = Graphics.FromImage(bmp)) { using var brush = new SolidBrush(Color.Red); using var pen = new Pen(brush, 5.0f); var rect = item.info.face.FaceRectangle; float scale = Math.Max(1.0f, (float)(1.0 * Math.Max(bmp.Width, bmp.Height) / 1920.0)); g.ScaleTransform(scale, scale); g.DrawRectangle(pen, new Rectangle(rect.Left, rect.Top, rect.Width, rect.Height)); } bmp.Save(Path.Combine(dir, Path.GetFileName(item.info.file)));

使用我上面的那张照片,检测结果如下(有点像相机对焦时人脸识别的感觉):

.NET做人脸识别并分类的实现示例

1000个脸的限制

.GroupAsync方法一次只能检测1000个FaceId,而上次活动800多张照片中有超过2000个FaceId,因此需要做一些必要的分组。

分组最简单的方法,就是使用System.Interactive包,它提供了Rx.NET那样方便快捷的API(这些API在LINQ中未提供),但又不需要引入Observable<T>那样重量级的东西,因此使用起来很方便。

这里我使用的是.Buffer(int)函数,它可以将IEnumerable<T>按指定的数量(如1000)进行分组,代码如下:

foreach (var buffer in faces .Buffer(1000) .Select((list, groupId) => (list, groupId)) { GroupResult group = await fc.Face.GroupAsync(buffer.list.Select(x => x.Key).ToList()); var folder = outFolder + @"\gid-" + buffer.groupId; CopyGroup(folder, group, faces); }

总结

文中用到的完整代码,全部上传了到我的博客数据Github,只要输入图片和key,即可直接使用和运行:
https://github.com/sdcb/blog-data/tree/master/2019/20191122-dotnet-face-detection

这个月我参加了上海的.NET Conf,我上述代码对.NET Conf的800多张照片做了分组,识别出了2000多张人脸,我将其中我的照片的前三张找出来,结果如下:

.NET做人脸识别并分类的实现示例


.NET做人脸识别并分类的实现示例


.NET做人脸识别并分类的实现示例


......

总的来说,这个效果还挺不错,渣渣分辨率的照片的脸都被它找到了😂。

注意,不一定非得用Azure Cognitive Services来做人脸识别,国内还有阿里云等厂商也提供了人脸识别等服务,并提供了.NET接口,无非就是调用API,注意其限制,代码总体差不多。

另外,如有离线人脸识别需求,Luxand提供了还有离线版人脸识别SDK,名叫Luxand FaceSDK,同样提供了.NET接口。因为无需网络调用,其识别更快,匹配速度更是可达每秒5千万个人脸数据,精度也非常高,亲测好用,目前最新版是v7.1.0,授权昂贵(但百度有惊喜)。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdsyyx.html