• C#如何实现视频换脸功能?
  • 发布于 1周前
  • 55 热度
    0 评论
效果

代码
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
 
namespace FaceFusionSharp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        string fileFilter = "图片|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
 
        string startupPath = "";
 
        string source_path = "";
 
        Yolov8Face detect_face;
        Face68Landmarks detect_68landmarks;
        FaceEmbdding face_embedding;
        SwapFace swap_face;
        FaceEnhance enhance_face;
 
        /// <summary>
        /// 选择头像
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;
            if (ofd.ShowDialog() != DialogResult.OK) return;
 
            pictureBox1.Image = null;
 
            source_path = ofd.FileName;
            pictureBox1.Image = new Bitmap(source_path);
        }
 
        string video_path = "";
        string videoFilter = "视频|*.mp4;*.avi;";
 
        /// <summary>
        /// 目标视频
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = videoFilter;
            ofd.InitialDirectory = Application.StartupPath + "\\test";
            if (ofd.ShowDialog() != DialogResult.OK) return;
 
            video_path = ofd.FileName;
            textBox1.Text = video_path;
 
            //读取第一帧显示
            VideoCapture vcapture = new VideoCapture(video_path);
            if (!vcapture.IsOpened())
            {
                MessageBox.Show("打开视频文件失败");
                video_path = "";
                return;
            }
            Mat frame = new Mat();
            if (vcapture.Read(frame))
            {
                pictureBox2.Image = new Bitmap(frame.ToMemoryStream());
                frame.Dispose();
            }
            else {
                MessageBox.Show("读取视频文件失败");
                video_path = "";
            }
 
        }
 
        List<Bbox> boxes = new List<Bbox>();
        Mat source_img=new Mat();
 
        VideoWriter vwriter;
        bool saveDetVideo = false;
 
        private void button1_Click(object sender, EventArgs e)
        {
            if (source_path=="")
            {
                MessageBox.Show("请选择头像");
                return;
            }
 
            if (video_path == "")
            {
                MessageBox.Show("请选择目标视频");
                return;
            }
 
            button1.Enabled = false;
            Application.DoEvents();
 
            source_img = Cv2.ImRead(source_path);
            boxes = detect_face.detect(source_img);
            if (boxes.Count == 0)
            {
                MessageBox.Show("头像中未检测到人脸!");
                button1.Enabled = true;
                return;
            }
 
            if (boxes.Count > 1)
            {
                MessageBox.Show("头像中检测到多张人脸,默认使用第一张!");
                button1.Enabled = true;
                return;
            }
 
            Application.DoEvents();
            Thread thread = new Thread(new ThreadStart(Swap));
            thread.Start();
            thread.Join();
 
            button1.Enabled = true;
            textBox1.Text = "执行完成!";
        }
 
        void Swap() {
 
            int position = 0; //一张图片里可能有多个人脸,这里只考虑1个人脸的情况
            List<Point2f> face68landmarks = detect_68landmarks.detect(source_img, boxes[position]);
 
            List<float> source_face_embedding = face_embedding.detect(source_img, face68landmarks);
 
            VideoCapture vcapture = new VideoCapture(video_path);
            Mat target_img = new Mat();
 
            if (checkBox1.Checked)
            {
                vwriter = new VideoWriter("out.mp4", FourCC.X264, vcapture.Fps, new OpenCvSharp.Size(vcapture.FrameWidth*2, vcapture.FrameHeight));
                saveDetVideo = true;
            }
            else
            {
                saveDetVideo = false;
            }
 
            Cv2.NamedWindow("FaceFusionSharp 按下ESC,退出", WindowFlags.Normal);
            Cv2.ResizeWindow("FaceFusionSharp 按下ESC,退出", vcapture.FrameWidth, vcapture.FrameHeight / 2);
 
            while (vcapture.Read(target_img))
            {
                boxes = detect_face.detect(target_img);
                if (boxes.Count == 0)
                {
                    //MessageBox.Show("Target中未检测到人脸!");
                    continue;
                }
 
                if (boxes.Count > 1)
                {
                    //MessageBox.Show("Target中检测到多张人脸,默认使用第一张!");
                }
 
                position = 0; //一张图片里可能有多个人脸,这里只考虑1个人脸的情况
                List<Point2f> target_landmark_5;
                target_landmark_5 = detect_68landmarks.detect(target_img, boxes[position]);
 
                Mat swapimg = swap_face.process(target_img, source_face_embedding, target_landmark_5);
 
                Mat resultimg = enhance_face.process(swapimg, target_landmark_5);
 
                Mat resultCompare = Mat.Zeros(target_img.Rows, target_img.Cols * 2, target_img.Type());
                Cv2.HConcat(new Mat[] { target_img, resultimg }, resultCompare);
 
                if (saveDetVideo)
                {
                    vwriter.Write(resultCompare);
                }
 
                Cv2.ImShow("FaceFusionSharp 按下ESC,退出", resultCompare);
 
                if (Cv2.WaitKey(1) == 27 || Cv2.GetWindowProperty("FaceFusionSharp 按下ESC,退出", WindowPropertyFlags.Visible) < 1.0)
                {
                    break;
                }
 
            }
 
            Cv2.DestroyAllWindows();
            vcapture.Release();
            if (saveDetVideo)
            {
                vwriter.Release();
            }
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            detect_face = new Yolov8Face("model/yoloface_8n.onnx");
            detect_68landmarks = new Face68Landmarks("model/2dfan4.onnx");
            face_embedding = new FaceEmbdding("model/arcface_w600k_r50.onnx");
            swap_face = new SwapFace("model/inswapper_128.onnx");
            enhance_face = new FaceEnhance("model/gfpgan_1.4.onnx");
 
            //target_path = "images/target.jpg";
            //source_path = "images/5.jpg";
 
            //target_path = "images/5.jpg";
            //source_path = "images/14.jpg";
            // 堆代码 duidaima.com
            //pictureBox1.Image = new Bitmap(source_path);
            //pictureBox2.Image = new Bitmap(target_path);
        }
    }
}

用户评论