c#Winform utilise Opencvsharp4 pour réaliser une reconnaissance faciale simple

     Configuration de l'environnement : vs2019, .Net FrameWork 4.8 Opencvsharp4

      Téléchargez simplement le dernier Opencvsharp4 dans Nuget,

       Permettez-moi de parler du principe de la reconnaissance faciale tel que je le comprends, c'est-à-dire que nous donnons d'abord au formateur des données d'entraînement, c'est-à-dire que nous disons au formateur à qui correspondent ces données, puis le formateur se souvient des caractéristiques de ces images et de la correspondant Le nom de la personne, puis découvrez les caractéristiques de l'image de reconnaissance lors de la reconnaissance, puis comparez-la avec les caractéristiques formées, recherchez la caractéristique qui lui est la plus proche dans l'ensemble de formation et donnez son nom correspondant, et similarité, c'est-à-dire Score.

      Dans Opencvsharp4, il existe des modules correspondants. Dans OpenCvSharp.Face, FaceRecognizer est l'entraîneur dont nous avons besoin. Notez que lors de l'ajout de l'ensemble d'entraînement, les données d'entraînement que nous donnons sont, l'image et le numéro d'identification correspondant, une fois convertis en nom, nous Lors de l'ajout de l'ensemble d'entraînement, enregistrez vous-même le nom correspondant. Lorsque vous donnez le résultat de l'entraînement, utilisez le numéro d'identification donné pour trouver le nom correspondant ; et lors de l'ajout de l'ensemble d'entraînement, placez la photo du même visage dans le même répertoire, c'est-à-dire qu'un nom peut correspondre à plusieurs visages différents, mais qu'un visage ne peut avoir qu'un seul nom ; lors de l'ajout d'un ensemble d'entraînement et de la reconnaissance faciale, la taille de l'image doit être la même ; veuillez ajouter au moins deux ensembles de image de formation.

     Implémentation des interfaces :

    Interface Winform simple, toutes les commandes sont autonomes

     J'ai également mis l'image d'entraînement ajoutée sur l'interface. Bien sûr, elle peut également être modifiée directement dans l'ensemble d'entraînement local, mais il convient de noter que la taille de l'image doit être cohérente.

Résultats de course approximatifs

 Code principal:

Tout d'abord, définissez un entraîneur

  public static FaceRecognizer faceRecongnizer = FisherFaceRecognizer.Create();

Définissez ensuite une classe personnalisée qui lie l'image à l'ID

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

       Utilisez une liste<yImgs> pour stocker les données d'entraînement. La raison pour laquelle je n'utilise pas de dictionnaire est la suivante : 1. Si le nombre est la clé et l'image est la valeur, un nombre, c'est-à-dire qu'une personne ne peut en ajouter qu'un image, et utilisez List<Mat> comme La valeur du dictionnaire est également gênante. Il est préférable d'utiliser une liste directement. 2. Si vous utilisez l'image comme clé et le nombre comme valeur, l'image ne peut pas être répétée, c'est-à-dire qu'une personne ne peut pas ajouter deux images identiques en tant qu'images d'entraînement. , et en utilisant List<yImgs>, vous pouvez ajouter deux images identiques en tant qu'images d'entraînement.

      Après avoir cette liste, nous définissons un dictionnaire pour lier le numéro et le nom de la personne, et le nom en double n'est pas considéré ici.

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

     Ensuite, nous pouvons ajouter des images de formation. J'ajoute actuellement des images localement, je les mets au format souhaité, puis je lis toutes les informations d'image du local avant la formation.

        /// <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);
            }
        }

Le format ajouté localement est le suivant

     Une fois les images de l'ensemble de formation ajoutées localement, les informations locales sont lues et le formateur est formé. Il s'agit d'attribuer une valeur à la List<yImgs> que nous avons définie au début, et de l'utiliser pour former le formateur.

        // 读取本地信息
        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;
        }

Pour la formation, il suffit d'appeler directement la méthode de formation du formateur

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

Il peut être reconnu après l'entraînement.

Les étapes approximatives sont les suivantes :

1. Obtenez toutes les images de visage à partir de l'image reconnue et ajustez ces images de visage à la même taille que l'ensemble d'apprentissage (il peut y avoir plusieurs visages dans l'image de reconnaissance et il ne peut y avoir qu'un seul visage dans l'image d'apprentissage).

        // 从图片中获取所有的人脸图片 并调整为指定大小
        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. Obtenez les positions de tous les visages ci-dessus

        // 获取图像所有的人脸框
        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. Reconnaître toutes les photos de visage obtenues et obtenir leurs noms correspondants

        // 获取所有名字
        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. Enfin, dessinez tous les noms dans les positions correspondantes.

        // 画出所有的框和名字
        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;
        }

Notez que lors de l'écriture du nom, si vous utilisez Cv2.PutText, le nom ne peut pas être en chinois

De cette manière, une reconnaissance faciale simple est réalisée.

Je suppose que tu aimes

Origine blog.csdn.net/Iawfy_/article/details/125495355
conseillé
Classement