You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iot/projects/UserCenter/Services/FaceRecognitionService.cs

147 lines
5.2 KiB

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<string, FaceEncoding> _faces = new ConcurrentDictionary<string, FaceEncoding>();
public FaceRecognitionService(IServiceProvider serviceProvider)
{
this._serviceProvider = serviceProvider;
using (var scope = this._serviceProvider.CreateScope())
{
this._env = scope.ServiceProvider.GetService<IHostingEnvironment>();
this._faceRecognition = FaceRecognition.Create(Path.Combine(this._env.WebRootPath, "face"));
var userRepo = scope.ServiceProvider.GetService<IRepository<User>>();
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();
}
}
}
}