1. 程式人生 > >OpenCV原理解讀之HAAR+Adaboost

OpenCV原理解讀之HAAR+Adaboost

cvLoadHaarClassifierCascade

從檔案中裝載訓練好的級聯分類器或者從OpenCV中嵌入的分類器資料庫中匯入

CvHaarClassifierCascade* cvLoadHaarClassifierCascade(
                         const char* directory,
                         CvSize orig_window_size );

directory:訓練好的級聯分類器的路徑

orig_window_size:級聯分類器訓練中採用的檢測目標的尺寸。因為這個資訊沒有在級聯分類器中儲存,所以要單獨指出,但是在haarcascade_frontalface_alt.xml中有指出size的大小。

函式 cvLoadHaarClassifierCascade 用於從檔案中裝載訓練好的利用哈爾特徵的級聯分類器,或者從OpenCV中嵌入的分類器資料庫中匯入。分類器的訓練可以應用函式haartraining(詳細察看opencv/apps/haartraining),orig_window_size是在訓練分類器時就確定好的,修改它並不能改變檢測的範圍或精度。

需要注意的是,這個函式已經過時了。現在的目標檢測分類器通常儲存在 XML 或 YAML 檔案中,而不是通過路徑匯入。從檔案中匯入分類器,可以使用函式 cvLoad 

cvReleaseHaarClassifierCascade

釋放haar classifier cascade。

void cvReleaseHaarClassifierCascade( CvHaarClassifierCascade** cascade );

cascade:雙指標型別指標指向要釋放的cascade. 指標由函式宣告。

函式 cvReleaseHaarClassifierCascade 釋放cascade的動態記憶體,其中cascade的動態記憶體或者是手工建立,或者通過函式 cvLoadHaarClassifierCascade 或 cvLoad分配。

cvHaarDetectObjects

檢測影象中的目標

typedef struct CvAvgComp
{
    CvRect rect; /* bounding rectangle for the object (average rectangle of a group) */
    int neighbors; /* number of neighbor rectangles in the group */
}
CvAvgComp;

CvSeq* cvHaarDetectObjects( const CvArr* image, CvHaarClassifierCascade* cascade,
                            CvMemStorage* storage, double scale_factor=1.1,
                            int min_neighbors=3, int flags=0,
                            CvSize min_size=cvSize(0,0) );

image:被檢影象

cascade:harr 分類器級聯的內部標識形式

storage:用來儲存檢測到的一序列候選目標矩形框的記憶體區域。

scale_factor:在前後兩次相繼的掃描中,搜尋視窗的比例係數。例如1.1指將搜尋視窗依次擴大10%。

min_neighbors:構成檢測目標的相鄰矩形的最小個數(預設-1)。如果組成檢測目標的小矩形的個數和小於min_neighbors-1 都會被排除。如果min_neighbors 為 0, 則函式不做任何操作就返回所有的被檢候選矩形框,這種設定值一般用在使用者自定義對檢測結果的組合程式上。

flags:操作方式。當前可以定義的操作方式是CV_HAAR_DO_CANNY_PRUNING(CANNY邊緣檢測)、CV_HAAR_SCALE_IMAGE(縮放影象檢測)、CV_HAAR_FIND_BIGGEST_OBJECT(尋找最大的目標)、CV_HAAR_DO_ROUGH_SEARCH(做粗略搜尋)

如果CV_HAAR_DO_CANNY_PRUNING被設定,函式利用Canny邊緣檢測器來排除一些邊緣很少或者很多的影象區域,因為這樣的區域一般不含被檢目標。人臉檢測中通過設定閾值使用了這種方法,並因此提高了檢測速度。當然該標記是在沒有定義CV_HAAR_SCALE_IMAGE下使用的,也就是說使用縮放檢測視窗的形式定義的

如果CV_HAAR_SCALE_IMAGE被設定則在每一個scale上縮放影象檢測,如果沒有定義則縮放檢測視窗進行檢測,當縮放檢測視窗檢測的時候是不能返回rejectLevels和levelWeights的。

如果CV_HAAR_FIND_BIGGEST_OBJECT被設定,如果沒有設定CV_HAAR_SCALE_IMAGE,儲存當前檢測視窗中面積最大的矩形,不管設定沒有設定CV_HAAR_SCALE_IMAGE,最後都輸出一個面積最大的矩形(如果檢測結果不為空的話),詳細分析可以參考cvHaarDetectObjectsForROC

如果CV_HAAR_DO_ROUGH_SEARCH設定了,則最小的縮放比例為0.6,否則為0.4,僅在縮放檢測視窗中有效

if( findBiggestObject )

   flags &= ~(CV_HAAR_SCALE_IMAGE|CV_HAAR_DO_CANNY_PRUNING);

從以上程式碼可以看出,尋找最大目標優先於縮放影象和邊緣檢測,也就是說如果同時定義了以上三項,則以尋找最大目標為準

其次從程式碼結構上縮放影象在前縮放檢測視窗在後,因此如果定義了縮放影象,則不進行邊緣檢測

min_size:檢測視窗的最小尺寸。預設的情況下被設為分類器訓練時採用的樣本尺寸(人臉檢測中預設大小是~20×20)。

函式 cvHaarDetectObjects 使用針對某目標物體訓練的級聯分類器在影象中找到包含目標物體的矩形區域,並且將這些區域作為一序列的矩形框返回。函式以不同比例大小的掃描視窗對影象進行幾次搜尋(察看cvSetImagesForHaarClassifierCascade)。 每次都要對影象中的這些重疊區域利用cvRunHaarClassifierCascade進行檢測。 有時候也會利用某些繼承(heuristics)技術以減少分析的候選區域,例如利用 Canny 裁減 (prunning)方法。 函式在處理和收集到候選的方框(全部通過級聯分類器各層的區域)之後,接著對這些區域進行組合並且返回一系列各個足夠大的組合中的平均矩形。調節程式中的預設引數(scale_factor=1.1, min_neighbors=3, flags=0)用於對目標進行更精確同時也是耗時較長的進一步檢測。為了能對視訊影象進行更快的實時檢測,引數設定通常是:scale_factor=1.2, min_neighbors=2, flags=CV_HAAR_DO_CANNY_PRUNING, min_size=<minimum possible face size> (例如, 對於視訊會議的影象區域).

程式內部呼叫cvHaarDetectObjectsForROC實現目標檢測,返回結果儲存在返回值CvSeq中,使用CvAvgComp結構體可以實現CvSeq到Rect的轉換

vector<CvAvgComp> vecAvgComp;

Seq<CvAvgComp>(_objects).copyTo(vecAvgComp);

objects.resize(vecAvgComp.size());

std::transform(vecAvgComp.begin(), vecAvgComp.end(), objects.begin(), getRect());

也可以使用cvGetSeqElem實現資料的讀取

CvRect face_rect = *(CvRect*)cvGetSeqElem( _objects, i, 0 ); cvHaarDetectObjectsForROC 執行目標檢測,可以返回rejectLevels和levelWeights CvSeq* cvHaarDetectObjectsForROC( const CvArr* _img,                      CvHaarClassifierCascade* cascade, CvMemStorage* storage,                      std::vector<int>& rejectLevels, std::vector<double>& levelWeights,                      double scaleFactor, int minNeighbors, int flags,                      CvSize minSize, CvSize maxSize, bool outputRejectLevels ); 在該函式cvHaarDetectObjectsForROC的內部呼叫了以下函式進行目標的檢測,需要注意的是如果定義了多尺度檢測也就是引數flags中設定了CV_HAAR_SCALE_IMAGE,則在後續檢測中在每一個scale上使用cvSetImagesForHaarClassifierCascade設定影象(scale=1.0),使用HaarDetectObjects_ScaleImage_Invoker進行並行運算(可以返回rejectLevels和levelWeights),而如果沒有設定多尺度檢測則只在當前尺度上使用cvSetImagesForHaarClassifierCascade設定影象(scale*=scaleFactor,需要注意的是當設定了CV_HAAR_FIND_BIGGEST_OBJECT則scaleFactor=1/scaleFactor,並且scale從最大開始不斷減小到1,否則scale從1開始不斷增大到最大),使用HaarDetectObjects_ScaleCascade_Invoker進行並行運算(不可以返回rejectLevels和levelWeights) 不管是使用縮放檢測影象,還是使用縮放檢測視窗,檢測完畢後對視窗進行合併     if( minNeighbors != 0 || findBiggestObject )     {         if( outputRejectLevels )             groupRectangles(rectList, rejectLevels, levelWeights, minNeighbors, GROUP_EPS ); // 關於group的方法參考《OpenCV函式解讀之groupRectangles         else             groupRectangles(rectList, rweights, std::max(minNeighbors, 1), GROUP_EPS);     }     else         rweights.resize(rectList.size(),0); 從上面的程式碼可以看出如果定義了CV_HAAR_FIND_BIGGEST_OBJECT,並且輸出outputRejectLevels為true的話是肯定沒有結果的,因為如果定義了CV_HAAR_FIND_BIGGEST_OBJECT,是不能進行縮放影象檢測的(CV_HAAR_SCALE_IMAGE被置為0),不進行縮放影象檢測也就不能返回rejectLevels和levelWeights,因此如果想返回rejectLevels和levelWeights,則必須不能定義CV_HAAR_FIND_BIGGEST_OBJECT並且必須定義CV_HAAR_SCALE_IMAGE,同時outputRejectLevels必須為true。當然如果定義不恰當很可能返回值中存在object但是不存在rejectLevels和levelWeights。 icvCreateHidHaarClassifierCascade 建立hid haar級聯分類器 /* create more efficient internal representation of haar classifier cascade */