如何使用 Opencv 實現人臉檢測和人臉識別?


如何使用 Opencv 實現人臉檢測和人臉識別?

Note:

使用人臉識別需要自行編譯 Opencv 第三方模塊,地址如下:
https://github.com/opencv/opencv_contrib

1.人臉檢測 CascadeClassifier

  1. 加載 Opencv 自帶的人臉檢測 haarcascade_frontalface_alt.xml 分類器。
  2. 圖像預處理 cvtColor(灰度化) equalizeHist(直方圖均衡化)
  3. 使用 detectMultiScale 函數進行識別。
  4. 使用 rectangle 函數繪制找到的目標矩形框。
  5. 在原圖像上 ROI 截取彩色的人臉保存。

2.人臉識別 FaceRecognizer FisherFaceRecognizer LBPHFaceRecognizer

2.1 人臉識別分類器訓練

  1. 樣本歸一化,即圖像大小一致、灰度化、直方圖均衡化等。
  2. Ptr<FaceRecognizer> face = EigenFaceRecognizer::create()
  3. 創建樣本和標簽向量 std::vector<Mat> images std::vector<int> labelspush_back 加入樣本和標簽。
  4. 進行訓練 face->train(images,labels)
  5. 保存訓練的分類器 face->save("face.xml")

2.2 人臉識別分類器加載和使用

  1. 加載訓練好的分類器 face->load(face.xml)
  2. 待識別圖像預處理 resize cvtColor 等。
  3. 預測輸入圖像獲取標簽值 int label = face->predict(Mat src),當然也可以獲取 置信度 來調整 閾值
  4. 根據標簽值,繪制 putText 對應的角色名。

Note:

1.訓練和預測的圖像大小必須一樣且為灰度圖像。

2.使用 FisherFaceRecognizer 標簽必須大於2類

Code

//人臉檢測
#include "opencv2/opencv.hpp"
#include "opencv2/face.hpp"
#include <iostream>
#include <string>
using namespace cv;
using namespace cv::face;
using namespace std;

void FindFaces(cv::Mat &dst)
{
Mat src = imread("src.jpg");
Mat frame = src.clone();
Mat facesRIO;
//圖像縮放,采用雙線性插值。
//cv::resize(src,src,Size(128,128),0,0,cv::INTER_LINEAR);
//圖像灰度化。
cv::cvtColor(src,src,COLOR_BGR2GRAY);
//直方圖均衡化,圖像增強,暗的變亮,亮的變暗。
cv::equalizeHist(src,src);
//
String face_cascade_name = "haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade,eyes_cascade;
if(!face_cascade.load(face_cascade_name))
{
    //加載臉部分類器失敗!
    return;
}
if(!eyes_cascade.load(eyes_cascade_name))
{
    //加載眼睛分類器失敗!
    return;
}
//存儲找到的臉部矩形。
std::vector<Rect> faces;
face_cascade.detectMultiScale(src,faces,1.1,2,0|CASCADE_SCALE_IMAGE,Size(30,30));
for(size_t i=0;i<faces.size();++i)
{
    //繪制矩形 BGR。
    rectangle(frame,faces[i],Scalar(0,0,255),1);
    //獲取矩形中心點。
    //Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
    //繪制圓形。
    //ellipse(frame, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
    //獲取臉部矩形區域。
    //Mat faceROI = src(faces[i]);
    //存儲找到的眼睛矩形。
    //std::vector<Rect> eyes;
    //eyes_cascade.detectMultiScale(faceROI,eyes,1.1,2,0 |CASCADE_SCALE_IMAGE,Size(30,30));
    //for(size_t j=0;j<eyes.size();++j)
    //{
        //Point eye_center(faces[i].x + eyes[j].x + eyes[j].width/2,faces[i].y + eyes[j].y + eyes[j].height/2);
        //int radius = cvRound((eyes[j].width + eyes[j].height)*0.25);
        //circle(frame,eye_center,radius,Scalar( 255, 0, 0 ),4,8,0);
    //}
    //截取人臉。
    facesROI = frame(faces[i]);
    //圖像縮放。
    cv::resize(facesROI,facesROI,Size(128,128),0,0,cv::INTER_LINEAR);
    //保存圖像。
    dst = facesROI;
    cv::imwrite("dst.jpg",facesROI);
}
return;
}
//人臉識別
void Distinguish()
{
/*******************************************************
 *假定 標簽1代表張三 標簽2代表李四 標簽3代表 王五
 ******************************************************/
//定義保存圖片和標簽的向量容器
std::vector<Mat> images;
std::vector<int> labels;
//讀取樣本
Mat src_1 = imread("src_1.jpg",CV_LOAD_IMAGE_GRAYSCALE);
Mat src_2 = imread("src_2.jpg",CV_LOAD_IMAGE_GRAYSCALE);
Mat src_3 = imread("src_3.jpg",CV_LOAD_IMAGE_GRAYSCALE);
Mat src_4 = imread("src_4.jpg",CV_LOAD_IMAGE_GRAYSCALE);
//預測樣本
Mat src_5 = imread("src_5.jpg",CV_LOAD_IMAGE_GRAYSCALE);
//圖像大小歸一化
cv::resize(src_1,src_1,Size(128,128));
cv::resize(src_2,src_2,Size(128,128));
cv::resize(src_3,src_3,Size(128,128));
cv::resize(src_4,src_4,Size(128,128));
cv::resize(src_5,src_5,Size(128,128));
//加入圖像
images.push_back(src_1);
images.push_back(src_2);
images.push_back(src_3);
images.push_back(src_4);
//加入標簽
labels.push_back(1);
labels.push_back(1);
labels.push_back(2);
labels.push_back(3);

Ptr<FaceRecognizer> faceClass = EigenFaceRecognizer::create();
Ptr<FisherFaceRecognizer> fisherClass = FisherFaceRecognizer::create();
Ptr<LBPHFaceRecognizer> lpbhClass = LBPHFaceRecognizer::create();
//訓練
faceClass->train(images,labels);
fisherClass->train(images,labels);
lpbhClass->train(images,labels);
//保存訓練的分類器
faceClass->save("faceClass.xml");
fisherClass->save("fisherClass.xml");
lpbhClass->save("lpbhClass.xml");
//加載分類器
//faceClass->load("faceClass.xml");
//fisherClass->load("fisherClass.xml");
//lpbhClass->load("lpbhClass.xml");
//使用訓練好的分類器進行預測。
int faceResult = faceClass->predict(src_5);
switch (faceResult)
{
case 1:
    //張三
    break;
case 2:
    //李四
    break;
case 3:
    //王五
    break;
default:
    //未知
    break;
}
//預測樣本並獲取標簽和置信度
int fisherResult = -1;
double fisherConfidence = 0.0;
fisherClass->predict(src_5,fisherResult,fisherConfidence);
std::count<<String("標簽類別:")<<fisherResult<<String("置信度:")<<fisherConfidence<<std::endl;
int lpbhResult = lpbhClass->predict(src_5);
std::count<<String("標簽類別:")<<lpbhResult;
return;
}

更多信息請自行查看官網參考 Opencv 3.3.0 官方教程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM