Обучите машину опорных векторов распознавать черты лица на C ++

Опубликовано: 25 Июля, 2021

Давайте посмотрим, как обучить модель машины опорных векторов, сохранить обученную модель и протестировать модель, чтобы проверить процент точности ее предсказания с помощью OpenCV.

Организация данных:

Используя imagenetscraper и autocrop, мы собираем данные из Интернета, imagenetscraper autocrop Собранные данные должны быть осмысленно организованы, чтобы мы могли получить к ним программный и ручной доступ. Используйте приведенную ниже структуру папок -

 FFR_dataset /
| - Возраст
| | - взрослый
| | - ребенок
| | - старый
| | - подросток
| - Эмоции
| | - гнев
| | - презрение
| | - счастлив
| | - нейтральный
| | - грустно
| | - сюрприз
| - Пол
    | - женский
    | - самец

Мы используем одни и те же имена каталогов в коде для доступа к ним для обучения , сохранения и прогнозирования результатов распознавания. Для обучения моделей и получения хороших результатов прогнозирования требуется минимум 50 изображений в каждой папке. Обучение большего количества изображений может улучшить результаты, но не рекомендуется, так как это занимает много времени и не дает значительных улучшений.

Выполнение

Используя образец, предоставленный в официальном репозитории opencv для обучения SVM с помощью HOG, train_HOG.cpp, мы реализуем код C ++ для обучения, сохранения и прогнозирования черт лица на изображении с несколькими лицами.

Есть три типа функций: возраст , эмоции и пол . Четыре возрастных группы, шесть эмоций и два гендерных типа. Следовательно, реализован n- классификатор для распознавания каждой особенности в данных лица.

Шаг №1: Для каждого типа функции, т. Е. (Возраст, Эмоции или Пол) прокрутите "n" времен выполнения.




// CTrainTestHOG::Run(int run_times)
for ( auto ft : m_FeatureList) {
DEBUGLW( " Feature type=[%s] " , ft.first.c_str());
std::vector< float > predictionAccuracyList;
predictionAccuracyList.reserve(run_times);
for ( int run = 0; run < run_times; ++run) {
DEBUGLW( " Run=[%d] " , run);
vector<Mat> trainData, predData;
vector< int > trainLabels, predLabels;
this ->get_ft_dataset(ft.first, trainData, predData,
trainLabels, predLabels);
// ... train, predict and measure the SVM model.
}
}

Шаг № 2: В каждом прогоне перебирайте значения признаков в типе признаков и получайте изображения в вектор или массив, т.е. получите все изображения из папок Gender-> Male и Gender-> Female.




// CTrainTestHOG::get_ft_dataset()
std::set<cv::String>& featureValueList = m_FeatureList.find(ft)->second;
for ( auto fv : featureValueList) {
DEBUGLW( " Feature value=[%s] " , fv.c_str());
std::vector<cv::Mat> _trainData;
std::vector<cv::Mat> _predData;
std::vector< int > _trainLabels;
std::vector< int > _predLabels;
errCode = this ->get_ftfv_dataset(ft, fv, _trainData, _predData,
_trainLabels, _predLabels);
if (errCode != EXIT_SUCCESS)
break ;
trainData.insert(trainData.end(), _trainData.begin(), _trainData.end());
predData.insert(predData.end(), _predData.begin(), _predData.end());
trainLabels.insert(trainLabels.end(), _trainLabels.begin(), _trainLabels.end());
predLabels.insert(predLabels.end(), _predLabels.begin(), _predLabels.end());
}

Шаги с 3 по 6:

  • Обрежьте изображения в векторе до прямоугольников лиц и обновите вектор изображений, добавив в него список новых лиц.
  • Выполните любые задачи предварительной обработки, такие как изменение размера до меньшего размера (64, 64) для каждого изображения в списке лиц.
  • Перемешайте предварительно обработанные изображения лиц в векторе случайным образом, чтобы ввести случайные входные данные.
  • Разделите набор данных на обучающие (80%) и прогнозные (20%) данные.




// CTrainTestHOG::get_ftfv_dataset()
std::vector<cv::Mat> imgList;
this ->get_images(folderName, imgList);
this ->get_cropped_faces(imgList);
this ->get_preprocessed_faces(imgList);
//-- return on empty img list to prevent seg fault
if (imgList.empty()) {
errCode = EXIT_FAILURE;
DEBUGLE( "Error img list is empty! " );
break ;
}
DEBUGLD( " imgList.size()=[%ld] " , imgList.size());
std::random_shuffle(imgList.begin(), imgList.end());
// 80% for training
int trainPart = imgList.size() * 0.8;
// 20% for predicting
int predPart = imgList.size() - trainPart;
DEBUGLD( " trainPart=[%d], predPart=[%d] " , trainPart, predPart);
trainData.reserve(trainPart);
predData.reserve(predPart);
ft_t::iterator ft_iter = m_FeatureList.find(ft);
fv_t::iterator fv_iter = ft_iter->second.find(fv);
int label = std::distance(ft_iter->second.begin(), fv_iter);
DEBUGLD( " label=[%d] " , label);
int i = 0;
for (; i < trainPart; ++i) {
trainData.push_back(imgList.at(i));
trainLabels.push_back(label);
}
DEBUGLD(" i=[%d], trainData.size()=[%ld],
trainLabels.size()
= [% ld] ", i, trainData.size(),
trainLabels.size());
for (; i < imgList.size(); ++i) {
predData.push_back(imgList.at(i));
predLabels.push_back(label);
}
DEBUGLD(" i=[%d], predData.size()=[%ld],
predLabels.size()
= [% ld] ", i, predData.size(), predLabels.size());

Шаг № 7: Вычислить HOG для каждого изображения в обучающих данных.




// CTrainTestHOG::computeHOGs()
HOGDescriptor hog;
vector<Mat> hogMats;
vector< float > descriptors;
for ( auto img : imgHogList) {
hog.winSize = img.size() / 8 * 8;
hog.compute(img, descriptors);
cv::Mat descriptors_mat(Mat(descriptors).clone());
hogMats.push_back(descriptors_mat);
}
imgHogList.swap(hogMats);

Шаг № 8: Преобразуйте вектор обучающих данных в объект OpenCV Mat для обучения SVM.




// CTrainTestHOG::convert_to_ml()
for ( size_t i = 0; i < train_samples.size(); ++i) {
CV_Assert(train_samples[i].cols == 1 || train_samples[i].rows == 1);
if (train_samples[i].cols == 1) {
cv::transpose(train_samples[i], tmp);
tmp.copyTo(trainData.row(( int )i));
}
else if (train_samples[i].rows == 1) {
train_samples[i].copyTo(trainData.row(( int )i));
}
}

Шаг № 9: Передайте объект Mat обучающих данных в функцию svm train вместе с вектором меток для обучающих данных.




// CTrainTestHOG::Run()
trainLabels.resize(ml_train_data.rows);
// train svm
DEBUGLW( " Training SVM - begin " );
m_pSVM->train(ml_train_data, ROW_SAMPLE, trainLabels);
DEBUGLW( " Training SVM - end " );

Шаг № 10: Сохраните обученную модель.




//-- step 10, CTrainTestHOG::Run()
cv::String svmModelFileName = cv::format( "%s/cv4_svm_%s_model.xml" ,
getenv (FFR_DATASET_PATH),
ft.first.c_str());
m_pSVM->save(svmModelFileName.c_str());
DEBUGLW( " Saved SVM model=[%s] " ,
svmModelFileName.c_str());

Шаг № 11: Прогнозируйте модель, вычисляя HOG для каждого изображения прогноза, преобразуйте набор данных прогноза в объект mat opencv и вызовите svm predic с вектором меток для сохранения результата.




//-- step 11, CTrainTestHOG::Run()
// test the model
// compute HOG for each pre-processed face
errCode = this->computeHOGs(predData);
if (errCode != EXIT_SUCCESS) {
    DEBUGLE("Error in computing HOGs for the feature "
            "type=[%s] ",
            ft.first.c_str());
    break;
}
  
// convert HOG feature vectors to SVM data
Mat ml_pred_data;
vector<int> resultLabels;
errCode = this->convert_to_ml(predData, ml_pred_data);
if (errCode != EXIT_SUCCESS) {
    DEBUGLE("Error in converting to ml for the "
            "feature type=[%s] ",
            ft.first.c_str());
    break;
}
predLabels.resize(ml_pred_data.rows);
// resultLabels.resize(ml_pred_data.rows);
// test svm
DEBUGLW(" Testing SVM - begin ");
Mat responses_mat;
m_pSVM->predict(ml_pred_data, responses_mat);
for (size_t i = 0; i < ml_pred_data.rows; ++i) {
    resultLabels.push_back(responses_mat.at<int>(i));
}
DEBUGLW(" Testing SVM - end ");

Шаг № 12 и № 13: Рассчитайте процент его точности, сравнивая ожидаемые метки предсказания с предсказанными метками.




// CTrainTestHOG::Run()
// check the accuracy
float accuracy = 0.0f;
this ->get_prediction_accuracy(predLabels, resultLabels, accuracy);
DEBUGLW( " Prediction accuracy=[%lf] " , accuracy);
predictionAccuracyList.push_back(accuracy);
//-- step 13, CTrainTestHOG::Run()
// check the mean accuracy of 'n' runs
float sum_of_accuracies = std::accumulate(
predictionAccuracyList.begin(),
predictionAccuracyList.end(), 0.0);
float mean_accuracy = sum_of_accuracies / predictionAccuracyList.size();
DEBUGLW( " Mean prediction accuracy=[%lf] " ,
mean_accuracy);

Запустите исполняемый файл с указанными ниже аргументами командной строки.

 ./train_hog --test --in = --out = --показывать

Вход:

Выход:

Журнал результатов для HOG SVM с использованием OpenCV 2.4
Журнал результатов для HOG SVM с использованием OpenCV 4.0

Примечание. Из-за длинных волос у всех трех человек на изображении пол определяется как «женский», что является ложным срабатыванием. В алгоритмах машинного обучения ложные срабатывания всегда являются обычным явлением, поскольку входной образец изображения имеет неоднозначные характеристики.