opencv 做人臉識(shí)別 opencv 人臉匹配分析
更新時(shí)間:2012年11月22日 10:36:59 作者:
opencv 人臉識(shí)別通過級(jí)聯(lián)分類器對(duì)特征的分級(jí)篩選來確定是否是人臉,每個(gè)節(jié)點(diǎn)的正確識(shí)別率很高,但正確拒絕率很低,任一節(jié)點(diǎn)判斷沒有人臉特征則結(jié)束運(yùn)算,宣布不是人臉
機(jī)器學(xué)習(xí)
機(jī)器學(xué)習(xí)的目的是把數(shù)據(jù)轉(zhuǎn)換成信息。
機(jī)器學(xué)習(xí)通過從數(shù)據(jù)里提取規(guī)則或模式來把數(shù)據(jù)轉(zhuǎn)成信息。
人臉識(shí)別
人臉識(shí)別通過級(jí)聯(lián)分類器對(duì)特征的分級(jí)篩選來確定是否是人臉。
每個(gè)節(jié)點(diǎn)的正確識(shí)別率很高,但正確拒絕率很低。
任一節(jié)點(diǎn)判斷沒有人臉特征則結(jié)束運(yùn)算,宣布不是人臉。
全部節(jié)點(diǎn)通過,則宣布是人臉。
工業(yè)上,常用人臉識(shí)別技術(shù)來識(shí)別物體。
對(duì)圖片進(jìn)行識(shí)別
#include "opencv2/core/core.hpp"
#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;
string face_cascade_name = "haarcascade_frontalface_alt.xml";
CascadeClassifier face_cascade;
string window_name = "人臉識(shí)別";
void detectAndDisplay( Mat frame );
int main( int argc, char** argv ){
Mat image;
image = imread( argv[1]);
if( argc != 2 || !image.data ){
printf("[error] 沒有圖片\n");
return -1;
}
if( !face_cascade.load( face_cascade_name ) ){
printf("[error] 無法加載級(jí)聯(lián)分類器文件!\n");
return -1;
}
detectAndDisplay(image);
waitKey(0);
}
void detectAndDisplay( Mat frame ){
std::vector<Rect> faces;
Mat frame_gray;
cvtColor( frame, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( int i = 0; i < faces.size(); i++ ){
Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
}
imshow( window_name, frame );
}
CascadeClassifier類
class CascadeClassifier
用于檢測(cè)物體的級(jí)聯(lián)分類器類。
CascadeClassifier::CascadeClassifier
從一個(gè)文件讀取分類器。
C++: CascadeClassifier::CascadeClassifier(const string& filename)
參數(shù) filename – 所要讀取分類器文件的文件名
CascadeClassifier::empty
檢查分類器是否已經(jīng)載入。
C++: bool CascadeClassifier::empty() const
CascadeClassifier::load
從一個(gè)文件讀取分類器。
C++: bool CascadeClassifier::load(const string& filename)
參數(shù) filename – 所要讀取分類器文件的文件名。文件可以是舊版的HAAR分類器模型也可以是新版的分類器模型。
CascadeClassifier::read
讀取一個(gè)文件存儲(chǔ)節(jié)點(diǎn)的分類器。
C++: bool CascadeClassifier::read(const FileNode& node)
CascadeClassifier::detectMultiScale
對(duì)不同大小的輸入圖像進(jìn)行物體識(shí)別,并返回一個(gè)識(shí)別到的物體的矩陣列表。
C++: void CascadeClassifier::detectMultiScale(const Mat& image, vector<Rect>& objects, double scaleFactor=1.1, int minNeighbors=3, int flags=0, Size minSize=Size(), Size maxSize=Size())
CascadeClassifier::setImage
設(shè)置被用于檢測(cè)的圖像。
C++: bool CascadeClassifier::setImage(Ptr<FeatureEvaluator>& feval, const Mat& image)
這個(gè)函數(shù)將在每張圖片中被 CascadeClassifier::detectMultiScale() 自動(dòng)調(diào)用。 但如果你想在不同位置手動(dòng)使用 CascadeClassifier::runAt(),你需要先調(diào)用該函數(shù),使得圖像被積分計(jì)算。
CascadeClassifier::runAt
在指定點(diǎn)運(yùn)行檢測(cè)。
C++: int CascadeClassifier::runAt(Ptr<FeatureEvaluator>& feval, Point pt, double& weight)
如果級(jí)聯(lián)分類器檢測(cè)到給定的位置中的一個(gè)對(duì)象,該函數(shù)返回1。否則,它會(huì)返回已被否決的候選區(qū)域在哪個(gè)階段的否定的指數(shù)。
使用CascadeClassifier::setImage() 設(shè)置圖像的檢測(cè)工作。
代碼注釋:
//需要載入的級(jí)聯(lián)分類器文件
string face_cascade_name = "haarcascade_frontalface_alt.xml";
//級(jí)聯(lián)分類器類
CascadeClassifier face_cascade;
//……
//載入級(jí)聯(lián)分類器,并判斷是否載入成功,如果不成功則打印提示
if( !face_cascade.load( face_cascade_name ) ){
printf("[error] 無法加載級(jí)聯(lián)分類器文件!\n");
return -1;
}
//……
//對(duì)圖片frame進(jìn)行識(shí)別檢測(cè)
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
轉(zhuǎn)換成灰度圖
由于CascadeClassifier類只支持CV_8U矩陣數(shù)據(jù),所以我們需要將圖片變成灰度圖。
cvtColor API:
將圖片從一個(gè)色彩空間轉(zhuǎn)到另一個(gè)色彩空間。
C++: void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )
該函數(shù)將輸入圖片從一個(gè)色彩空間轉(zhuǎn)到另一個(gè)色彩空間。當(dāng)從RGB顏色空間進(jìn)行變換時(shí),應(yīng)明確指定的信道的順序(RGB或BGR)。值得注意,在OpenCV的默認(rèn)顏色格式中,通常被稱為作為RGB,但實(shí)際上是BGR(字節(jié)是相反的)。因此,在一個(gè)標(biāo)準(zhǔn)的(24位)的彩色圖像的第一個(gè)字節(jié)是一個(gè)8位的藍(lán)色分量,第二個(gè)字節(jié)將是綠色的,第三個(gè)字節(jié)將是紅色的。而第四,第五,和第六字節(jié),則是第二像素(藍(lán),然后綠色,然后紅色),依此類推。
R、G和B 通道通常信道值范圍:
CV_8U:0 — 255
CV_16U:0 — 65535
CV_32F:0 — 1
線性變換的情況下,有沒有范圍是無所謂的。但是,在一個(gè)非線性變換的情況下,輸入的RGB圖像應(yīng)被歸為適當(dāng)?shù)闹捣秶鷥?nèi),以得到正確的結(jié)果。例如,如果你有一個(gè)32位浮點(diǎn)圖像直接轉(zhuǎn)換成一個(gè)8位的圖像而沒有任何縮放,那么它將有0到255的數(shù)值范圍,而這并不能準(zhǔn)確0..1所有浮點(diǎn)數(shù)的值。所以,你需要之前調(diào)用cvtColor,進(jìn)行圖像縮放。
代碼注釋:
//將frame轉(zhuǎn)換成灰度圖,輸出到frame_gray
cvtColor( frame, frame_gray, CV_BGR2GRAY );
直方圖均衡化
直方圖是圖像中像素強(qiáng)度分布的圖形表達(dá)方式。
它統(tǒng)計(jì)了每一個(gè)強(qiáng)度值所具有的像素個(gè)數(shù)。
直方圖均衡化是通過拉伸像素強(qiáng)度分布范圍來增強(qiáng)圖像對(duì)比度的一種方法。
說得更清楚一些, 以上面的直方圖為例, 你可以看到像素主要集中在中間的一些強(qiáng)度值上. 直方圖均衡化要做的就是 拉伸 這個(gè)范圍. 見下面左圖: 綠圈圈出了 少有像素分布其上的 強(qiáng)度值. 對(duì)其應(yīng)用均衡化后, 得到了中間圖所示的直方圖. 均衡化的圖像見下面右圖.
我們利用直方圖均衡化對(duì)圖片增強(qiáng)對(duì)比度,方便級(jí)聯(lián)分類器分析。
equalizeHist API:
對(duì)灰度圖像進(jìn)行直方圖均衡。
C++: void equalizeHist(InputArray src, OutputArray dst)
table4
直方圖均衡函數(shù)使用了下列的算發(fā):
計(jì)算源文件的直方圖
。
調(diào)整直方圖,使得其方格總個(gè)數(shù)為255。
對(duì)直方圖進(jìn)行積分:

使用
變換圖片,其映射函數(shù)為:
。
該算法歸一化亮度并增加了圖像的對(duì)比度。
機(jī)器學(xué)習(xí)的目的是把數(shù)據(jù)轉(zhuǎn)換成信息。
機(jī)器學(xué)習(xí)通過從數(shù)據(jù)里提取規(guī)則或模式來把數(shù)據(jù)轉(zhuǎn)成信息。
人臉識(shí)別
人臉識(shí)別通過級(jí)聯(lián)分類器對(duì)特征的分級(jí)篩選來確定是否是人臉。
每個(gè)節(jié)點(diǎn)的正確識(shí)別率很高,但正確拒絕率很低。
任一節(jié)點(diǎn)判斷沒有人臉特征則結(jié)束運(yùn)算,宣布不是人臉。
全部節(jié)點(diǎn)通過,則宣布是人臉。
工業(yè)上,常用人臉識(shí)別技術(shù)來識(shí)別物體。
對(duì)圖片進(jìn)行識(shí)別
復(fù)制代碼 代碼如下:
#include "opencv2/core/core.hpp"
#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;
string face_cascade_name = "haarcascade_frontalface_alt.xml";
CascadeClassifier face_cascade;
string window_name = "人臉識(shí)別";
void detectAndDisplay( Mat frame );
int main( int argc, char** argv ){
Mat image;
image = imread( argv[1]);
if( argc != 2 || !image.data ){
printf("[error] 沒有圖片\n");
return -1;
}
if( !face_cascade.load( face_cascade_name ) ){
printf("[error] 無法加載級(jí)聯(lián)分類器文件!\n");
return -1;
}
detectAndDisplay(image);
waitKey(0);
}
void detectAndDisplay( Mat frame ){
std::vector<Rect> faces;
Mat frame_gray;
cvtColor( frame, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for( int i = 0; i < faces.size(); i++ ){
Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
}
imshow( window_name, frame );
}
CascadeClassifier類
class CascadeClassifier
用于檢測(cè)物體的級(jí)聯(lián)分類器類。
CascadeClassifier::CascadeClassifier
從一個(gè)文件讀取分類器。
C++: CascadeClassifier::CascadeClassifier(const string& filename)
參數(shù) filename – 所要讀取分類器文件的文件名
參數(shù) | filename – 所要讀取分類器文件的文件名 |
---|
CascadeClassifier::empty
檢查分類器是否已經(jīng)載入。
C++: bool CascadeClassifier::empty() const
CascadeClassifier::load
從一個(gè)文件讀取分類器。
C++: bool CascadeClassifier::load(const string& filename)
參數(shù) filename – 所要讀取分類器文件的文件名。文件可以是舊版的HAAR分類器模型也可以是新版的分類器模型。
參數(shù) | filename – 所要讀取分類器文件的文件名。文件可以是舊版的HAAR分類器模型也可以是新版的分類器模型。 |
---|
CascadeClassifier::read
讀取一個(gè)文件存儲(chǔ)節(jié)點(diǎn)的分類器。
C++: bool CascadeClassifier::read(const FileNode& node)
CascadeClassifier::detectMultiScale
對(duì)不同大小的輸入圖像進(jìn)行物體識(shí)別,并返回一個(gè)識(shí)別到的物體的矩陣列表。
C++: void CascadeClassifier::detectMultiScale(const Mat& image, vector<Rect>& objects, double scaleFactor=1.1, int minNeighbors=3, int flags=0, Size minSize=Size(), Size maxSize=Size())
參數(shù) |
|
---|
CascadeClassifier::setImage
設(shè)置被用于檢測(cè)的圖像。
C++: bool CascadeClassifier::setImage(Ptr<FeatureEvaluator>& feval, const Mat& image)
參數(shù) |
|
---|
這個(gè)函數(shù)將在每張圖片中被 CascadeClassifier::detectMultiScale() 自動(dòng)調(diào)用。 但如果你想在不同位置手動(dòng)使用 CascadeClassifier::runAt(),你需要先調(diào)用該函數(shù),使得圖像被積分計(jì)算。
CascadeClassifier::runAt
在指定點(diǎn)運(yùn)行檢測(cè)。
C++: int CascadeClassifier::runAt(Ptr<FeatureEvaluator>& feval, Point pt, double& weight)
參數(shù) |
feval – 用于特征計(jì)算的特征求值程序。 pt – 指定檢測(cè)窗口左上角的點(diǎn)。窗口的大小和檢測(cè)的圖片大小一致。 |
---|
如果級(jí)聯(lián)分類器檢測(cè)到給定的位置中的一個(gè)對(duì)象,該函數(shù)返回1。否則,它會(huì)返回已被否決的候選區(qū)域在哪個(gè)階段的否定的指數(shù)。
使用CascadeClassifier::setImage() 設(shè)置圖像的檢測(cè)工作。
代碼注釋:
復(fù)制代碼 代碼如下:
//需要載入的級(jí)聯(lián)分類器文件
string face_cascade_name = "haarcascade_frontalface_alt.xml";
//級(jí)聯(lián)分類器類
CascadeClassifier face_cascade;
//……
//載入級(jí)聯(lián)分類器,并判斷是否載入成功,如果不成功則打印提示
if( !face_cascade.load( face_cascade_name ) ){
printf("[error] 無法加載級(jí)聯(lián)分類器文件!\n");
return -1;
}
//……
//對(duì)圖片frame進(jìn)行識(shí)別檢測(cè)
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
轉(zhuǎn)換成灰度圖
由于CascadeClassifier類只支持CV_8U矩陣數(shù)據(jù),所以我們需要將圖片變成灰度圖。
cvtColor API:
將圖片從一個(gè)色彩空間轉(zhuǎn)到另一個(gè)色彩空間。
C++: void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )
參數(shù) |
|
---|
該函數(shù)將輸入圖片從一個(gè)色彩空間轉(zhuǎn)到另一個(gè)色彩空間。當(dāng)從RGB顏色空間進(jìn)行變換時(shí),應(yīng)明確指定的信道的順序(RGB或BGR)。值得注意,在OpenCV的默認(rèn)顏色格式中,通常被稱為作為RGB,但實(shí)際上是BGR(字節(jié)是相反的)。因此,在一個(gè)標(biāo)準(zhǔn)的(24位)的彩色圖像的第一個(gè)字節(jié)是一個(gè)8位的藍(lán)色分量,第二個(gè)字節(jié)將是綠色的,第三個(gè)字節(jié)將是紅色的。而第四,第五,和第六字節(jié),則是第二像素(藍(lán),然后綠色,然后紅色),依此類推。
R、G和B 通道通常信道值范圍:
CV_8U:0 — 255
CV_16U:0 — 65535
CV_32F:0 — 1
線性變換的情況下,有沒有范圍是無所謂的。但是,在一個(gè)非線性變換的情況下,輸入的RGB圖像應(yīng)被歸為適當(dāng)?shù)闹捣秶鷥?nèi),以得到正確的結(jié)果。例如,如果你有一個(gè)32位浮點(diǎn)圖像直接轉(zhuǎn)換成一個(gè)8位的圖像而沒有任何縮放,那么它將有0到255的數(shù)值范圍,而這并不能準(zhǔn)確0..1所有浮點(diǎn)數(shù)的值。所以,你需要之前調(diào)用cvtColor,進(jìn)行圖像縮放。
代碼注釋:
復(fù)制代碼 代碼如下:
//將frame轉(zhuǎn)換成灰度圖,輸出到frame_gray
cvtColor( frame, frame_gray, CV_BGR2GRAY );
直方圖均衡化
直方圖是圖像中像素強(qiáng)度分布的圖形表達(dá)方式。
它統(tǒng)計(jì)了每一個(gè)強(qiáng)度值所具有的像素個(gè)數(shù)。

直方圖均衡化是通過拉伸像素強(qiáng)度分布范圍來增強(qiáng)圖像對(duì)比度的一種方法。
說得更清楚一些, 以上面的直方圖為例, 你可以看到像素主要集中在中間的一些強(qiáng)度值上. 直方圖均衡化要做的就是 拉伸 這個(gè)范圍. 見下面左圖: 綠圈圈出了 少有像素分布其上的 強(qiáng)度值. 對(duì)其應(yīng)用均衡化后, 得到了中間圖所示的直方圖. 均衡化的圖像見下面右圖.

我們利用直方圖均衡化對(duì)圖片增強(qiáng)對(duì)比度,方便級(jí)聯(lián)分類器分析。
equalizeHist API:
對(duì)灰度圖像進(jìn)行直方圖均衡。
C++: void equalizeHist(InputArray src, OutputArray dst)
table4
直方圖均衡函數(shù)使用了下列的算發(fā):
計(jì)算源文件的直方圖

調(diào)整直方圖,使得其方格總個(gè)數(shù)為255。
對(duì)直方圖進(jìn)行積分:

使用


該算法歸一化亮度并增加了圖像的對(duì)比度。
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)靜態(tài)存儲(chǔ)通訊錄的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C語(yǔ)言實(shí)現(xiàn)一個(gè)靜態(tài)存儲(chǔ)的通訊錄,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C語(yǔ)言有一定幫助,需要的可以參考一下2022-09-09C語(yǔ)言使用結(jié)構(gòu)體實(shí)現(xiàn)簡(jiǎn)單通訊錄
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言使用結(jié)構(gòu)體實(shí)現(xiàn)簡(jiǎn)單通訊錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02C++?AVL樹插入新節(jié)點(diǎn)后的四種調(diào)整情況梳理介紹
AVL樹是高度平衡的而二叉樹,它的特點(diǎn)是AVL樹中任何節(jié)點(diǎn)的兩個(gè)子樹的高度最大差別為1,本文主要給大家介紹了C++如何實(shí)現(xiàn)AVL樹,需要的朋友可以參考下2022-08-08C語(yǔ)言中你容易忽略的知識(shí)點(diǎn)與技巧總結(jié)
這篇文章主要給大家介紹了關(guān)于C語(yǔ)言中你容易忽略的知識(shí)點(diǎn)與技巧,文中通過實(shí)例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-03-03