c++ - Clasificador SVM basado en características HOG para "detección de objetos" en OpenCV
object-recognition training-data (3)
He estado lidiando con el mismo problema y sorprendido por la falta de algunas soluciones limpias de C ++. He creado ~> este envoltorio de SVMLight <~ , que es una biblioteca estática que proporciona las clases SVMTrainer
y SVMClassifier
que simplifican la capacitación a algo como:
// we are going to use HOG to obtain feature vectors:
HOGDescriptor hog;
hog.winSize = Size(32,48);
// and feed SVM with them:
SVMLight::SVMTrainer svm("features.dat");
luego para cada muestra de entrenamiento:
// obtain feature vector describing sample image:
vector<float> featureVector;
hog.compute(img, featureVector, Size(8, 8), Size(0, 0));
// and write feature vector to the file:
svm.writeFeatureVectorToFile(featureVector, true); // true = positive sample
hasta que el archivo features.dat
contenga vectores de características para todas las muestras y al final solo llame:
std::string modelName("classifier.dat");
svm.trainAndSaveModel(modelName);
Una vez que tenga un archivo con modelo (o features.dat
que puede entrenar al clasificador):
SVMLight::SVMClassifier c(classifierModelName);
vector<float> descriptorVector = c.getDescriptorVector();
hog.setSVMDetector(descriptorVector);
...
vector<Rect> found;
Size padding(Size(0, 0));
Size winStride(Size(8, 8));
hog.detectMultiScale(segment, found, 0.0, winStride, padding, 1.01, 0.1);
simplemente consulte la documentación de HOGDescriptor para obtener más información :)
Tengo un proyecto, que quiero detectar objetos en las imágenes; mi objetivo es usar las características de HOG. Al utilizar la implementación OpenCV SVM, pude encontrar el código para detectar personas, y leí algunos artículos sobre cómo ajustar los parámetros para detectar objetos en lugar de personas. Lamentablemente, no pude hacer eso por algunas razones; en primer lugar, probablemente estoy ajustando los parámetros de forma incorrecta, en segundo lugar, no soy un buen programador en C ++, pero tengo que hacerlo con C ++ / OpenCV ... here puede encontrar el código para detectar las características de HOG para las personas usando C ++ / OpenCV.
Digamos que quiero detectar el objeto en esta image . Ahora, le mostraré lo que he tratado de cambiar en el código, pero no funcionó conmigo.
El código que traté de cambiar:
HOGDescriptor hog;
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
Traté de cambiar getDefaultPeopleDetector()
con los siguientes parámetros, pero no funcionó:
(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9, 0,-1, 0, 0.2, true, cv::HOGDescriptor::DEFAULT_NLEVELS)
Luego intenté hacer un vector, pero cuando quise imprimir los resultados, parece estar vacío.
vector<float> detector;
HOGDescriptor hog(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9, 0,-1, 0, 0.2, true, cv::HOGDescriptor::DEFAULT_NLEVELS);
hog.setSVMDetector(detector);
Por favor, necesito ayuda para resolver este problema.
He hecho cosas similares a las tuyas: recolectar muestras de imágenes positivas y negativas usando HOG para extraer las características del automóvil, entrenar el conjunto de características usando SVM lineal (uso la luz SVM), luego usar el modelo para detectar automóviles usando la función HOG multidetect.
Recibo muchos falsos positivos, luego vuelvo a entrenar los datos usando muestras positivas y falsas positivas + muestras negativas. El modelo resultante se prueba nuevamente. La detección resultante mejora (menos falsos positivos) pero el resultado no es satisfactorio (promedio de 50% de índice de aciertos y 50% de falsos positivos). Ajustar los parámetros multidetectos mejora el resultado pero no mucho (10% menos de falsos positivos y aumenta la tasa de aciertos).
Editar Puedo compartir el código fuente si lo desea, y estoy abierto a la discusión, ya que no he obtenido resultados satisfactorios con HOG. De todos modos, creo que el código puede ser un buen punto de partida sobre el uso de HOG para el entrenamiento y la detección
Editar: agregar código
static void calculateFeaturesFromInput(const string& imageFilename, vector<float>& featureVector, HOGDescriptor& hog)
{
Mat imageData = imread(imageFilename, 1);
if (imageData.empty()) {
featureVector.clear();
printf("Error: HOG image ''%s'' is empty, features calculation skipped!/n", imageFilename.c_str());
return;
}
// Check for mismatching dimensions
if (imageData.cols != hog.winSize.width || imageData.rows != hog.winSize.height) {
featureVector.clear();
printf("Error: Image ''%s'' dimensions (%u x %u) do not match HOG window size (%u x %u)!/n", imageFilename.c_str(), imageData.cols, imageData.rows, hog.winSize.width, hog.winSize.height);
return;
}
vector<Point> locations;
hog.compute(imageData, featureVector, winStride, trainingPadding, locations);
imageData.release(); // Release the image again after features are extracted
}
...
int main(int argc, char** argv) {
// <editor-fold defaultstate="collapsed" desc="Init">
HOGDescriptor hog; // Use standard parameters here
hog.winSize.height = 128;
hog.winSize.width = 64;
// Get the files to train from somewhere
static vector<string> tesImages;
static vector<string> positiveTrainingImages;
static vector<string> negativeTrainingImages;
static vector<string> validExtensions;
validExtensions.push_back("jpg");
validExtensions.push_back("png");
validExtensions.push_back("ppm");
validExtensions.push_back("pgm");
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Read image files">
getFilesInDirectory(posSamplesDir, positiveTrainingImages, validExtensions);
getFilesInDirectory(negSamplesDir, negativeTrainingImages, validExtensions);
/// Retrieve the descriptor vectors from the samples
unsigned long overallSamples = positiveTrainingImages.size() + negativeTrainingImages.size();
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Calculate HOG features and save to file">
// Make sure there are actually samples to train
if (overallSamples == 0) {
printf("No training sample files found, nothing to do!/n");
return EXIT_SUCCESS;
}
/// @WARNING: This is really important, some libraries (e.g. ROS) seems to set the system locale which takes decimal commata instead of points which causes the file input parsing to fail
setlocale(LC_ALL, "C"); // Do not use the system locale
setlocale(LC_NUMERIC,"C");
setlocale(LC_ALL, "POSIX");
printf("Reading files, generating HOG features and save them to file ''%s'':/n", featuresFile.c_str());
float percent;
/**
* Save the calculated descriptor vectors to a file in a format that can be used by SVMlight for training
* @NOTE: If you split these steps into separate steps:
* 1. calculating features into memory (e.g. into a cv::Mat or vector< vector<float> >),
* 2. saving features to file / directly inject from memory to machine learning algorithm,
* the program may consume a considerable amount of main memory
*/
fstream File;
File.open(featuresFile.c_str(), ios::out);
if (File.good() && File.is_open()) {
File << "# Use this file to train, e.g. SVMlight by issuing $ svm_learn -i 1 -a weights.txt " << featuresFile.c_str() << endl; // Remove this line for libsvm which does not support comments
// Iterate over sample images
for (unsigned long currentFile = 0; currentFile < overallSamples; ++currentFile) {
storeCursor();
vector<float> featureVector;
// Get positive or negative sample image file path
const string currentImageFile = (currentFile < positiveTrainingImages.size() ? positiveTrainingImages.at(currentFile) : negativeTrainingImages.at(currentFile - positiveTrainingImages.size()));
// Output progress
if ( (currentFile+1) % 10 == 0 || (currentFile+1) == overallSamples ) {
percent = ((currentFile+1) * 100 / overallSamples);
printf("%5lu (%3.0f%%):/tFile ''%s''", (currentFile+1), percent, currentImageFile.c_str());
fflush(stdout);
resetCursor();
}
// Calculate feature vector from current image file
calculateFeaturesFromInput(currentImageFile, featureVector, hog);
if (!featureVector.empty()) {
/* Put positive or negative sample class to file,
* true=positive, false=negative,
* and convert positive class to +1 and negative class to -1 for SVMlight
*/
File << ((currentFile < positiveTrainingImages.size()) ? "+1" : "-1");
// Save feature vector components
for (unsigned int feature = 0; feature < featureVector.size(); ++feature) {
File << " " << (feature + 1) << ":" << featureVector.at(feature);
}
File << endl;
}
}
printf("/n");
File.flush();
File.close();
} else {
printf("Error opening file ''%s''!/n", featuresFile.c_str());
return EXIT_FAILURE;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Pass features to machine learning algorithm">
/// Read in and train the calculated feature vectors
printf("Calling SVMlight/n");
SVMlight::getInstance()->read_problem(const_cast<char*> (featuresFile.c_str()));
SVMlight::getInstance()->train(); // Call the core libsvm training procedure
printf("Training done, saving model file!/n");
SVMlight::getInstance()->saveModelToFile(svmModelFile);
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Generate single detecting feature vector from calculated SVM support vectors and SVM model">
printf("Generating representative single HOG feature vector using svmlight!/n");
vector<float> descriptorVector;
vector<unsigned int> descriptorVectorIndices;
// Generate a single detecting feature vector (v1 | b) from the trained support vectors, for use e.g. with the HOG algorithm
SVMlight::getInstance()->getSingleDetectingVector(descriptorVector, descriptorVectorIndices);
// And save the precious to file system
saveDescriptorVectorToFile(descriptorVector, descriptorVectorIndices, descriptorVectorFile);
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Test detecting vector">
cout << "Test Detecting Vector" << endl;
hog.setSVMDetector(descriptorVector); // Set our custom detecting vector
cout << "descriptorVector size: " << sizeof(descriptorVector) << endl;
getFilesInDirectory(tesSamplesDir, tesImages, validExtensions);
namedWindow("Test Detector", 1);
for( size_t it = 0; it < tesImages.size(); it++ )
{
cout << "Process image " << tesImages[it] << endl;
Mat image = imread( tesImages[it], 1 );
detectAndDrawObjects(image, hog);
for(;;)
{
int c = waitKey();
if( (char)c == ''n'')
break;
else if( (char)c == ''/x1b'' )
exit(0);
}
}
// </editor-fold>
return EXIT_SUCCESS;
}
Para detectar objetos arbitrarios con el uso de las descripciones HOG de opencv y el clasificador SVM, primero debe entrenar al clasificador. Jugar con los parámetros no ayudará aquí, lo siento :(.
En términos generales, deberá completar los siguientes pasos:
Paso 1) Prepare algunas imágenes de entrenamiento de los objetos que desea detectar (muestras positivas). También deberá preparar algunas imágenes sin objetos de interés (muestras negativas).
Paso 2) Detecte las características HOG de la muestra de entrenamiento y use estas características para entrenar un clasificador SVM (también provisto en OpenCV).
Paso 3) Usa los coeficientes del clasificador SVM entrenado en el método HOGDescriptor :: setSVMDetector ().
Solo entonces, puede usar el código de ejemplo peopledetector.cpp para detectar los objetos que desea detectar.