J'ai un projet, que je veux détecter des objets dans les images; mon objectif est d'utiliser les fonctionnalités HOG. En utilisant l'implémentation OpenCV SVM, j'ai pu trouver le code pour détecter les personnes, et j'ai lu quelques articles sur le réglage des paramètres afin de détecter un objet au lieu de personnes. Malheureusement, je n'ai pas pu le faire pour plusieurs raisons; tout d'abord, je suis probablement en train de régler les paramètres incorrectement, deuxièmement, je ne suis pas un bon programmeur en C++ mais je dois le faire avec C++/OpenCV ... ici vous pouvez trouver le code pour détecter les fonctionnalités HOG pour les personnes à l'aide de C++/OpenCV.
Disons que je veux détecter l'objet dans ce image . Maintenant, je vais vous montrer ce que j'ai essayé de changer dans le code, mais cela n'a pas fonctionné avec moi.
Le code que j'ai essayé de changer:
HOGDescriptor hog;
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
J'ai essayé de modifier getDefaultPeopleDetector()
avec les paramètres suivants, mais cela n'a pas fonctionné:
(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9, 0,-1, 0, 0.2, true, cv::HOGDescriptor::DEFAULT_NLEVELS)
J'ai ensuite essayé de faire un vecteur, mais quand j'ai voulu imprimer les résultats, il semble être vide.
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);
S'il vous plaît, j'ai besoin d'aide pour résoudre ce problème.
Afin de détecter des objets arbitraires à l'aide des descripteurs HOG opencv et du classificateur SVM, vous devez d'abord former le classificateur. Jouer avec les paramètres n'aidera pas ici, désolé :(.
En termes généraux, vous devrez effectuer les étapes suivantes:
Étape 1) Préparez des images d'apprentissage des objets que vous souhaitez détecter (échantillons positifs). Vous devrez également préparer des images sans objets d'intérêt (échantillons négatifs).
Étape 2) Détectez les fonctionnalités HOG de l'exemple de formation et utilisez ces fonctionnalités pour former un classificateur SVM (également fourni dans OpenCV).
Étape 3) Utilisez les coefficients du classificateur SVM formé dans la méthode HOGDescriptor :: setSVMDetector ().
Ce n'est qu'alors que vous pouvez utiliser l'exemple de code peopledetector.cpp pour détecter les objets que vous souhaitez détecter.
J'ai été confronté au même problème et surpris par le manque de solutions C++ propres que j'ai créées ~> ce wrapper de SVMLight <~, qui est une bibliothèque statique qui fournit des classes SVMTrainer
et SVMClassifier
qui simplifient la formation à quelque chose comme:
// 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");
puis pour chaque échantillon de formation:
// 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
jusqu'au features.dat
le fichier contient des vecteurs de fonctionnalités pour tous les échantillons et à la fin vous appelez simplement:
std::string modelName("classifier.dat");
svm.trainAndSaveModel(modelName);
Une fois que vous avez un fichier avec le modèle (ou features.dat
avec lequel vous pouvez simplement former le classificateur):
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);
il suffit de vérifier la documentation de HOGDescriptor pour plus d'informations :)
J'ai fait des choses similaires à vous: collecter des échantillons d'images positives et négatives à l'aide de HOG pour extraire les caractéristiques de la voiture, former l'ensemble de fonctionnalités à l'aide de SVM linéaire (j'utilise la lumière SVM), puis utiliser le modèle pour détecter la voiture à l'aide de la fonction multidétecter HOG.
J'obtiens beaucoup de faux positifs, puis je recycle les données en utilisant des échantillons positifs et des échantillons faux positifs + négatifs. Le modèle résultant est ensuite testé à nouveau. La détection résultante s'améliore (moins de faux positifs) mais le résultat n'est pas satisfaisant (taux de réussite moyen de 50% et 50% de faux positifs). Le réglage des paramètres multidétecteurs améliore le résultat mais pas beaucoup (10% de faux positifs en moins et augmentation du taux de réussite).
Edit Je peux vous partager le code source si vous le souhaitez, et je suis très ouvert à la discussion car je n'ai pas obtenu de résultats satisfaisants en utilisant HOG. Quoi qu'il en soit, je pense que le code peut être un bon point de départ pour utiliser HOG pour la formation et la détection
Modifier: ajouter du code
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;
}