機器學習 機器學習的目的是把數據轉換成信息。
機器學習通過從數據裡提取規則或模式來把數據轉成信息。
人臉識別 人臉識別通過級聯分類器對特征的分級篩選來確定是否是人臉。
每個節點的正確識別率很高,但正確拒絕率很低。
任一節點判斷沒有人臉特征則結束運算,宣布不是人臉。
全部節點通過,則宣布是人臉。
工業上,常用人臉識別技術來識別物體。
對圖片進行識別 代碼如下:
#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 – 所要讀取分類器文件的文件名
參數 | filename – 所要讀取分類器文件的文件名
CascadeClassifier::empty
檢查分類器是否已經載入。
C++: bool CascadeClassifier::empty() const
CascadeClassifier::load
從一個文件讀取分類器。
C++: bool CascadeClassifier::load(const string& filename)
參數 filename – 所要讀取分類器文件的文件名。文件可以是舊版的HAAR分類器模型也可以是新版的分類器模型。
參數 | 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, int minNeighbors=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)
table4
直方圖均衡函數使用了下列的算發:
計算源文件的直方圖
。
調整直方圖,使得其方格總個數為255。
對直方圖進行積分:
使用
變換圖片,其映射函數為:
。
該算法歸一化亮度並增加了圖像的對比度。