效果
Demo下载
项目
VS2022+.net4.8+OpenCvSharp4+DlibDotNet
相关介绍参考
代码
using DlibDotNet;
using OpenCvSharp.Extensions;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization;namespace OpenCvSharp_人脸替换
{public partial class Form1 : Form{public Form1(){InitializeComponent();}Bitmap bmp;string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";string imgPath = "";string startupPath = "";Bitmap bmp2;string imgPath2 = "";FrontalFaceDetector fd;ShapePredictor sp;private void button2_Click(object sender, EventArgs e){OpenFileDialog ofd = new OpenFileDialog();ofd.Filter = fileFilter;if (ofd.ShowDialog() != DialogResult.OK) return;pictureBox1.Image = null;imgPath = ofd.FileName;bmp = new Bitmap(imgPath);pictureBox1.Image = new Bitmap(imgPath);}private void button3_Click(object sender, EventArgs e){OpenFileDialog ofd = new OpenFileDialog();ofd.Filter = fileFilter;if (ofd.ShowDialog() != DialogResult.OK) return;pictureBox2.Image = null;imgPath2 = ofd.FileName;bmp2 = new Bitmap(imgPath2);pictureBox2.Image = new Bitmap(imgPath2);}private void button1_Click(object sender, EventArgs e){if (pictureBox1.Image==null || pictureBox2.Image==null){return;}pictureBox3.Image = ProcessImage(bmp, bmp2);}/// <summary>/// Process the original selfie and produce the face-swapped image./// </summary>/// <param name="image">The original selfie image.</param>/// <param name="newImage">The new face to insert into the selfie.</param>/// <returns>A new image with faces swapped.</returns>public Bitmap ProcessImage(Bitmap image, Bitmap newImage){// convert image to dlib formatvar img = Dlib.LoadImage<RgbPixel>(imgPath);// find bradley's faces in imagevar faces = fd.Operator(img);if (faces.Count()==0){return null;}var bradley = faces[0];// get bradley's landmark pointsvar bradleyShape = sp.Detect(img, bradley);var bradleyPoints = (from i in Enumerable.Range(0, (int)bradleyShape.Parts)let p = bradleyShape.GetPart((uint)i)select new OpenCvSharp.Point(p.X, p.Y)).ToArray();// get convex hull of bradley's pointsvar hull = Cv2.ConvexHullIndices(bradleyPoints);var bradleyHull = from i in hullselect bradleyPoints[i];// find landmark points in face to swapvar imgMark = Dlib.LoadImage<RgbPixel>(imgPath2);var faces2 = fd.Operator(imgMark);if (faces2.Count() == 0){return null;}var mark = faces2[0];var markShape = sp.Detect(imgMark, mark);var markPoints = (from i in Enumerable.Range(0, (int)markShape.Parts)let p = markShape.GetPart((uint)i)select new OpenCvSharp.Point(p.X, p.Y)).ToArray();// get convex hull of mark's pointsvar hull2 = Cv2.ConvexHullIndices(bradleyPoints);var markHull = from i in hull2select markPoints[i];// calculate Delaunay trianglesvar triangles = Utility.GetDelaunayTriangles(bradleyHull);// get transformations to warp the new face onto Bradley's facevar warps = Utility.GetWarps(markHull, bradleyHull, triangles);// apply the warps to the new face to prep it for insertion into the main imagevar warpedImg = Utility.ApplyWarps(newImage, image.Width, image.Height, warps);// prepare a mask for the warped imagevar mask = new Mat(image.Height, image.Width, MatType.CV_8UC3);mask.SetTo(0);Cv2.FillConvexPoly(mask, bradleyHull, new Scalar(255, 255, 255), LineTypes.Link8);// find the center of the warped facevar r = Cv2.BoundingRect(bradleyHull);var center = new OpenCvSharp.Point(r.Left + r.Width / 2, r.Top + r.Height / 2);// blend the warped face into the main imagevar selfie = BitmapConverter.ToMat(image);var blend = new Mat(selfie.Size(), selfie.Type());Cv2.SeamlessClone(warpedImg, selfie, mask, center, blend, SeamlessCloneMethods.NormalClone);// return the modified main imagereturn BitmapConverter.ToBitmap(blend);}private void Form1_Load(object sender, EventArgs e){fd = Dlib.GetFrontalFaceDetector();sp = ShapePredictor.Deserialize("shape_predictor_68_face_landmarks.dat");Dlib.Encoding = Environment.OSVersion.Platform == PlatformID.Win32NT ? Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.ANSICodePage) : Encoding.UTF8;}}
}