OpenCV中基於Haar特徵和級聯分類器的人臉檢測(三)
使用機器學習的方法進行人臉檢測的第一步需要訓練人臉分類器,這是一個耗時耗力的過程,需要收集大量的正負樣本,並且樣本質量的好壞對結果影響巨大,如果樣本沒有處理好,再優秀的機器學習分類演算法都是零。
今年3月23日,微軟公司在推特(Twitter)社交平臺上推出了一個基於機器學習的智慧聊天機器人Tay,Tay被設定為一個年齡為十幾歲的女孩,主要目標受眾是18歲至24歲的青少年。人們只需要@一下Tay,Tay就會追蹤該使用者的網名、性別、喜歡的食物、郵編、感情狀況等個人資訊。除了聊天,Tay還可以說笑話,講故事等,讓人感覺這就是一個知道你很多小祕密,嘴甜心暖的“小閨蜜”。Tay會在與人們的交流中不斷學習,隨著時間積累,她的理解能力將逐步提升,變得愈發“智慧”。
然而比較戲劇性的是在Tay推出24小時不到,這個人工智慧機器人就被人類徹底“教壞”,成為一個集反猶太人、性別歧視、種族歧視於一身的“不良少女”。逼得微軟不得不讓Tay暫時“下崗”。
微軟在一項宣告中表示,“人工智慧機器人Tay屬於機器學習專案,設計它的目的就是讓它與人類進行互動。在學習的過程中,它把人類的好壞言論都學了。因此,它發表了一些不恰當的言論。我們正在糾偏,對Tay進行調整。”
微軟的機器學習演算法不可謂不先進,但是為什麼會出現這種情況呢,比較合理的解釋就是Tay是被人們輸入的“不良”樣本帶壞的。
一個好訊息是,OpenCV安裝包裡自帶有已經訓練好的人臉分類器“haarcascade_frontalface_alt.xml”,位置在“XX\opencv\sources\data\haarcascades”裡,我們可以直接拿來使用,檢測效果還可以接受。這個資料夾下還有其他一些分類器,像左右眼、上身、笑臉檢測等等。
下邊就使用OpenCV自帶的基於Haar特徵的級聯分類器實現人臉檢測,使用的版本是VS2012+OpenCV2.4.10,本來我的機器上安裝的是OpenCV2.4.13版本,但是發現13版本的載入分類器的函式cvLoad總是報錯,換成10版本就沒問題了(包括之前在訓練決策樹的時候,也發現2.4.13版本的訓練結果總是不對)。
程式涉及到Mat和IplImage指標的一個轉換,還有一個比較關鍵的函式cvHaarDetectObjects,函式原型是:
cvHaarDetectObjects( const CvArr* image, CvHaarClassifierCascade* cascade, CvMemStorage* storage, double scale_factor CV_DEFAULT(1.1), int min_neighbors CV_DEFAULT(3), int flags CV_DEFAULT(0), CvSize min_size CV_DEFAULT(cvSize(0,0)), CvSize max_size CV_DEFAULT(cvSize(0,0)));
- 第一個引數image,表示待檢測影象;
- 第二個引數cascade,表示Haar特徵分類器,需要使用cvLoad()載入Haar特徵分類器XML檔案;
- 第三個引數為storage,是申請的一塊記憶體空間,用於管理所使用的記憶體。
- 第四個引數scale_factor,表示下一次對影象的掃描中,搜尋視窗增長的比例係數,即下次搜尋視窗擴大的比例,有其預設值1.1。
- 第五個引數min_neighbors,從其命名上就可以看出來,表示構成檢測目標的相鄰矩形的最小個數,如果在檢測目標位置的“鄰居”位置上,檢測到的潛在的人臉目標小於設定值,則不認為是人臉區域,所有調節這個引數可以對人臉的檢測個數特別是目標的魯棒性產生影響。值越小,檢測到的人臉區域越多,同時意味著可能有誤檢和重複區域。
- 第六個引數CV_DEFAULT,不甚理解,使用預設值吧。
- 第七個引數min_size和第八個引數max_size表示檢測視窗的最小值和最大值,程式一般會根據影象大小自動設定。
#include <opencv2/opencv.hpp>
#include "highgui/highgui.hpp"
#include <Windows.h>
using namespace std;
using namespace cv;
int main()
{
// 載入Haar特徵檢測分類器
const char *pstrCascadeFileName = "D:\\ProgramFilesD\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml";
CvHaarClassifierCascade *pHaarCascade = NULL;
pHaarCascade = (CvHaarClassifierCascade*)cvLoad(pstrCascadeFileName);
// 載入影象並轉換為灰度影象
const char *pstrImageName = "E:\\Picture\\Face03.jpg";
Mat image=imread(pstrImageName);
Mat imageGray;
cvtColor(image,imageGray,CV_RGB2GRAY);
// 人臉識別與標記
if (pHaarCascade != NULL)
{
MemStorage mStorage=cvCreateMemStorage(0);
cvClearMemStorage(mStorage);
// 識別
DWORD dwTimeBegin, dwTimeEnd;
dwTimeBegin = GetTickCount();
//Mat轉換為IplImage
IplImage IimageGray(imageGray);
CvSeq *pcvSeqFaces = cvHaarDetectObjects(&IimageGray, pHaarCascade, mStorage);
dwTimeEnd = GetTickCount();
cout<<"檢測到的人臉總數:\n"<<pcvSeqFaces->total<<endl<<endl;
cout<<"檢測耗時:\n"<<dwTimeEnd-dwTimeBegin<<endl;
// 用矩形框標記
for(int i = 0; i <pcvSeqFaces->total; i++)
{
CvRect* r = (CvRect*)cvGetSeqElem(pcvSeqFaces, i);
Point2f p1=Point2f(r->x,r->y); //矩形左上角點位
Point2f p2=Point2f(r->x+r->height,r->y+r->width); //矩形右下角點位
rectangle(image,p1,p2,Scalar(255,0,0),2); //矩形框標註人臉位置
}
}
namedWindow("人臉檢測",0);
imshow("人臉檢測", image);
waitKey(0);
return 0;
}
標準臉:
藝術照:
多人合照:
這個是專門針對正面人臉的,檢測效果還可以,有時候會有誤檢,通過調整引數一般可以消除掉。
--------------------- 本文來自 -牧野- 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/dcrmg/article/details/53043718?utm_source=copy