Haar級(jí)聯(lián)分類(lèi)器
在OpenCV中主要使用了兩種特征(即兩種方法)進(jìn)行人臉檢測(cè),Haar特征和LBP特征。用的最多的是Haar特征人臉檢測(cè)。
Haar級(jí)聯(lián)分類(lèi)器是一種用于目標(biāo)檢測(cè)的機(jī)器學(xué)習(xí)方法,它是一種基于機(jī)器學(xué)習(xí)的特征選擇方法,能夠快速而有效地檢測(cè)出圖像中的對(duì)象或特定的模式,例如人臉。
Haar級(jí)聯(lián)分類(lèi)器工作的基本原理是使用弱分類(lèi)器(通常是基于決策樹(shù)的弱分類(lèi)器)級(jí)聯(lián)成一個(gè)強(qiáng)大的分類(lèi)器。在訓(xùn)練過(guò)程中,它通過(guò)提取訓(xùn)練樣本中的特征并根據(jù)這些特征進(jìn)行分類(lèi)來(lái)逐步學(xué)習(xí)目標(biāo)對(duì)象(例如人臉)的特征模式。級(jí)聯(lián)的概念允許快速篩選出負(fù)樣本,減少計(jì)算量,從而提高了檢測(cè)速度。下圖展示了級(jí)聯(lián)的過(guò)程:
我們需要考慮如何在層次結(jié)構(gòu)中組合多個(gè)Haar級(jí)聯(lián)分類(lèi)器,以便用一個(gè)分類(lèi)器識(shí)別父區(qū)域(就目標(biāo)而言是一張人臉),用其他分類(lèi)器識(shí)別子區(qū)域(比如眼睛)。
opencv提供了多種訓(xùn)練好的級(jí)聯(lián)分類(lèi)器模型文件,這些文件通常是XML格式,存放在opencv安裝目錄下源碼文件夾中sources\data\haarcascades
haarcascade_eye.xml, 眼睛
haarcascade_eye_tree_eyeglasses.xml, 戴眼鏡的眼睛
haarcascade_frontalcatface.xml, 正面貓臉
haarcascade_frontalcatface_extended.xml, 正面貓臉
haarcascade_frontalface_alt.xml, 正面人臉
haarcascade_frontalface_alt2.xml, 正面人臉
haarcascade_frontalface_alt_tree.xml, 正面人臉
haarcascade_frontalface_default.xml, 正面人臉
haarcascade_fullbody.xml, 人體
haarcascade_lefteye_2splits.xml, 左眼
haarcascade_license_plate_rus_16stages.xml,
haarcascade_lowerbody.xml,
haarcascade_profileface.xml,
haarcascade_righteye_2splits.xml, 右眼
haarcascade_russian_plate_number.xml,
haarcascade_smile.xml, 笑臉
haarcascade_upperbody.xml, 上身
從文件名可知這些級(jí)聯(lián)是用于人臉、眼睛、鼻子和嘴的跟蹤。這些文件需要正面、直立的人臉圖像。創(chuàng)建人臉檢測(cè)器時(shí)會(huì)使用這些文件,創(chuàng)建自己的級(jí)聯(lián),并訓(xùn)練這些級(jí)聯(lián)來(lái)檢測(cè)各種對(duì)象。
Haar級(jí)聯(lián)分類(lèi)器執(zhí)行流程
1. 數(shù)據(jù)準(zhǔn)備
正樣本收集: 收集包含需要檢測(cè)對(duì)象的圖像,并對(duì)圖像進(jìn)行標(biāo)注,標(biāo)注出感興趣對(duì)象的位置。
負(fù)樣本收集: 收集不包含感興趣對(duì)象的圖像,或者與感興趣對(duì)象不相關(guān)的圖像樣本。
創(chuàng)建樣本信息文件: 創(chuàng)建包含正樣本和負(fù)樣本信息的數(shù)據(jù)文件,描述圖像路徑、對(duì)象位置和標(biāo)簽等信息。
2. 特征提取
Haar 特征選擇: 對(duì)于每個(gè)樣本圖像,從圖像中提取 Haar 特征。Haar 特征是一種矩形區(qū)域的強(qiáng)度差異計(jì)算,用于表示圖像的局部特征。
特征值計(jì)算: 計(jì)算每個(gè)樣本圖像的 Haar 特征值。Haar 特征是根據(jù)矩形區(qū)域的像素和計(jì)算的。這些特征值將用于訓(xùn)練分類(lèi)器。
3. 訓(xùn)練分類(lèi)器
級(jí)聯(lián)分類(lèi)器訓(xùn)練: 使用提取的特征值對(duì)分類(lèi)器進(jìn)行訓(xùn)練。初始階段,級(jí)聯(lián)分類(lèi)器包含多個(gè)弱分類(lèi)器(例如決策樹(shù)、Adaboost 等)。
特征選擇和增強(qiáng): 訓(xùn)練過(guò)程中,級(jí)聯(lián)分類(lèi)器將對(duì)特征進(jìn)行選擇和增強(qiáng),以提高對(duì)感興趣對(duì)象和背景的區(qū)分能力。
級(jí)聯(lián)結(jié)構(gòu)構(gòu)建: 根據(jù)訓(xùn)練數(shù)據(jù)和特征值,構(gòu)建多個(gè)級(jí)聯(lián)階段,每個(gè)階段都包含多個(gè)弱分類(lèi)器。
4. 級(jí)聯(lián)分類(lèi)器應(yīng)用
對(duì)象檢測(cè): 將訓(xùn)練好的級(jí)聯(lián)分類(lèi)器應(yīng)用于新的圖像中進(jìn)行對(duì)象檢測(cè)。級(jí)聯(lián)分類(lèi)器采用級(jí)聯(lián)結(jié)構(gòu)逐漸縮小搜索區(qū)域,使用不同階段的弱分類(lèi)器進(jìn)行對(duì)象檢測(cè)。
非極大值抑制: 對(duì)檢測(cè)到的對(duì)象進(jìn)行非極大值抑制(Non-Maximum Suppression),以消除重疊區(qū)域或多次檢測(cè)到同一對(duì)象的情況。
使用 Haar 級(jí)聯(lián)檢測(cè)器檢測(cè)圖片中的人臉的步驟:
(1)創(chuàng)建一個(gè) CascadeClassifier 級(jí)聯(lián)分類(lèi)器對(duì)象,從 .xml 文件加載級(jí)聯(lián)分類(lèi)器模型。
(2)讀取待檢測(cè)的圖片。
(3)使用 detectMultiScale() 方法檢測(cè)圖片,返回檢測(cè)到的面部或眼睛的邊界矩形。
(4)將檢測(cè)到的邊界矩形繪制到檢測(cè)圖片上。
OpenCV 中定義了級(jí)聯(lián)分類(lèi)器類(lèi) cv::CascadeClassifier。在 Python 語(yǔ)言中,使用接口函數(shù) cv2.CascadeClassifier() 從文件創(chuàng)建分類(lèi)器。成員函數(shù) cv.CascadeClassifier.detectMultiScale() 用于執(zhí)行對(duì)圖像進(jìn)行目標(biāo)檢測(cè)。
代碼示例:
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
void detectAndDisplay(Mat frame);
//注意,需要把"haarcascade_frontalface_alt.xml"和"haarcascade_eye_tree_eyeglasses.xml"這兩個(gè)文件復(fù)制到工程路徑下
string face_cascade_name = "haarcascade_frontalface_alt.xml";
string eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
string window_name = "Capture - Face detection";
RNG rng(12345);
//-----------------------------------【main( )函數(shù)】--------------------------------------------
// 描述:控制臺(tái)應(yīng)用程序的入口函數(shù),我們的程序從這里開(kāi)始
//-------------------------------------------------------------------------------------------------
int main(void)
{
VideoCapture capture;
Mat frame;
//-- 1. 加載級(jí)聯(lián)(cascades)
if (!face_cascade.load(face_cascade_name)) { printf("--(!)Error loading\n"); return -1; };
if (!eyes_cascade.load(eyes_cascade_name)) { printf("--(!)Error loading\n"); return -1; };
//-- 2. 讀取視頻
capture.open(0);
if (capture.isOpened())
{
for (;;)
{
capture >> frame;
//-- 3. 對(duì)當(dāng)前幀使用分類(lèi)器(Apply the classifier to the frame)
if (!frame.empty())
{
detectAndDisplay(frame);
}
else
{
printf(" --(!) No captured frame -- Break!"); break;
}
int c = waitKey(10);
if ((char)c == 'c') { break; }
}
}
return 0;
}
void detectAndDisplay(Mat frame)
{
std::vector<Rect> faces;
Mat frame_gray;
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
equalizeHist(frame_gray, frame_gray);
//-- 人臉檢測(cè)
face_cascade.detectMultiScale(frame_gray, faces, 1.1, 3, 0 | CASCADE_SCALE_IMAGE, Size(30, 30), Size(200, 200));
for (size_t i = 0; i < faces.size(); i++)
{
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), 2, 8, 0);
Mat faceROI = frame_gray(faces[i]);
std::vector<Rect> eyes;
//-- 在臉中檢測(cè)眼睛
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), 3, 8, 0);
}
}
//-- 顯示最終效果圖
imshow(window_name, frame);
}
代碼分析:
(1)加載級(jí)聯(lián)分類(lèi)器
通過(guò) CascadeClassifier 類(lèi)加載人臉和眼睛的級(jí)聯(lián)分類(lèi)器(XML 文件),即 haarcascade_frontalface_alt.xml 和 haarcascade_eye_tree_eyeglasses.xml。
(2)讀取視頻流
使用 VideoCapture 對(duì)象打開(kāi)攝像頭設(shè)備(ID為0),讀取視頻幀數(shù)據(jù)。
(3)循環(huán)處理每一幀
在循環(huán)中,不斷從攝像頭捕獲幀數(shù)據(jù) capture >> frame。
對(duì)于每一幀,先進(jìn)行空幀檢測(cè),如果幀不為空則調(diào)用 detectAndDisplay() 函數(shù)進(jìn)行人臉和眼睛檢測(cè)。
(4)人臉檢測(cè)
detectAndDisplay() 函數(shù)將傳入的幀 frame 轉(zhuǎn)換為灰度圖像 frame_gray,并進(jìn)行直方圖均衡化。
調(diào)用 face_cascade.detectMultiScale() 在灰度圖像中檢測(cè)人臉區(qū)域,并將檢測(cè)到的人臉區(qū)域存儲(chǔ)在 faces 向量中。
什么叫直方圖均衡化?
首先直方圖是圖像中像素強(qiáng)度分布的圖形表達(dá)方式,它統(tǒng)計(jì)了每一個(gè)強(qiáng)度值所具有的像素個(gè)數(shù)。如下圖所示,橫坐標(biāo)代表圖像的灰度變化0-255,縱坐標(biāo)代碼每個(gè)灰度對(duì)應(yīng)的像素個(gè)數(shù)。
那么直方圖均衡化是通過(guò)拉伸像素強(qiáng)度分布范圍來(lái)增強(qiáng)圖像對(duì)比度的一種方法。特別是在一些局部對(duì)比度較低的圖像中,可以幫助提高圖像的質(zhì)量。
說(shuō)得更清楚一些, 以下面的直方圖為例, 你可以看到左邊直方圖像素主要集中在中間的一些強(qiáng)度值上. 直方圖均衡化要做的就是 拉伸 這個(gè)范圍.。對(duì)其應(yīng)用均衡化后, 得到了右圖所示的直方圖. 均衡化的圖像見(jiàn)下面右圖??梢院苊黠@的看到圖像對(duì)比度得到了增強(qiáng)。
圖像均衡化函數(shù)
void equalizeHist(InputArray src, OutputArray dst);
detectMultiScale函數(shù)解析:該函數(shù)主要用于級(jí)聯(lián)分類(lèi)器(如 Haar 級(jí)聯(lián)分類(lèi)器或者基于 HOG 特征的 SVM 分類(lèi)器)進(jìn)行對(duì)象檢測(cè)。
void CascadeClassifier::detectMultiScale(
InputArray image, // 輸入圖像
std::vector<Rect>& objects, // 檢測(cè)到的對(duì)象位置矩形
double scaleFactor = 1.1, // 每次圖像縮小的比例
int minNeighbors = 3, // 最小鄰近數(shù),用于合并矩形
int flags = 0, // 未使用的參數(shù),默認(rèn)為0
Size minSize = Size(), // 對(duì)象最小尺寸
Size maxSize = Size() // 對(duì)象最大尺寸
);
image:輸入圖像(灰度圖像或彩色圖像)。
objects:檢測(cè)到的對(duì)象位置矩形集合,返回給調(diào)用者。
scaleFactor:表示在前后兩次相繼的掃描中,搜索窗口的比例系數(shù)。默認(rèn)為1.1即每次搜索窗口依次擴(kuò)大10%。建議范圍通常在 1.01 到 1.5 之間,較小的值會(huì)增加檢測(cè)時(shí)間,但也會(huì)增加準(zhǔn)確性。較大的值會(huì)減少檢測(cè)時(shí)間,但可能會(huì)降低準(zhǔn)確性。
minNeighbors:匹配成功所需要的周?chē)匦慰虻臄?shù)目,每一個(gè)特征匹配到的區(qū)域都是一個(gè)矩形框,只有多個(gè)矩形框同時(shí)存在的時(shí)候,才認(rèn)為是匹配成功,比如人臉,這個(gè)默認(rèn)值是3,較大的值可以提高對(duì)象檢測(cè)的準(zhǔn)確性,但也會(huì)增加漏檢率。通常建議設(shè)置在3到6之間。
flags:未使用的參數(shù),通常為0。
可以取如下這些值:
CASCADE_DO_CANNY_PRUNING=1, 利用canny邊緣檢測(cè)來(lái)排除一些邊緣很少或者很多的圖像區(qū)域
CASCADE_SCALE_IMAGE=2, 正常比例檢測(cè)
CASCADE_FIND_BIGGEST_OBJECT=4, 只檢測(cè)最大的物體
CASCADE_DO_ROUGH_SEARCH=8 初略的檢測(cè)
minSize 和 maxSize:指定對(duì)象的最小和最大尺寸。在實(shí)際應(yīng)用中,可以根據(jù)目標(biāo)對(duì)象的大小設(shè)置這兩個(gè)參數(shù),以過(guò)濾掉尺寸不在指定范圍內(nèi)的檢測(cè)結(jié)果。minSize對(duì)于人臉檢測(cè),通常設(shè)置在 20x20 到 30x30 的范圍內(nèi)。maxSize對(duì)于人臉檢測(cè),可以設(shè)置在 200x200 到 300x300 之間。
(5)眼睛檢測(cè)
遍歷每個(gè)檢測(cè)到的人臉區(qū)域,在每個(gè)人臉區(qū)域中調(diào)用 eyes_cascade.detectMultiScale() 進(jìn)行眼睛檢測(cè),并將檢測(cè)到的眼睛區(qū)域存儲(chǔ)在 eyes 向量中。
在檢測(cè)到的每個(gè)眼睛區(qū)域周?chē)?huà)一個(gè)圓圈。
(6)顯示結(jié)果
最后通過(guò) imshow() 在窗口中顯示帶有人臉和眼睛檢測(cè)框的幀圖像。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-768021.html
效果顯示:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-768021.html

到了這里,關(guān)于《opencv實(shí)用探索·二十一》人臉識(shí)別的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!