using Application.Domain.Entities; using FaceRecognitionDotNet; using Infrastructure.Data; using Infrastructure.Extensions; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Concurrent; using System.IO; using System.Linq; using System.Runtime.InteropServices; namespace UserCenter.Services { public class FaceRecognitionService : IDisposable { private readonly IServiceProvider _serviceProvider; private readonly IHostingEnvironment _env; private readonly FaceRecognition _faceRecognition; private readonly ConcurrentDictionary _faces = new ConcurrentDictionary(); public FaceRecognitionService(IServiceProvider serviceProvider) { this._serviceProvider = serviceProvider; using (var scope = this._serviceProvider.CreateScope()) { this._env = scope.ServiceProvider.GetService(); this._faceRecognition = FaceRecognition.Create(Path.Combine(this._env.WebRootPath, "face")); var userRepo = scope.ServiceProvider.GetService>(); var users = userRepo.ReadOnlyTable().Where(o => o.FaceImage != null).ToList(); foreach (var user in users) { if (!string.IsNullOrEmpty(user.FaceImage)) { try { var faceEndoding = this.GetFaceImageEncoding(user.FaceImage); this._faces.TryAdd(user.UserName, faceEndoding); } catch (Exception ex) { ex.PrintStack(ex.Message); } } } } } private FaceEncoding GetFaceImageEncoding(string faceImage) { var faceImagePath = Path.Combine(this._env.WebRootPath, faceImage.TrimStart('/')); Console.WriteLine(faceImage); using (var img = FaceRecognition.LoadImageFile(faceImagePath)) { var faceEncodings = this._faceRecognition.FaceEncodings(img).ToArray(); if (faceEncodings.Length == 0) { throw new Exception($"cann't find face"); } else if (faceEncodings.Length > 1) { throw new Exception($"find too many faces"); } return faceEncodings.FirstOrDefault(); } } public string FindFace(System.Drawing.Bitmap bitmap) { var userName = ""; var data = this.ToManaged(bitmap); using (var faceImage = FaceRecognition.LoadImage(data, bitmap.Height, bitmap.Width, 3)) { var encodings = this._faceRecognition.FaceEncodings(faceImage).ToArray(); if (encodings.Length > 0) { var encoding = encodings.First(); foreach (var item in this._faces) { if (FaceRecognition.CompareFace(item.Value, encoding, 0.4)) { userName = item.Key; Console.WriteLine($"find user:{userName}"); break; } } } else { Console.WriteLine("can't find face from image"); } foreach (var encoding in encodings) { encoding.Dispose(); } } return userName; } public void AddFace(string userName, string faceImage) { this._faces.TryAdd(userName, this.GetFaceImageEncoding(faceImage)); } public void UpdateFace(string userName, string faceImage) { this.RemoveFace(userName); this.AddFace(userName, faceImage); } public void RemoveFace(string userName) { this._faces.TryRemove(userName, out FaceEncoding face); face.Dispose(); } public byte[] ToManaged(System.Drawing.Bitmap bitmap) { var format = bitmap.PixelFormat; var width = bitmap.Width; var height = bitmap.Height; var array = new byte[width * height * 3]; // bitmap is treated as rgb System.Drawing.Imaging.BitmapData bitmapData = null; try { bitmapData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly, format); Marshal.Copy(bitmapData.Scan0, array, 0, array.Length); } finally { if (bitmapData != null) bitmap.UnlockBits(bitmapData); } return array; } public void Dispose() { foreach (var item in this._faces) { item.Value?.Dispose(); } } } }