c # Winform usa Opencvsharp4 para realizar un reconocimiento facial simple

     Configuración del entorno: vs2019, .Net FrameWork 4.8 Opencvsharp4

      Simplemente descargue el último Opencvsharp4 en Nuget,

       Permítanme hablar sobre el principio del reconocimiento facial tal como lo entiendo, es decir, primero le damos al entrenador algunos datos de entrenamiento, es decir, le decimos al entrenador a quién corresponden esos datos, y luego el entrenador recuerda las características de estas imágenes y el correspondiente El nombre de la persona, y luego descubra las características de la imagen de reconocimiento durante el reconocimiento, y luego compárela con las características entrenadas, descubra la característica más cercana a ella en el conjunto de entrenamiento, y dé su nombre correspondiente, y similitud, eso es Score.

      En Opencvsharp4, hay módulos correspondientes. En OpenCvSharp.Face, FaceRecognizer es el entrenador que necesitamos. Tenga en cuenta que al agregar el conjunto de entrenamiento, los datos de entrenamiento que damos son, la imagen y el número de identificación correspondiente, cuando se convierte en un nombre, nosotros puede Al agregar el conjunto de entrenamiento, guarde el nombre correspondiente usted mismo. Al dar el resultado del entrenamiento, use el número de identificación dado para encontrar el nombre correspondiente; y al agregar el conjunto de entrenamiento, coloque la foto de la misma cara en el mismo directorio, es decir, un nombre puede corresponder a varias caras diferentes, pero una cara solo puede tener un nombre; al agregar un conjunto de entrenamiento y realizar el reconocimiento facial, el tamaño de la imagen debe ser el mismo; agregue al menos dos conjuntos de imagen de entrenamiento

     Implementación de la interfaz:

    Interfaz simple de Winform, todos los controles son autónomos

     También puse la imagen de entrenamiento agregada en la interfaz. Por supuesto, también se puede modificar directamente en el conjunto de entrenamiento local, pero debe tenerse en cuenta que el tamaño de la imagen debe ser consistente.

Resultados de carrera aproximados

 Código principal:

Primero, defina un entrenador

  public static FaceRecognizer faceRecongnizer = FisherFaceRecognizer.Create();

Luego defina una clase personalizada que vincule la imagen a la ID

    class yImgs
    {
        // 图像
        public Mat Image { set; get; }
        // 编号 
        public int ImageGroupId { set; get; }
    }

       Use una List<yImgs> para almacenar datos de entrenamiento. La razón por la que no uso un diccionario es: 1. Si el número es la clave y la imagen es el valor, un número, es decir, una persona solo puede agregar uno imagen, y use List<Mat> como El valor del diccionario también es problemático. Es mejor usar una Lista directamente. 2. Si usa la imagen como Clave y el número como Valor, la imagen no se puede repetir, es decir, una persona no puede agregar dos imágenes idénticas como imágenes de entrenamiento, y usando List<yImgs>, puede agregar dos imágenes iguales como imágenes de entrenamiento.

      Después de tener esta Lista, definimos un diccionario para vincular el número y el nombre de la persona, y el nombre duplicado no se considera aquí.

 public static Dictionary<int, string> namesDatas = new Dictionary<int, string>();

     Luego podemos agregar imágenes de entrenamiento.Actualmente agrego imágenes localmente, las configuro en el formato deseado y luego leo toda la información de la imagen del local antes del entrenamiento.

        /// <summary>
        /// 添加训练集图片 即把指定图片调整为指定大小 并保存在训练集路径中
        /// 同一人的照片都放在一个文件夹内 该文件夹的名字为 名字ID_名字,如:1_Lena 
        /// 图片名字是按顺序自己生成的  1.jpg  2.jpg....
        /// </summary>
        /// <param name="src">训练图像</param>
        /// <param name="size">图像大小</param>
        /// <param name="groupId">编号,与名字一一对应</param>
        /// <param name="name">名字</param>
        public static void AddTrainImg(Mat src, OpenCvSharp.Size size,int groupId,string name)
        {
            string path0 = groupId.ToString() + "_" + name;
            string path = yVars.path + "\\" + path0 + "\\";
            // 判断图像是否可以作为训练图像添加 
            // 即 图像包含人脸 且只有一张人脸 
            if (yMethods.TrainImgISOK(src) == false)
            {
                return;
            }
            try
            {
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
            }
            catch (Exception ex)
            {
                YXH._01.yMessagebox.ShowDialogCN("路径创建失败:" + ex.Message);
                return;
            }
            DirectoryInfo _path = new DirectoryInfo(path);
            int i = 0;
            do
            {
                i++;
            } while (File.Exists(path + i.ToString() + ".jpg"));
            string picname = path + i.ToString() + ".jpg";
            try
            {
                Cv2.Resize(src, src, size);
                src.SaveImage(picname);
                yVars.TrainAgain = true;
                YXH._01.yMessagebox.ShowDialogCN("训练图像添加成功");
            }
            catch (Exception ex)
            {
                YXH._01.yMessagebox.ShowDialogCN("训练图像添加失败:" + ex.Message);
            }
        }

El formato agregado localmente es el siguiente

     Después de agregar localmente las imágenes del conjunto de entrenamiento, se lee la información local y se entrena al entrenador. Es para asignarle un valor al List<yImgs> que definimos al principio, y usarlo para entrenar al entrenador.

        // 读取本地信息
        private static bool GetInfos()
        {
            // 把原先的信息清空 
            yVars.faceDatas.Clear(); // 训练数据 List<yImgs>
            yVars.namesDatas.Clear(); // 字典  Dictionary<int, string>
            DirectoryInfo _path = new DirectoryInfo(yVars.path); //训练集存放路径

            if (_path.GetDirectories().Length < 2)
            {
                YXH._01.yMessagebox.ShowDialogCN("本地训练集小于两组,请添加训练集");
                return false;
            }
            if (yFiles.DirectoryHasTwoGroup(yVars.path) == false)
            {
                YXH._01.yMessagebox.ShowDialogCN("本地训练集小于两组,请添加训练集");
                return false;
            } 

            foreach (DirectoryInfo var in _path.GetDirectories())
            {
                string[] tempstr = var.ToString().Split('_');
                int groupID = 0;
                int.TryParse(tempstr[0], out groupID);
                foreach (FileInfo vv in var.GetFiles())
                {
                    if (!vv.FullName.Contains(".jpg"))
                        continue;
                    yVars.faceDatas.Add(
                        new yImgs
                        {
                            Image = new Mat(vv.FullName, ImreadModes.Grayscale),
                            ImageGroupId = groupID,
                        });
                }
                yVars.namesDatas.Add(groupID, tempstr[1]);
            }
            return true;
        }

Para el entrenamiento, simplemente llame directamente al método de entrenamiento del entrenador

  yVars.faceRecongnizer.Train(yVars.faceDatas.Select(x => x.Image), yVars.faceDatas.Select(x => x.ImageGroupId));

Se puede reconocer después del entrenamiento.

Los pasos aproximados son los siguientes:

1. Obtenga todas las imágenes de caras de la imagen reconocida y ajuste estas imágenes de caras al mismo tamaño que el conjunto de entrenamiento (puede haber varias caras en la imagen de reconocimiento y solo puede haber una cara en la imagen de entrenamiento)

        // 从图片中获取所有的人脸图片 并调整为指定大小
        private static List<Mat> GetFaces(Mat mm, OpenCvSharp.Rect[] rects, OpenCvSharp.Size size)
        {
            List<Mat> faces = new List<Mat>();
            foreach (Rect rect in rects)
            {
                Mat m1 = new Mat(mm, rect);
                Cv2.CvtColor(m1, m1, ColorConversionCodes.BGR2GRAY);
                Cv2.Resize(m1, m1, size);
                // Cv2.EqualizeHist(m1, m1);
                faces.Add(m1);
            }
            return faces;
        }

2. Obtenga las posiciones de todas las caras de arriba

        // 获取图像所有的人脸框
        private static OpenCvSharp.Rect[] GetRects(Mat mm)
        {
            Mat grayImage = new Mat();
            Cv2.CvtColor(mm, grayImage, ColorConversionCodes.BGR2GRAY);
            Cv2.EqualizeHist(grayImage, grayImage);
            string path = System.Windows.Forms.Application.StartupPath + "\\xml\\haarcascades\\" + "haarcascade_frontalface_alt.xml";
            CascadeClassifier face = new CascadeClassifier(path); 
            Rect[] faces = face.DetectMultiScale(mm);
            return faces;
        }

3. Reconoce todas las fotos de caras obtenidas y obtén sus nombres correspondientes

        // 获取所有名字
        private static List<string> GetNames(List<Mat> mm)
        {
            List<string> names = new List<string>();
            for (int i = 0; i < mm.Count; i++)
            {
                int groupId = -2;
                //groupId = yVars.FaceDetect.faceRecongnizer.Predict(mm[i]);
                double confidence = 0.0;
                yVars.faceRecongnizer.Predict(mm[i], out groupId, out confidence);
                string desName;
                yVars.namesDatas.TryGetValue(groupId, out desName);
                // names.Add(desName + " " + confidence.ToString("0.00"));
                names.Add(desName);
            }
            return names;
        }

4. Finalmente, dibuja todos los nombres en las posiciones correspondientes.

        // 画出所有的框和名字
        public static Mat ShowFaceRects(Mat mm, Rect[] faces, List<string> names)
        {
            Random rnd = new Random();
            int i = -1;
            foreach (Rect face in faces)
            {
                i++;
                Scalar color = new Scalar(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255));
                Cv2.Rectangle(mm, face, color);
                // 无法显示中文 可以考虑用  System.Drawing.Graphics
                Cv2.PutText(mm, names[i], face.TopLeft, HersheyFonts.HersheySimplex, 0.8, new Scalar(255, 23, 0));
            }
            return mm;
        }

Tenga en cuenta que al escribir el nombre, si usa Cv2.PutText, el nombre no puede estar en chino

De esta manera, se realiza un reconocimiento facial simple.

Supongo que te gusta

Origin blog.csdn.net/Iawfy_/article/details/125495355
Recomendado
Clasificación