OpenCV 2.4+ C++ 人臉識別
機器學習
- 機器學習的目的是把資料轉換成資訊。
- 機器學習通過從資料裡提取規則或模式來把資料轉成資訊。
人臉識別
- 人臉識別通過級聯分類器對特徵的分級篩選來確定是否是人臉。
- 每個節點的正確識別率很高,但正確拒絕率很低。
- 任一節點判斷沒有人臉特徵則結束運算,宣佈不是人臉。
- 全部節點通過,則宣佈是人臉。
工業上,常用人臉識別技術來識別物體。
對圖片進行識別
#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 = "人臉識別"; 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] 無法載入級聯分類器檔案!\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
用於檢測物體的級聯分類器類。
CascadeClassifier::CascadeClassifier
從一個檔案讀取分類器。
- C++:CascadeClassifier::CascadeClassifier(const string& filename)
引數 filename – 所要讀取分類器檔案的檔名 CascadeClassifier::empty
檢查分類器是否已經載入。
- C++:bool CascadeClassifier::empty() const
CascadeClassifier::load
從一個檔案讀取分類器。
- C++:bool CascadeClassifier::load(const string& filename)
引數 filename – 所要讀取分類器檔案的檔名。檔案可以是舊版的HAAR分類器模型也可以是新版的分類器模型。 CascadeClassifier::read
讀取一個檔案儲存節點的分類器。
C++:bool CascadeClassifier::read(const FileNode& node)
CascadeClassifier::detectMultiScale
對不同大小的輸入影象進行物體識別,並返回一個識別到的物體的矩陣列表。
- C++:void CascadeClassifier::detectMultiScale(const Mat& image, vector<Rect>& objects, double scaleFactor=1.1, intminNeighbors=3, int flags=0, Size minSize=Size(), Size maxSize=Size())
引數
- image – 需要檢測的 CV_8U 輸入矩陣。
- objects – 輸出vector載體容器用於儲存被識別的物體矩陣。
- scaleFactor – 指定每張圖片的縮小比例的引數。
- minNeighbors – 指定每個候選矩陣至少包含的鄰近元素個數。
- flags – 與舊版級聯分類器模型函式cvHaarDetectObjects的flags相同. 此引數不被用於新版模型。
- minSize – 最小可能的物件的大小,小於的物件將被忽略。
- maxSize – 最大可能的物件的大小,大於的物件將被忽略。
CascadeClassifier::setImage
設定被用於檢測的影象。
- C++:bool CascadeClassifier::setImage(Ptr<FeatureEvaluator>& feval, const Mat& image)
引數
- feval – 用於特徵計算的特徵求值程式的指標。
- image – 需要進行特徵檢測的 CV_8U 輸入矩陣。
這個函式將在每張圖片中被 CascadeClassifier::detectMultiScale() 自動呼叫。 但如果你想在不同位置手動使用CascadeClassifier::runAt(),你需要先呼叫該函式,使得影象被積分計算。
CascadeClassifier::runAt
在指定點執行檢測。
- C++:int CascadeClassifier::runAt(Ptr<FeatureEvaluator>& feval, Point pt, double& weight)
引數 feval – 用於特徵計算的特徵求值程式。
pt – 指定檢測視窗左上角的點。視窗的大小和檢測的圖片大小一致。
如果級聯分類器檢測到給定的位置中的一個物件,該函式返回1。否則,它會返回已被否決的候選區域在哪個階段的否定的指數。
使用CascadeClassifier::setImage() 設定影象的檢測工作。
程式碼註釋:
//需要載入的級聯分類器檔案 string face_cascade_name = "haarcascade_frontalface_alt.xml"; //級聯分類器類 CascadeClassifier face_cascade; //…… //載入級聯分類器,並判斷是否載入成功,如果不成功則列印提示 if( !face_cascade.load( face_cascade_name ) ){ printf("[error] 無法載入級聯分類器檔案!\n"); return -1; } //…… //對圖片frame進行識別檢測 face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
轉換成灰度圖
由於CascadeClassifier類只支援CV_8U矩陣資料,所以我們需要將圖片變成灰度圖。
cvtColor API:
將圖片從一個色彩空間轉到另一個色彩空間。
- C++:void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )
引數
- src – 輸入影象:8位無符號,16位無符號(CV_16UC...),或單精度浮點資料型別。
- dst – 輸出影象,與輸入影象相同大小、深度。
- code – 顏色空間轉換程式碼。
- dstCn – 目標影象的通道數,當該引數為0時,則通道樹由src和code自動得出。
該函式將輸入圖片從一個色彩空間轉到另一個色彩空間。當從RGB顏色空間進行變換時,應明確指定的通道的順序(RGB或BGR)。值得注意,在OpenCV的預設顏色格式中,通常被稱為作為RGB,但實際上是BGR(位元組是相反的)。因此,在一個標準的(24位)的彩色影象的第一個位元組是一個8位的藍色分量,第二個位元組將是綠色的,第三個位元組將是紅色的。而第四,第五,和第六位元組,則是第二畫素(藍,然後綠色,然後紅色),依此類推。
R、G和B 通道通常通道值範圍:
- CV_8U:0 — 255
- CV_16U:0 — 65535
- CV_32F:0 — 1
線性變換的情況下,有沒有範圍是無所謂的。但是,在一個非線性變換的情況下,輸入的RGB影象應被歸為適當的值範圍內,以得到正確的結果。例如,如果你有一個32位浮點影象直接轉換成一個8位的影象而沒有任何縮放,那麼它將有0到255的數值範圍,而這並不能準確0..1所有浮點數的值。所以,你需要之前呼叫cvtColor,進行影象縮放。
程式碼註釋:
//將frame轉換成灰度圖,輸出到frame_gray cvtColor( frame, frame_gray, CV_BGR2GRAY );
直方圖均衡化
- 直方圖是影象中畫素強度分佈的圖形表達方式。
- 它統計了每一個強度值所具有的畫素個數。
- 直方圖均衡化是通過拉伸畫素強度分佈範圍來增強影象對比度的一種方法。
- 說得更清楚一些, 以上面的直方圖為例, 你可以看到畫素主要集中在中間的一些強度值上. 直方圖均衡化要做的就是 拉伸 這個範圍. 見下面左圖: 綠圈圈出了 少有畫素分佈其上的 強度值. 對其應用均衡化後, 得到了中間圖所示的直方圖. 均衡化的影象見下面右圖.
我們利用直方圖均衡化對圖片增強對比度,方便級聯分類器分析。
equalizeHist API:
對灰度影象進行直方圖均衡。
- C++:void equalizeHist(InputArray src, OutputArray dst)
引數
- src – 源為8位單通道影象。
- dst – 輸出影象,和源圖片同樣大小型別。
直方圖均衡函式使用了下列的演算法:
計算原始檔的直方圖 。
調整直方圖,使得其方格總個數為255。
對直方圖進行積分:
使用 變換圖片,其對映函式為:。
該演算法歸一化亮度並增加了影象的對比度。
被山寨的原文
FROM: http://www.cnblogs.com/justany/archive/2012/11/22/2781552.html