c#Winform은 Opencvsharp4를 사용하여 간단한 얼굴 인식을 실현합니다.

     환경 구성: vs2019, .Net FrameWork 4.8 Opencvsharp4

      Nuget에서 최신 Opencvsharp4를 다운로드하십시오.

       내가 이해하는 얼굴 인식의 원리에 대해 이야기하겠습니다. 즉, 먼저 트레이너에게 일부 훈련 데이터를 제공합니다. 즉, 이 데이터가 누구에 해당하는지 트레이너에게 알려주면 트레이너는 이러한 이미지의 특성과 해당하는 사람의 이름을 인식한 후 인식하는 동안 인식 이미지의 특징을 찾은 다음 훈련된 특징과 비교하여 훈련 세트에서 가장 가까운 특징을 찾아 해당 이름을 지정하고 유사성, 즉 점수입니다.

      Opencvsharp4에는 해당 모듈이 있습니다. OpenCvSharp.Face에서 FaceRecognizer는 우리에게 필요한 트레이너입니다. 훈련 세트를 추가할 때 제공하는 훈련 데이터는 이미지와 해당 ID 번호입니다. 이름으로 변환할 때 훈련 세트 추가 시 해당 이름을 직접 저장 훈련 결과 제공 시 주어진 ID 번호로 해당 이름 찾기 훈련 세트 추가 시 같은 얼굴 사진을 같은 안에 넣기 즉, 이름은 여러 다른 얼굴에 해당할 수 있지만 얼굴은 하나의 이름만 가질 수 있습니다. 트레이닝 세트를 추가하고 얼굴 인식을 수행할 때 이미지 크기는 동일해야 합니다. 트레이닝 이미지.

     인터페이스 구현:

    간단한 Winform 인터페이스, 모든 컨트롤은 독립적입니다.

     추가된 트레이닝 이미지도 인터페이스에 넣었습니다.물론 로컬 트레이닝셋에서 직접 수정도 가능하지만 이미지의 크기는 일정해야 한다는 점에 유의해야 합니다.

대략적인 실행 결과

 메인 코드:

먼저 트레이너를 정의합니다.

  public static FaceRecognizer faceRecongnizer = FisherFaceRecognizer.Create();

그런 다음 이미지를 ID에 바인딩하는 사용자 정의 클래스를 정의하십시오.

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

       List<yImgs>를 사용하여 training data를 저장하고 사전을 사용하지 않는 이유는 1. 숫자가 Key이고 이미지가 Value라면 하나의 숫자, 즉 한 사람이 하나만 추가할 수 있습니다. 딕셔너리의 값도 번거롭기 때문에 List를 직접 사용하는 것이 좋습니다 2. 이미지를 Key로 숫자를 Value로 사용하면 이미지가 반복될 수 없고, 즉, 한 사람이 두 개의 동일한 사진을 교육용 사진으로 추가할 수 없으며 List<yImgs>를 사용하여 두 개의 동일한 사진을 교육용 사진으로 추가할 수 있습니다.

      이 List를 만든 후 사람의 번호와 이름을 묶는 사전을 정의하며 중복 이름은 여기에서 고려하지 않습니다.

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

     그런 다음 교육 이미지를 추가할 수 있습니다. 현재 로컬에서 이미지를 추가하고 원하는 형식으로 설정한 다음 교육 전에 로컬에서 모든 이미지 정보를 읽습니다.

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

로컬에서 추가된 형식은 다음과 같습니다.

     트레이닝 세트 이미지가 로컬로 추가된 후 로컬 정보를 읽고 트레이너를 트레이닝합니다. 처음에 정의한 List<yImgs>에 값을 할당하고 트레이너를 훈련시키는 데 사용하는 것입니다.

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

트레이닝은 트레이너의 트레이닝 방법을 직접 호출하면 됩니다.

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

훈련 후에 인식할 수 있습니다.

대략적인 단계는 다음과 같습니다.

1. 인식된 이미지에서 모든 얼굴 이미지를 가져오고 이 얼굴 이미지를 훈련 세트와 같은 크기로 조정합니다.(인식 이미지에는 여러 개의 얼굴이 있을 수 있으며 훈련 이미지에는 하나의 얼굴만 있을 수 있습니다.)

        // 从图片中获取所有的人脸图片 并调整为指定大小
        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. 위의 모든 얼굴의 위치를 ​​가져옵니다.

        // 获取图像所有的人脸框
        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. 획득한 모든 얼굴 사진을 인식하고 해당 이름을 얻습니다.

        // 获取所有名字
        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. 마지막으로 해당 위치에 모든 이름을 그립니다.

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

이름을 작성할 때 Cv2.PutText를 사용하는 경우 이름을 중국어로 작성할 수 없습니다.

이런 식으로 간단한 얼굴 인식이 구현됩니다.

추천

출처blog.csdn.net/Iawfy_/article/details/125495355