利用DlibDotNet和OpenCvSharp实现头像裁剪
起因:由于OA入职后提供的人员照片需要经过裁剪后再上传至门禁等其他需要使用到人脸的系统,虽然有小软件可以解决需求,但是还是希望通过自动化的形式进行处理,参考网上的资料和官方示例,大致实现了功能
using DlibDotNet; using OpenCvSharp; using DlibDotNet.Extensions; Console.WriteLine("Hello, World!"); var InputImage_str = @"D:\test\aaa.jpg"; var OutputImage_str = @"D:\test\bbb.jpg"; var Predictor_str = @"D:\Code\DlibDotNet-master\test\DlibDotNet.Tests\data\shape_predictor_68_face_landmarks.dat"; var mat = Cv2.ImRead(InputImage_str, ImreadModes.AnyColor); var array = new byte[mat.Width * mat.Height * mat.ElemSize()]; System.Runtime.InteropServices.Marshal.Copy(mat.Data, array, 0, array.Length); using var inputImage = Dlib.LoadImageData<BgrPixel>(array, (uint)mat.Height, (uint)mat.Width, (uint)(mat.Width * mat.ElemSize())); var angle_list = new[] { 0, 30, 60, 90, 120, 180, 210, 240, 270, 300, 330 }; Func<Array2D<BgrPixel>, int, Array2D<BgrPixel>> GetPositiveImage = (Array2D<BgrPixel> intpuImgae, int angle) => { var outputImage = new Array2D<BgrPixel>(intpuImgae.Rows, intpuImgae.Columns); Dlib.RotateImage(intpuImgae, outputImage, angle); var dets = Dlib.GetFrontalFaceDetector().Operator(outputImage); if (dets == null || dets.Length == 0) return null; return outputImage; }; var outputImage = angle_list.Select(x => GetPositiveImage(inputImage, x)).FirstOrDefault(x => x != null); if (outputImage == null) throw new Exception("未能找到人像"); var det = Dlib.GetFrontalFaceDetector().Operator(outputImage).MaxBy(x=>x.Width * x.Height); var Predictor = DlibDotNet.ShapePredictor.Deserialize(Predictor_str); var shape = Predictor.Detect(outputImage, det); var chipLocations = Dlib.GetFaceChipDetails(new[] { shape }, 200u, 0.8); using var faceChips = Dlib.ExtractImageChips<RgbPixel>(outputImage, chipLocations); using var tileImage = Dlib.TileImages(faceChips); tileImage.ToBitmap().Save(OutputImage_str); using var win = new ImageWindow(); using var winFaces = new ImageWindow(); var lines = Dlib.RenderFaceDetections(new[] { shape }); win.ClearOverlay(); win.SetImage(outputImage); win.AddOverlay(lines); winFaces.SetImage(tileImage); Console.WriteLine("hit enter to process next frame"); Console.ReadKey();