在看了文檔[2,3]後開始對照著看OpenCV代碼,看得暈頭轉向啊。又搜了網上的一些文章,先針對自己的理解做筆記如下,日後好在此基礎上補充。OpenCV臉部偵測之資料結構:
所有的結構都代表一個級聯boosted Haar分類器。級聯有下面的等級結構:
Cascade:
Stage1:
Classifier11:
Feature11
Classifier12:
Feature12
...
Stage2:
Classifier21:
Feature21
...
...
關於特徵
typedef struct CvTHaarFeature//Haar-like 特徵
{
char desc[CV_HAAR_FEATURE_DESC_MAX];// haar_x3等描述feature的形狀
int tilted;//0->up-rightfeature, 1->45 rotated feature 見。
struct
{
CvRect r;
float weight;
} rect[CV_HAAR_FEATURE_MAX];//一個feature由2-3個長方形組成
} CvTHaarFeature;
typedef struct CvFastHaarFeature
{
int tilted; //0->up-right feature, 1->45rotated feature 見。
struct
{
int p0, p1, p2, p3;//把上面的Feature中的r的四個角點位置按照映像左上方開始算起第幾個(offset)。這樣方便後面等積分圖算出來後直接把p0,p1,p2,p3當做下標來取積分數值即可。
float weight;
} rect[CV_HAAR_FEATURE_MAX];
} CvFastHaarFeature;
typedef struct CvIntHaarFeatures
{
CvSize winsize;
int count;
CvTHaarFeature* feature;
CvFastHaarFeature* fastfeature;
} CvIntHaarFeatures;
/* Prepared for training samples */
typedef struct CvHaarTrainingData
{
CvSize winsize; /* training image size */
int maxnum; /* maximumnumber of samples *///(2000+2000)
CvMat sum; /* sumimages (each row represents image) *///(2000+2000) x (20x20)
CvMat tilted; /* tilted sumimages (each row represents image) *///(2000+2000) x (20x20)
CvMat normfactor; /* normalizationfactor */
CvMat cls; /* classes.1.0 - object, 0.0 - background */// 1 x (2000+2000)
CvMat weights; /* weights *///1 x (2000+2000)Adaboost訓練的時候需要的樣本權值
CvMat* valcache; /* precalculated feature values (CV_32FC1) */
CvMat* idxcache; /* presorted indices (CV_IDX_MAT_TYPE) */
} CvHaarTrainigData;
typedef struct CvUserdata
{
CvHaarTrainingData* trainingData;
CvIntHaarFeatures* haarFeatures;
} CvUserdata;
以上描述的結構體可總結如下[1].
關於分類器
typedef struct CvCARTHaarClassifier//基於Haar-like特徵的弱分類器
{
CV_INT_HAAR_CLASSIFIER_FIELDS()
int count;//這個弱分類器需要的Haar-like特徵數目,如果上傳調用時nsplits為1這個count值即為1,也就是說一般理解的弱分類器。
int* compidx;//選擇出的這個弱分類器的Haar-like特徵的序號
CvTHaarFeature* feature; //選擇出的這個弱分類器的Haar-like特徵
CvFastHaarFeature* fastfeature; //選擇出的這個弱分類器的Haar-like特徵
float* threshold; //選擇出的這個弱分類器的Haar-like特徵的threshold
int* left;//跟CART樹有關,應該是Node的序號
int* right; //跟CART樹有關,應該是Node的序號
float* val;//跟上面的threshold比較後的output值,其實是code裡面的Curleft和curright
} CvCARTHaarClassifier;
typedef struct CvStageHaarClassifier//基於Haar-like特徵的強分類器
{
CV_INT_HAAR_CLASSIFIER_FIELDS()
int count;
float threshold;//強分類器的threshold,大於此值的output為1,小於此值的output為0
CvIntHaarClassifier** classifier;//被轉化為弱分類器CvCARTHaarClassifier,
} CvStageHaarClassifier;
typedef struct CvCascadeHaarClassifier//基於Haar-like特徵的級聯強分類器
{
CV_INT_HAAR_CLASSIFIER_FIELDS()
int count;
CvIntHaarClassifier** classifier; //被轉化為強分類器CvStageHaarClassifier
} CvCascadeHaarClassifier;
/* internal weak classifier*/
typedef struct CvIntHaarClassifier
{//感覺像是c++裡的抽象類別的意思
CV_INT_HAAR_CLASSIFIER_FIELDS()
} CvIntHaarClassifier;
那麼這裡為什麼要使用一個如此複雜的結構呢。大體來說有兩個好處:
1、 方便弱分類器之間的切換,當我們不選用CART而是其他的弱分類器結構的時候,就可以調用CvIntHaarClassifier時轉換成其他的指標
2、 這樣方便了Haar訓練的過程和Boost過程的銜接。
訓練部分的介面及流程圖
OpenCV 有cvCreateTreeCascadeClassifier和cvCreateCascadeClassifier兩種級聯分類器,目前先討論後者。
建立Cascade分類器:
void cvCreateCascadeClassifier(
const char* dirname,//工作目錄
const char* vecfilename,//正樣本的描述檔案,其中包含正樣本的數目,寬高,以及所有樣本映像資料
const char* bgfilename,//負樣本的描述檔案,只包含負樣本的路徑
int npos, //用於訓練的正樣本的數目
int nneg, //用於訓練的負樣本的數目
int nstages,//訓練多少層
int numprecalculated, //MB
int numsplits, //在一個弱分類器中用的feature數目,1->stump classifier; 2或更多 -> CARTclassifier
float minhitrate, //每一個stage在訓練的時候需要達到的最低hit rate
float maxfalsealarm,//每一個stage在訓練的時候允許達到的最高的false alarm rate
float weightfraction,//boosting演算法的一個參數
int mode, //BASIC-> only uprightfeatures; ALL->full set of upright and 45度features;
int symmetric,//對稱的話可以加快訓練進程
int equalweights,//enable equal weightsfor positives and negatives.
int winwidth, //width of training images
int winheight, //height of training images
int boosttype, //DAB->Discrete Ada Boost;RAB->Real Ada Boost; LB->Logic Boost; GAB->Gentle Adaboost
int stumperror,//跟DAB有關的一個參數
)
建立Gentle Adaboost強分類器:
建立弱分類器:(以stump為例)不是我做的,是[1]裡的,openCV裡的代碼順序跟這個稍有出入,但是基本一致。
Curleft和curright 即為跟threshold比較後的output
Reference
1. http://wenku.baidu.com/view/87fccf09581b6bd97f19ea12.html
2. "Empirical Analysis of Detection Cascades of Boosted Classifiers for Rapid Object Detection" , Rainer Lienhart, Alexander Kuranov, Vadim Pisarevsky,2002
3. “Rapid Object Detection using a Boosted Cascade of Simple Features”, Paul Viola, Michael Jones, 2001