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.

20
demandé sur LihO 2012-05-27 00:27:00

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.

35
répondu Hakan Serce 2014-01-27 12:40:09

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 :)

9
répondu LihO 2014-01-12 01:34:33

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;
}
7
répondu bonchenko 2013-04-25 12:50:22