1. 程式人生 > >opencv人臉檢測_Haar特徵分類器實現人臉檢測_cascade.detectMultiScale引數詳解

opencv人臉檢測_Haar特徵分類器實現人臉檢測_cascade.detectMultiScale引數詳解

1.  概述

CascadeClassifier為OpenCV中cv namespace下用來做目標檢測的級聯分類器的一個類。該類中封裝的目標檢測機制,簡而言之是滑動視窗機制+級聯分類器的方式

2.  支援的特徵

對於Haar、LBP和HOG,CascadeClassifier都有自己想對他們說的話:

1)  Haar:因為之前從OpenCV1.0以來,一直都是隻有用haar特徵的級聯分類器訓練和檢測(當時的檢測函式稱為cvHaarDetectObjects,訓練得到的也是特徵和node放在一起的xml),所以在之後當CascadeClassifier出現並統一三種特徵到同一種機制和資料結構下時,沒有放棄原來的C程式碼編寫的haar檢測,仍保留了原來的檢測部分。另外,Haar在檢測中無論是特徵計算環節還是判斷環節都是三種特徵中最簡潔的,但是筆者的經驗中他的訓練環節卻往往是耗時最長的。

2)  LBP:LBP在2.2中作為人臉檢測的一種方法和Haar並列出現,他的單個點的檢測方法(將在下面看到具體討論)是三者中較為複雜的一個

,所以當檢測的點數相同時,如果不考慮特徵計算時間,僅計算判斷環節,他的時間是最長的

3)  HOG:在2.4.0中才開始出現在該類中的HOG檢測,其實並不是OpenCV的新生力量,因為在較早的版本中HOG特徵已經開始作為單獨的行人檢測模組出現。比較起來,雖然HOG在行人檢測和這裡的檢測中同樣是滑窗機制,但是一個是級聯adaboost,另一個是SVM;而且HOG特徵為了加入CascadeClassifier支援的特徵行列改變了自身的特徵計算方式:不再有相鄰cell之間的影響,並且採用在Haar和LBP上都可行的積分圖計算,放棄了曾經的HOGCache方式,雖然後者的加速效能遠高於前者,而簡單的HOG特徵也使得他的分類效果有所下降(如果用SVM分類器對相同樣本產生的兩種HOG特徵做分類,沒有了相鄰cell影響的計算方式下的HOG特徵不那麼容易完成分類)。這些是HOG為了加入CascadeClassifier而做出的犧牲,不過你肯定也想得到OpenCV保留了原有的HOG計算和檢測機制。另外,HOG在特徵計算環節是最耗時的,但他的判斷環節和Haar一樣的簡潔。

3.CascadeClassifier檢測的基本原理:

  xml中存放的是訓練後的特徵池,特徵size大小根據訓練時的引數而定,檢測的時候可以簡單理解為就是將每個固定size特徵(檢測視窗)與輸入影象的同樣大小區域比較,如果匹配那麼就記錄這個矩形區域的位置,然後滑動視窗,檢測影象的另一個區域,重複操作。由於輸入的影象中特徵大小不定,比如在輸入影象中眼睛是50x50的區域,而訓練時的是25x25,那麼只有當輸入影象縮小到一半的時候,才能匹配上,所以這裡還有一個逐步縮小影象,也就是製作影象金字塔的流程.

 

void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& objects,
                                          double scaleFactor, int minNeighbors,
                                          int flags, Size minObjectSize, Size maxObjectSize)
{
    vector<int> fakeLevels;
    vector<double> fakeWeights;
    detectMultiScale( image, objects, fakeLevels, fakeWeights, scaleFactor,
        minNeighbors, flags, minObjectSize, maxObjectSize, false );
}

引數意思:
1. const Mat& image:輸入影象
2. vector& objects:輸出的矩形向量組
3. double scaleFactor=1.1:這個是每次縮小影象的比例,預設是1.1
4. minNeighbors=3:匹配成功所需要的周圍矩形框的數目,每一個特徵匹配到的區域都是一個矩形框,只有多個矩形框同時存在的時候,才認為是匹配成功,比如人臉,這個預設值是3。
5. flags=0:可以取如下這些值:
CASCADE_DO_CANNY_PRUNING=1, 利用canny邊緣檢測來排除一些邊緣很少或者很多的影象區域
CASCADE_SCALE_IMAGE=2, 正常比例檢測
CASCADE_FIND_BIGGEST_OBJECT=4, 只檢測最大的物體
CASCADE_DO_ROUGH_SEARCH=8 初略的檢測
6. minObjectSize maxObjectSize:匹配物體的大小範圍

    由於人臉可能出現在影象的任何位置,在檢測時用固定大小的視窗對影象從上到下、從左到右掃描,判斷窗口裡的子影象是否為人臉,這稱為滑動視窗技術(sliding window)。為了檢測不同大小的人臉,還需要對影象進行放大或者縮小構造影象金字塔,對每張縮放後的影象都用上面的方法進行掃描。由於採用了滑動視窗掃描技術,並且要對影象進行反覆縮放然後掃描,因此整個檢測過程會非常耗時。

以512x512大小的影象為例,假設分類器視窗為24x24,滑動視窗的步長為1,則總共需要掃描的視窗數為:以512x512大小的影象為例,假設分類器視窗為24x24,滑動視窗的步長為1,則總共需要掃描的視窗數為:

以512x512大小的影象為例,假設分類器視窗為24x24,滑動視窗的步長為1,則總共需要掃描的視窗數為:

即要檢測一張圖片需要掃描大於120萬個視窗!!!計算量驚人,因此有必要採取某種措施提高效率,具體解決方案本文會給出。

其實這種方法不好。。。。

4.實踐:利用Opencv自帶的Haar特徵分類器進行人臉檢測。 

(1)Haar特徵分類器

Haar特徵分類器就是一個XML檔案,該檔案中會描述人體各個部位的Haar特徵值。包括人臉、眼睛、嘴脣等等。

Haar特徵分類器存放目錄:OpenCV安裝目錄中的\data\ haarcascades目錄下,例如:

 例如此次程式進行人臉識別,需要將分類器haarcascade_frontalface_alt2.xml複製到所建專案的可執行資料夾內。

(2)對CascadeClassifier做初始化

cv::CascadeClassifier classifier;

classifier.load(“cascade.xml”); //這裡的xml是訓練得到的分類器

CascadeClassifier類中既有load也有read函式,二者是相同的,load將引用read函式

#include <opencv2/core/core.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/opencv.hpp>

#include <vector>  
#include <cstdio>  

using namespace cv;
using namespace std;
int main() 
{
   //1.載入分類器
	CascadeClassifier cascade;
	//如果要識別人體的其它部位,只需將上面的haarcascade_frontalface_alt2.xml分類器替換即可。
	cascade.load("haarcascade_frontalface_alt2.xml"); 
	Mat srcImg, dstImg, grayImg;

	//2.讀圖片
	srcImg = imread("1.jpg");
	//尺寸調整  
	resize(srcImg, srcImg, Size(srcImg.cols / 4, srcImg.rows / 4), 0, 0, INTER_LINEAR); //用線性插值
	dstImg = srcImg.clone();
	imshow("原圖",srcImg);
	//waitKey(0);
	grayImg.create(srcImg.size(), srcImg.type());
	cvtColor(srcImg, grayImg, CV_BGR2GRAY);//生成灰度圖,提高檢測效率

	//定義7種顏色,用於標記人臉
	Scalar colors[] =
	{
		// 紅橙黃綠青藍紫
	   CV_RGB(255,0,0),
	   CV_RGB(255, 97, 0),
	   CV_RGB(255, 255, 0),
	   CV_RGB(0, 255, 0),
	   CV_RGB(255, 97, 0),
	   CV_RGB(0, 0, 255),
	   CV_RGB(160, 32, 240),
	};
	// 3.檢測
	vector<Rect> rect;
	cascade.detectMultiScale(grayImg, rect, 1.1, 3, 0);//分類器物件呼叫

	printf("檢測到人臉個數:%d\n", rect.size());

	//4.標記--在臉部畫圓
	for (int i = 0; i < rect.size(); i++)
	{
		Point center;
		int radius;
		center.x = cvRound((rect[i].x + rect[i].width * 0.5));
		center.y = cvRound((rect[i].y + rect[i].height * 0.5));

		radius = cvRound((rect[i].width + rect[i].height) *0.25);
		circle(dstImg, center, radius, colors[i % 7], 2);
	}

	//5.顯示
	imshow("識別結果",dstImg);
	waitKey(0);
}

識別結果:

僅僅是用了一個函式而已,還有很長路要走。。。

我還希望通過深度學習+opencv實現人臉檢測,請期待。

等會。。。大家分得清楚,人臉檢測和人臉識別嗎?其實人臉檢測,就是本文中的,就是對一副圖片進行檢測,檢測是否包含人臉,而人臉識別則是人臉檢測的基礎上,不僅要檢測出是否含有人臉,而且要進一步檢測出的人臉影象與已有人臉庫中的人臉進行對比,識別出該人臉影象中對應庫中的哪一個。