OpenCV 臉部偵測自學(7)

來源:互聯網
上載者:User

目前需要提煉下ml部分的介面。目的是以後方便選擇用哪種分類器。還是一頭霧水啊。。。學到哪先記錄到哪。

一。以CvSVM為例。下面是CvSVM類的定義:

class CV_EXPORTS_W CvSVM : public CvStatModel{public:    // SVM type    enum { C_SVC=100, NU_SVC=101, ONE_CLASS=102, EPS_SVR=103, NU_SVR=104 };    // SVM kernel type    enum { LINEAR=0, POLY=1, RBF=2, SIGMOID=3 };    // SVM params type    enum { C=0, GAMMA=1, P=2, NU=3, COEF=4, DEGREE=5 };    CV_WRAP CvSVM();    virtual ~CvSVM();    CvSVM( const CvMat* trainData, const CvMat* responses,           const CvMat* varIdx=0, const CvMat* sampleIdx=0,           CvSVMParams params=CvSVMParams() );    virtual bool train( const CvMat* trainData, const CvMat* responses,                        const CvMat* varIdx=0, const CvMat* sampleIdx=0,//這兩個參數好像不太用                        CvSVMParams params=CvSVMParams() );    virtual float predict( const CvMat* sample, bool returnDFVal=false ) const;//    virtual float predict( const CvMat* samples, CV_OUT CvMat* results ) const;    CV_WRAP virtual int get_support_vector_count() const;    virtual const float* get_support_vector(int i) const;    virtual CvSVMParams get_params() const { return params; };    CV_WRAP virtual void clear();    static CvParamGrid get_default_grid( int param_id );    virtual void write( CvFileStorage* storage, const char* name ) const;    virtual void read( CvFileStorage* storage, CvFileNode* node );    CV_WRAP int get_var_count() const { return var_idx ? var_idx->cols : var_all; }protected:    virtual bool set_params( const CvSVMParams& params );    virtual bool train1( int sample_count, int var_count, const float** samples,                    const void* responses, double Cp, double Cn,                    CvMemStorage* _storage, double* alpha, double& rho );    virtual bool do_train( int svm_type, int sample_count, int var_count, const float** samples,                    const CvMat* responses, CvMemStorage* _storage, double* alpha );    virtual void create_kernel();    virtual void create_solver();    virtual float predict( const float* row_sample, int row_len, bool returnDFVal=false ) const;    virtual void write_params( CvFileStorage* fs ) const;    virtual void read_params( CvFileStorage* fs, CvFileNode* node );    CvSVMParams params;    CvMat* class_labels;    int var_all;    float** sv;    int sv_total;    CvMat* var_idx;    CvMat* class_weights;    CvSVMDecisionFunc* decision_func;    CvMemStorage* storage;    CvSVMSolver* solver;    CvSVMKernel* kernel;};

SVM的介面基本上跟大部分分類器的差不多。train函數參數裡一個是train_data,一個是response,最後一個是SVM對應的參數結構體。predict的參數就是一個1 x N的樣本特徵向量。下面是OpenCV提供的一個調用例子。

#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/ml/ml.hpp>using namespace cv;int main(){// Data for visual representationint width = 512, height = 512;Mat image = Mat::zeros(height, width, CV_8UC3);// Set up training datafloat labels[4] = {1.0, -1.0, -1.0, -1.0};Mat labelsMat(4, 1, CV_32FC1, labels);//對應於介面的_responsefloat trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };Mat trainingDataMat(4, 2, CV_32FC1, trainingData);//對應於介面的_train_data// Set up SVM's parametersCvSVMParams params;params.svm_type    = CvSVM::C_SVC;params.kernel_type = CvSVM::LINEAR;params.term_crit   = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);// Train the SVMCvSVM SVM;SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);Vec3b green(0,255,0), blue (255,0,0);// Show the decision regions given by the SVMfor (int i = 0; i < image.rows; ++i)for (int j = 0; j < image.cols; ++j){Mat sampleMat = (Mat_<float>(1,2) << i,j);float response = SVM.predict(sampleMat);if (response == 1)image.at<Vec3b>(j, i)  = green;else if (response == -1)image.at<Vec3b>(j, i)  = blue;}// Show the training dataint thickness = -1;int lineType = 8;circle( image, Point(501,  10), 5, Scalar(  0,   0,   0), thickness, lineType);circle( image, Point(255,  10), 5, Scalar(255, 255, 255), thickness, lineType);circle( image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType);circle( image, Point( 10, 501), 5, Scalar(255, 255, 255), thickness, lineType);// Show support vectorsthickness = 2;lineType  = 8;int c     = SVM.get_support_vector_count();for (int i = 0; i < c; ++i){const float* v = SVM.get_support_vector(i);circle( image,  Point( (int) v[0], (int) v[1]),   6,  Scalar(128, 128, 128), thickness, lineType);}imwrite("result.png", image);        // save the imageimshow("SVM Simple Example", image); // show it to the userwaitKey(0);}

                           
二。以cascadeclassifier為例說下它如何跟ml.hpp的關係。這個關係有點複雜,不像SVM那麼標準了。
在traincascade\boost.cpp中

bool CvCascadeBoost::train( const CvFeatureEvaluator* _featureEvaluator,//包含了sum,tilted,特徵的位置等資訊                           int _numSamples,                           int _precalcValBufSize, int _precalcIdxBufSize,                           const CvCascadeBoostParams& _params )

這個是訓練一個強分類器的介面,裡面調用訓練一個弱分類器的介面是:ml\ml.hpp

boolCvBoostTree::train( CvDTreeTrainData* _train_data,                    const CvMat* _subsample_idx, CvBoost* _ensemble )

可是從ml.hpp檔案中可以看到大部分從cvStatModel裡面繼承來的分類器的訓練函數的結構應該是:

virtual bool train( const CvMat* train_data, [int tflag,] ..., const CvMat* responses, ...,    [const CvMat* var_idx,] ..., [const CvMat* sample_idx,] ...    [const CvMat* var_type,] ..., [const CvMat* missing_mask,] <misc_training_alg_params> ... )=0;

用括弧括起來的是可選的參數,但是train_data的意思是一行是一個樣本的所有特徵(好像這麼一行都叫特徵向量。。。),行數是樣本的數目。responses是響應值的矩陣,應該是一個n x 1的矩陣。
而在我們的例子裡這兩個參數都跑到CvDTreeTrainData* _train_data這裡面去了。

1. 

featureEvaluator->init( (CvFeatureParams*)featureParams, numPos + numNeg, cascadeParams.winSize );

在CvCascadeBoost初始化_featureEvaluator的時候就已經根據選擇的特徵類型,正樣本的大小把所有樣本的積分圖空間申請了。還有就是在這個初始化的時候也把對應的responses申請了。
2. 

bool CvCascadeClassifier::updateTrainingSet( double& acceptanceRatio)//featureEvaluator->setImage( img, isPositive ? 1 : 0, i );

在這把積分圖和response都計算出來。
3. TrainCascade\boost.cpp

data = new CvCascadeBoostTrainData( _featureEvaluator, _numSamples,                                        _precalcValBufSize, _precalcIdxBufSize, _params );

在這裡計算所有的樣本的特徵值。這樣上面1.2.步驟中的featureEvaluator的資訊也都在data中了,所以data直接送到CvBoostTree::train的介面中去了:

CvCascadeBoostTree* tree = new CvCascadeBoostTree;        if( !tree->train( data, subsample_mask, this ) )//應該是訓練一個弱分類器tree        {            delete tree;            break;        }        cvSeqPush( weak, &tree );//把弱分類器添加到強分類器裡面

所以我們要封裝train的時候需要把從父類vfr_machine_learning_package的介面的_train_data和response給處理下成CvDTreeTrainData的data,然後才能調用if( !tree->train( data, subsample_mask, this ) )

                           

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.