2013-04-08 2 views
2

Я создаю приложение для классификации людей в изображениях городской среды.openCV C++: Проблемы с CvBoost (класс Adaboost)

Я дрессировать classifer в следующем порядке:

int main (int argc, char **argv) 
{ 

/* STEP 2. Opening the file */ 
//1. Declare a structure to keep the data 
    CvMLData cvml; 
//2. Read the file 
    cvml.read_csv ("directory/train_rand.csv"); 
//3. Indicate which column is the response 
    cvml.set_response_idx (0); 

/* STEP 3. Splitting the samples */ 
//1. Select 4000 for the training 
    CvTrainTestSplit cvtts (4000, true); 
//2. Assign the division to the data 
    cvml.set_train_test_split (&cvtts); 

    printf ("Training ... "); 
/* STEP 4. The training */ 
//1. Declare the classifier 
    CvBoost boost; 
//2. Train it with 100 features 
    boost.train (&cvml, CvBoostParams (CvBoost::REAL,100, 0, 1, false, 0), 
      false); 

/* STEP 5. Calculating the testing and training error */ 
// 1. Declare a couple of vectors to save the predictions of each sample 
    std::vector<float> train_responses, test_responses; 
// 2. Calculate the training error 
    float fl1 = boost.calc_error (&cvml, CV_TRAIN_ERROR, &train_responses); 
// 3. Calculate the test error 
    float fl2 = boost.calc_error (&cvml, CV_TEST_ERROR, &test_responses); 

    cout<<"Error train: "<<fl1<<endl; 

    cout<<"Error test: "<<fl2<<endl; 

/* STEP 6. Save your classifier */ 
// Save the trained classifier 
    boost.save ("./trained_boost_4000samples-100ftrs.xml", "boost"); 

    return 0; 
} 

train_rand.csv файл, где первый столбец категория. Остальные столбцы станут чертами проблемы. Например, я мог бы использовать три функции. Каждый из них представляет среднее значение красного, синего и зеленого на пиксель в изображении. Поэтому мой файл csv должен выглядеть так. Обратите внимание, что в первом столбце я использую символ, поэтому OpenCV распознает это как категорию.

B,124.34,45.4,12.4 
B,64.14,45.23,3.23 
B,42.32,125.41,23.8 
R,224.4,35.34,163.87 
R,14.55,12.423,89.67 
... 

Для моей реальной проблемы я использую 100 функций и 8000 образцов. Я тренирую классификатор с половиной данных и тестирую с остальными.

После тренировки я получаю тестовую ошибку около 5% (что довольно хорошо для всего лишь 100 функций).

Теперь я хочу использовать классификатор в новых данных:

CvBoost boost 

boost.load("directory/trained_boost_4000samples-100ftrs.xml"); 

float x = boost.predict(SampleData,Mat(),Range::all(),false,false); 
cout<<x; 

Я бегу этот код на тысячи образцов и всегда выдает то же самое значение, которое 2. я действительно не» я понимаю, что я делаю неправильно здесь, но даже если бы я обучал классификатору неправильным образом, он не классифицировал бы 100% времени таким же образом, также, ошибка теста, которую я вычислил до того, как показывает, что классификатор должен работать хорошо.

Одна вещь, которая меня беспокоит, заключается в том, что SampleData должен иметь такое же количество столбцов, что и образец, который я использовал для обучения. Дело в том, что данные, используемые для обучения, имеют 100 столбцов + 1 ответ, и если я попытаюсь запустить классификатор всего за 100 функций, он выдает исключение, говорящее, что размеры не совпадают. Если я запускаю классификатор с 101 функциями (что абсолютно произвольно), он работает, но результаты не имеют никакого смысла.

Может ли кто-нибудь помочь мне с этим? Заранее спасибо!

С уважением

+0

Я не мог найти какой-либо документации о формате обучающих данных. Вы уверены, что первый столбец - это метка, также примеры, которые я видел, используют реальные значения в качестве ярлыков, можете ли вы сопоставить 'B' /' R' с '-1.0' /' 1.0'? – Robert

ответ

2

мне удалось получить AdaBoost работает путем адаптации code from the SVM documentation. Единственным трюком было обеспечение достаточного количества данных выборки (> = 11).

От the blog where your code is copied from:

ПРИМЕЧАНИЕ: Для очень странной причине реализация OpenCV не работает с менее чем 11 образцов.

// Training data 
float labels[11] = { 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}; 
Mat labelsMat(11, 1, CV_32FC1, labels); 

float trainingData[11][2] = { 
    {501, 10}, {508, 15}, 
    {255, 10}, {501, 255}, {10, 501}, {10, 501}, {11, 501}, {9, 501}, {10, 502}, {10, 511}, {10, 495} }; 
Mat trainingDataMat(11, 2, CV_32FC1, trainingData); 

// Set up SVM's parameters 
CvSVMParams params; 
params.svm_type = CvSVM::C_SVC; 
params.kernel_type = CvSVM::LINEAR; 
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6); 

// Train a SVM classifier 
CvSVM SVM; 
SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params); 

// Train a boost classifier 
CvBoost boost; 
boost.train(trainingDataMat, 
      CV_ROW_SAMPLE, 
      labelsMat); 

// Test the classifiers 
Mat testSample1 = (Mat_<float>(1,2) << 251, 5); 
Mat testSample2 = (Mat_<float>(1,2) << 502, 11); 

float svmResponse1 = SVM.predict(testSample1); 
float svmResponse2 = SVM.predict(testSample2); 

float boostResponse1 = boost.predict(testSample1); 
float boostResponse2 = boost.predict(testSample2); 

std::cout << "SVM: " << svmResponse1 << " " << svmResponse2 << std::endl; 
std::cout << "BOOST: " << boostResponse1 << " " << boostResponse2 << std::endl; 

// Output: 
// > SVM: -1 1 
// > BOOST: -1 1