Cv模式識別


目標檢測(轉至OpenCV中文論壇)

目標檢測方法最初由Paul Viola [Viola01]提出,並由Rainer Lienhart [Lienhart02]對這一方法進行了改善. 首先,利用樣本(大約幾百幅樣本圖片)的 harr 特徵進行分類器訓練,得到一個級聯的boosted分類器。訓練樣本分爲正例樣本和反例樣本,其中正例樣本是指待檢目標樣本(例如人臉或汽車等),反例樣本指其它任意圖片,所有的樣本圖片都被歸一化爲同樣的尺寸大小(例如,20x20)。

分類器訓練完以後,就可以應用於輸入圖像中的感興趣區域(與訓練樣本相同的尺寸)的檢測。檢測到目標區域(汽車或人臉)分類器輸出爲1,否則輸出爲0。爲了檢測整副圖像,可以在圖像中移動搜索窗口,檢測每一個位置來確定可能的目標。 爲了搜索不同大小的目標物體,分類器被設計爲可以進行尺寸改變,這樣比改變待檢圖像的尺寸大小更爲有效。所以,爲了在圖像中檢測未知大小的目標物體,掃描程序通常需要用不同比例大小的搜索窗口對圖片進行幾次掃描。

分類器中的“級聯”是指最終的分類器是由幾個簡單分類器級聯組成。在圖像檢測中,被檢窗口依次通過每一級分類器, 這樣在前面幾層的檢測中大部分的候選區域就被排除了,全部通過每一級分類器檢測的區域即爲目標區域。 目前支持這種分類器的boosting技術有四種: Discrete Adaboost, Real Adaboost, Gentle Adaboost and Logitboost。"boosted" 即指級聯分類器的每一層都可以從中選取一個boosting算法(權重投票),並利用基礎分類器的自我訓練得到。基礎分類器是至少有兩個葉結點的決策樹分類器。 Haar特徵是基礎分類器的輸入,主要描述如下。目前的算法主要利用下面的Harr特徵。

Image:Haarfeatures.png

每個特定分類器所使用的特徵用形狀、感興趣區域中的位置以及比例係數(這裏的比例係數跟檢測時候採用的比例係數是不一樣的,儘管最後會取兩個係數的乘積值)來定義。例如在第二行特徵(2c)的情況下,響應計算爲覆蓋全部特徵整個矩形框(包括兩個白色矩形框和一個黑色矩形框)象素的和減去黑色矩形框內象素和的三倍 。每個矩形框內的象素和都可以通過積分圖象很快的計算出來。(察看下面和對cvIntegral的描述).

通過HaarFaceDetect 的演示版可以察看目標檢測的工作情況。

下面只是檢測部分的參考手冊。 haartraining是它的一個單獨的應用,可以用來對系列樣本訓練級聯的 boosted分類器。詳細察看opencv/apps/haartraining。

CvHaarFeature, CvHaarClassifier, CvHaarStageClassifier, CvHaarClassifierCascade

Boosted Haar 分類器結構

#define CV_HAAR_FEATURE_MAX  3
/* 一個 harr 特徵由 2-3 個具有相應權重的矩形組成 */
/* a haar feature consists of 2-3 rectangles with appropriate weights */
typedef struct CvHaarFeature
{
    int  tilted;  /* 0 means up-right feature, 1 means 45--rotated feature */
    
    /* 2-3 rectangles with weights of opposite signs and
       with absolute values inversely proportional to the areas of the rectangles.
       if rect[2].weight !=0, then
       the feature consists of 3 rectangles, otherwise it consists of 2 */
    struct
    {
        CvRect r;
        float weight;
    } rect[CV_HAAR_FEATURE_MAX];
}
CvHaarFeature;
/* a single tree classifier (stump in the simplest case) that returns the response for the feature
   at the particular image location (i.e. pixel sum over subrectangles of the window) and gives out
   a value depending on the responce */
typedef struct CvHaarClassifier
{
    int count;  /* number of nodes in the decision tree */
    /* these are "parallel" arrays. Every index i
       corresponds to a node of the decision tree (root has 0-th index).
       left[i] - index of the left child (or negated index if the left child is a leaf)
       right[i] - index of the right child (or negated index if the right child is a leaf)
       threshold[i] - branch threshold. if feature responce is <= threshold, left branch
                      is chosen, otherwise right branch is chosed.
       alpha[i] - output value correponding to the leaf. */
    CvHaarFeature* haar_feature;
    float* threshold;
    int* left;
    int* right;
    float* alpha;
}
CvHaarClassifier;
/* a boosted battery of classifiers(=stage classifier):
   the stage classifier returns 1
   if the sum of the classifiers' responces
   is greater than threshold and 0 otherwise */
typedef struct CvHaarStageClassifier
{
    int  count;  /* number of classifiers in the battery */
    float threshold; /* threshold for the boosted classifier */
    CvHaarClassifier* classifier; /* array of classifiers */
    /* these fields are used for organizing trees of stage classifiers,
       rather than just stright cascades */
    int next;
    int child;
    int parent;
}
CvHaarStageClassifier;
typedef struct CvHidHaarClassifierCascade CvHidHaarClassifierCascade;
/* cascade or tree of stage classifiers */
typedef struct CvHaarClassifierCascade
{
    int  flags; /* signature */
    int  count; /* number of stages */
    CvSize orig_window_size; /* original object size (the cascade is trained for) */
    /* these two parameters are set by cvSetImagesForHaarClassifierCascade */
    CvSize real_window_size; /* current object size */
    double scale; /* current scale */
    CvHaarStageClassifier* stage_classifier; /* array of stage classifiers */
    CvHidHaarClassifierCascade* hid_cascade; /* hidden optimized representation of the cascade,
                                                created by cvSetImagesForHaarClassifierCascade */
}
CvHaarClassifierCascade;

所有的結構都代表一個級聯boosted Haar分類器。級聯有下面的等級結構:

Cascade:
Stage1:
Classifier11:
Feature11
Classifier12:
Feature12
...
Stage2:
Classifier21:
Feature21
...
...

整個等級可以手工構建,也可以利用函數cvLoadHaarClassifierCascade從已有的磁盤文件或嵌入式基中導入。

cvLoadHaarClassifierCascade

從文件中裝載訓練好的級聯分類器或者從OpenCV中嵌入的分類器數據庫中導入

CvHaarClassifierCascade* cvLoadHaarClassifierCascade(
                         const char* directory,
                         CvSize orig_window_size );
directory
訓練好的級聯分類器的路徑
orig_window_size
級聯分類器訓練中採用的檢測目標的尺寸。因爲這個信息沒有在級聯分類器中存儲,所以要單獨指出。

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

需要注意的是,這個函數已經過時了。現在的目標檢測分類器通常存儲在 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邊緣檢測器來排除一些邊緣很少或者很多的圖像區域,因爲這樣的區域一般不含被檢目標。人臉檢測中通過設定閾值使用了這種方法,並因此提高了檢測速度。
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> (例如, 對於視頻會議的圖像區域).

例子:利用級聯的Haar classifiers尋找檢測目標(e.g. faces).

#include "cv.h"
#include "highgui.h"
CvHaarClassifierCascade* load_object_detector( const char* cascade_path 
{
    return (CvHaarClassifierCascade*)cvLoad( cascade_path );
}
void detect_and_draw_objects( IplImage* image,
                              CvHaarClassifierCascade* cascade,
                              int do_pyramids )
{
    IplImage* small_image = image;
    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* faces;
    int i, scale = 1;

    /* if the flag is specified, down-scale the 輸入圖像 to get a
       performance boost w/o loosing quality (perhaps) */
    if( do_pyramids )
    {
        small_image = cvCreateImage( cvSize(image->width/2,image->height/2), IPL_DEPTH_8U, 3 );
        cvPyrDown( image, small_image, CV_GAUSSIAN_5x5 );
        scale = 2;
    }

    /* use the fastest variant */
    faces = cvHaarDetectObjects( small_image, cascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING );

    /* draw all the rectangles */
    for( i = 0; i < faces->total; i++ )
    {
        /* extract the rectanlges only */
        CvRect face_rect = *(CvRect*)cvGetSeqElem( faces, i, 0 );
        cvRectangle( image, cvPoint(face_rect.x*scale,face_rect.y*scale),
                     cvPoint((face_rect.x+face_rect.width)*scale,
                             (face_rect.y+face_rect.height)*scale),
                     CV_RGB(255,0,0), 3 );
    }

    if( small_image != image )
        cvReleaseImage( &small_image );
    cvReleaseMemStorage( &storage );
}

/* takes image filename and cascade path from the command line */
int main( int argc, char** argv )
{
    IplImage* image;
    if( argc==3 && (image = cvLoadImage( argv[1], 1 )) != 0 )
    {
        CvHaarClassifierCascade* cascade = load_object_detector(argv[2]);
        detect_and_draw_objects( image, cascade, 1 );
        cvNamedWindow( "test", 0 );
        cvShowImage( "test", image );
        cvWaitKey(0);
        cvReleaseHaarClassifierCascade( &cascade );
        cvReleaseImage( &image );
    }

    return 0;
}

cvSetImagesForHaarClassifierCascade

爲隱藏的cascade(hidden cascade)指定圖像

void cvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* cascade,
                                          const CvArr* sum, const CvArr* sqsum,
                                          const CvArr* tilted_sum, double scale );
cascade
隱藏 Harr 分類器級聯 (Hidden Haar classifier cascade), 由函數 cvCreateHidHaarClassifierCascade生成
sum
32-比特,單通道圖像的積分圖像(Integral (sum) 單通道 image of 32-比特 integer format). 這幅圖像以及隨後的兩幅用於對快速特徵的評價和亮度/對比度的歸一化。 它們都可以利用函數 cvIntegral從8-比特或浮點數 單通道的輸入圖像中得到。
sqsum
單通道64比特圖像的平方和圖像
tilted_sum
單通道32比特整數格式的圖像的傾斜和(Tilted sum)
scale
cascade的窗口比例. 如果 scale=1, 就只用原始窗口尺寸檢測 (只檢測同樣尺寸大小的目標物體) - 原始窗口尺寸在函數cvLoadHaarClassifierCascade中定義 (在 "<default_face_cascade>"中缺省爲24x24), 如果scale=2, 使用的窗口是上面的兩倍 (在face cascade中缺省值是48x48 )。 這樣儘管可以將檢測速度提高四倍,但同時尺寸小於48x48的人臉將不能被檢測到。

函數 cvSetImagesForHaarClassifierCascade 爲hidden classifier cascade 指定圖像 and/or 窗口比例係數。 如果圖像指針爲空,會繼續使用原來的圖像(i.e. NULLs 意味這"不改變圖像")。比例係數沒有 "protection" 值,但是原來的值可以通過函數 cvGetHaarClassifierCascadeScale 重新得到並使用。這個函數用於對特定圖像中檢測特定目標尺寸的cascade分類器的設定。函數通過cvHaarDetectObjects進行內部調用,但當需要在更低一層的函數cvRunHaarClassifierCascade中使用的時候,用戶也可以自行調用。

cvRunHaarClassifierCascade

在給定位置的圖像中運行 cascade of boosted classifier

int cvRunHaarClassifierCascade( CvHaarClassifierCascade* cascade,
                                CvPoint pt, int start_stage=0 );
cascade
Haar 級聯分類器
pt
待檢測區域的左上角座標。待檢測區域大小爲原始窗口尺寸乘以當前設定的比例係數。當前窗口尺寸可以通過cvGetHaarClassifierCascadeWindowSize重新得到。
start_stage
級聯層的初始下標值(從0開始計數)。函數假定前面所有每層的分類器都已通過。這個特徵通過函數cvHaarDetectObjects內部調用,用於更好的處理器高速緩衝存儲器。

函數 cvRunHaarClassifierCascade 用於對單幅圖片的檢測。在函數調用前首先利用 cvSetImagesForHaarClassifierCascade設定積分圖和合適的比例係數 (=> 窗口尺寸)。當分析的矩形框全部通過級聯分類器每一層的時返回正值(這是一個候選目標),否則返回0或負值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章