天天看點

基于emgucv的人臉檢測及識别前言一、窗體設計二、代碼部分三、結果四、總結

文章目錄

  • 前言
  • 一、窗體設計
  • 二、代碼部分
  • 三、結果
  • 四、總結

前言

這是該系列文章的第二篇。本篇文章主要實作的功能是對人臉進行檢測及識别。人臉檢測部分用的算法是級聯分類器,人臉識别部分用的LBPH算法。識别精度可以媲美普通學校用的人臉識别系統,話不多說,上代碼

一、窗體設計

基于emgucv的人臉檢測及識别前言一、窗體設計二、代碼部分三、結果四、總結

二、代碼部分

using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Face;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using System;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace facerecognize
{
    public partial class Form1 : Form
    {
        //在方法外面定義各個需要的變量和類,這樣所有的方法都可調用相應的變量
        Capture _capture;
        //執行個體化人臉檢測級聯分類器
        CascadeClassifier face_detect = new CascadeClassifier(@"haarcascade\haarcascade_frontalface_alt2.xml");//haarcascade_frontalface_alt2
        Mat face_image = new Mat();
        VectorOfInt image_lable = new VectorOfInt();
        VectorOfMat image_data = new VectorOfMat();
        string[] name;
        //執行個體化局部二值模式人臉識别器
        FaceRecognizer face_recognize = new LBPHFaceRecognizer();
        bool after_train = false;
        bool catch_face = false;
        ASCIIEncoding ascii = new ASCIIEncoding();


        public Form1()
        {
            InitializeComponent();
        }
        //定義攝像頭捕捉到圖檔時調用的方法
        void frame(object sender,EventArgs e)
        {
            Mat scr = _capture.QueryFrame();
            //裁剪圖檔,提高電腦運作速度
            CvInvoke.Resize(scr, scr, new Size(320, 240));
            //檢測人臉
            Rectangle[] recs = face_detect.DetectMultiScale(scr);
            foreach(Rectangle rec in recs)
            {
                CvInvoke.Rectangle(scr, rec, new MCvScalar(0, 0, 255));
                //将人臉區域圖檔顯示在imagebox2中,整張圖檔顯示在imagebox1中
                imageBox2.Image = new Mat(scr, rec);
                imageBox1.Image = scr;

            }

            if(catch_face)
            {
                if(labeltextBox.Text!=null)
                {
                    //這裡輸入的隻能是英文字元,若是中文,則會出現亂碼,筆者一開始以為是編碼問題,後面嘗試好幾種解碼方法,都沒能解決這個問題。
                    string labeltext = labeltextBox.Text;
                    face_image = new Image<Gray, byte>(new Bitmap(imageBox2.Image.Bitmap)).Resize(120, 120, Inter.Area).Mat;
                    //将圖檔以image_data-文本框中輸入的名字-系統時間.jpg格式儲存,友善後面将文本框中名字取出
                    face_image.Save("Image_data" + "\\" + labeltext + "_" + DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + ".jpg");
                    MessageBox.Show("儲存成功");
                    catch_face = false;
                }
            }

            if(after_train)
            {
                foreach(Rectangle rec in recs)
                {
                    //局部變量text存放人臉名字
                    string text = "";
                    Mat scr_image = new Mat(scr, rec);
                    //将人臉圖檔縮減,并且轉為mat格式
                    scr_image = scr_image.ToImage<Gray, byte>().Resize(120, 120, Inter.Area).Mat;
                    //對人臉進行識别
                    FaceRecognizer.PredictionResult result = face_recognize.Predict(scr_image);
                    //name中存的是上面文本框存的各個人臉對應的名字,與label也是一一對應的
                    text = name[result.Label];
                    if(result.Distance>3000)
                    {
                        text = "Miss";

                    }
                    CvInvoke.PutText(scr, text, rec.Location, FontFace.HersheyComplex, 1, new MCvScalar(0, 0, 255));
                    imageBox1.Image = scr;

                }
            }
        }

        private void imageBox1_Click(object sender, EventArgs e)
        {

        }

        //打開攝像頭
        private void opencap_Click(object sender, EventArgs e)
        {
            _capture = new Capture(0);
            Application.Idle += frame;

        }

        //儲存圖檔,并将catch_face重置為true
        private void savebtn_Click(object sender, EventArgs e)
        {
            catch_face = true;
        }

        //開始訓練圖檔
        private void trainbtn_Click(object sender, EventArgs e)
        {
            //将iamge_data中獲得所有檔案存在path中,後面對其進行切片處理,并且将取得的人臉名字存在name中
            string[] path = Directory.GetFiles("Image_data");
            Mat[] data = new Mat[path.Length];
            int[] label = new int[path.Length];
            name = new string[path.Length];
            for(int i =0;i<path.Length;i++)
            {
                Image<Gray, byte> image = new Image<Gray, byte>(path[i]);
                data[i] = image.Mat;
                label[i] = i;
                //傳回最後出現\\的索引
                int a = path[i].LastIndexOf('\\');
                //傳回最後出現_的索引
                int b = path[i].LastIndexOf('_');
                //從a+1處開始截取字元,截取b-a-1個,這就是人臉名字在的區域
                name[i] = path[i].Substring(a+1, b - a - 1);

            }
            image_data.Push(data);
            image_lable.Push(label);
            //訓練圖檔
            face_recognize.Train(image_data, image_lable);
            face_recognize.Save("face\\data.txt");
            MessageBox.Show("訓練成功");
            after_train = true;
            

        }
    }
}
           

三、結果

基于emgucv的人臉檢測及識别前言一、窗體設計二、代碼部分三、結果四、總結

四、總結

識别精度還是很不錯的,但目前值得改進的部分就是文本框中不能輸入中文,不然檔案名中會出現亂碼。筆者也已經換了好幾種編碼方式,依然沒有解決這個問題。

希望與各位熱愛cv的小夥伴們共同進步,有知道解決方法的讀者可在評論區留言。

注:轉載請備注出處,原創不易。