Classificateur SVM basé sur les caractéristiques HOG pour "détection d'objet" dans OpenCV
j'ai un projet, je veux détecter des objets dans les images; mon but est d'utiliser PORC fonctionnalités. En utilisant L'implémentation SVM D'OpenCV, j'ai pu trouver le code pour détecter les gens, et j'ai lu des articles sur le réglage des paramètres afin de détecter les objets plutôt que les gens. Malheureusement, je n'ai pas pu le faire pour quelques raisons; tout d'abord, je ne suis probablement pas un bon programmeur en C++, mais je dois le faire avec C++/OpenCV... ici vous pouvez trouver le code pour détecter les traits de porc pour les personnes en utilisant 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 il ne fonctionne pas avec moi.
Le code que j'ai essayé de changer:
HOGDescriptor hog;
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
j'ai essayé de changer getDefaultPeopleDetector()
avec les paramètres suivants, mais il ne fonctionne pas:
(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 lorsque 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 de l'aide pour résoudre ce problème.
3 réponses
pour détecter les objets arbitraires avec les descripteurs de porcs opencv et le 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 suivre les étapes suivantes:
Étape 1) Préparez quelques images d'entraînement des objets que vous voulez détecter (échantillons positifs). Aussi, vous aurez besoin de préparer quelques images sans objets d'intérêt (négatif échantillon.)
Étape 2) détecter les caractéristiques de L'échantillon de formation et utiliser ces caractéristiques 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 peopledetector.rpc exemple de code pour détecter les objets à détecter.
j'ai été confronté au même problème et surpris par le manque de solutions propres C++ que j'ai créé ~> 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 pour tous les échantillons et à la fin vous avez juste appel:
std::string modelName("classifier.dat");
svm.trainAndSaveModel(modelName);
une fois que vous avez un fichier avec model (ou features.dat
cela il vous suffit de 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'info :)
j'ai fait des choses semblables à ce que vous avez fait: recueillir des échantillons d'images positives et négatives à L'aide de HOG pour extraire les caractéristiques de la voiture, former le jeu de caractéristiques à l'aide de SVM linéaire (j'utilise SVM light), puis utiliser le modèle pour détecter la voiture à l'aide de la fonction multitect de HOG.
j'obtiens beaucoup de faux positifs, puis je retreins les données en utilisant des échantillons positifs et des 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 la le résultat n'est pas satisfaisant (taux de réponse moyen de 50% et faux positifs de 50%). L'ajustement des paramètres multidetect améliore le résultat mais pas grand chose (10% de faux positifs en moins et augmentation du taux de succès).
Modifier Je peux vous partager le code source si vous le souhaitez, et je suis très ouvert à la discussion car je n'ai pas de résultats satisfaisants avec HOG. Quoi qu'il en soit, je pense que le code peut être un bon point de départ sur L'utilisation de HOG pour la formation et la détection
modifier: ajouter 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;
}