SVM classifier based on HOG features for “object detection” in OpenCV

前端 未结 3 1660
眼角桃花
眼角桃花 2020-12-02 06:13

I have a project, which I want to detect objects in the images; my aim is to use HOG features. By using OpenCV SVM implementation , I could find the code for detecting peop

3条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-02 06:45

    I have done similar things as you did: collect samples of positive and negative images using HOG to extract features of car, train the feature set using linear SVM (I use SVM light), then use the model to detect car using HOG multidetect function.

    I get lot of false positives, then I retrain the data using positive samples and false positive+negative samples. The resulting model is then tested again. The resulting detection improves (less false positives) but the result is not satisfying (average 50% hit rate and 50% false positives). Tuning up multidetect parameters improve the result but not much (10% less false positives and increase in hit rate).

    Edit I can share you the source code if you'd like, and I am very open for discussion as I have not get satisfactory results using HOG. Anyway, I think the code can be good starting point on using HOG for training and detection

    Edit: adding code

    static void calculateFeaturesFromInput(const string& imageFilename, vector& 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 locations;
        hog.compute(imageData, featureVector, winStride, trainingPadding, locations);
        imageData.release(); // Release the image again after features are extracted
    }
    

    ...

    int main(int argc, char** argv) {
    
        // 
        HOGDescriptor hog; // Use standard parameters here
        hog.winSize.height = 128;
        hog.winSize.width = 64;
    
        // Get the files to train from somewhere
        static vector tesImages;
        static vector positiveTrainingImages;
        static vector negativeTrainingImages;
        static vector validExtensions;
        validExtensions.push_back("jpg");
        validExtensions.push_back("png");
        validExtensions.push_back("ppm");
        validExtensions.push_back("pgm");
        // 
    
        // 
        getFilesInDirectory(posSamplesDir, positiveTrainingImages, validExtensions);
        getFilesInDirectory(negSamplesDir, negativeTrainingImages, validExtensions);
        /// Retrieve the descriptor vectors from the samples
        unsigned long overallSamples = positiveTrainingImages.size() + negativeTrainingImages.size();
        // 
    
        // 
        // 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 >), 
         * 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 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;
        }
        // 
    
        // 
        /// Read in and train the calculated feature vectors
        printf("Calling SVMlight\n");
        SVMlight::getInstance()->read_problem(const_cast (featuresFile.c_str()));
        SVMlight::getInstance()->train(); // Call the core libsvm training procedure
        printf("Training done, saving model file!\n");
        SVMlight::getInstance()->saveModelToFile(svmModelFile);
        // 
    
        // 
        printf("Generating representative single HOG feature vector using svmlight!\n");
        vector descriptorVector;
        vector 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);
        // 
    
        // 
    
        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);
            }
        }
        // 
        return EXIT_SUCCESS;
    }
    

提交回复
热议问题