Ask Your Question
3

How to 2-Class Categolization using SURF+BoW+SVM

asked 2013-11-27 06:42:03 -0600

shige gravatar image

updated 2013-11-27 22:44:33 -0600

I try to 2-Class Categolization. I retreive Image descriptors SURF and BOW, and SVM is used for training. My question is what I specify to clusterCount of BOWKMeansTrainer. training code is like below,

void createTrainDataUsingBow(std::vector<char*> files, cv::Mat& train, cv::Mat& response, int label)
{
    cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("FlannBased");
    cv::Ptr<cv::DescriptorExtractor> extractor = new cv::SurfDescriptorExtractor();
    cv::BOWImgDescriptorExtractor dextract( extractor, matcher );
    cv::SurfFeatureDetector detector(500);

    // cluster count
    int cluster = 100;

    // create the object for the vocabulary.
    cv::BOWKMeansTrainer bow( cluster,  cv::TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, FLT_EPSILON), 1, cv::KMEANS_PP_CENTERS );

    // get SURF descriptors and add to BOW each input files
    std::vector<char*>::const_iterator file;
    for( file = files.begin(); file != files.end(); file++)
    {
        cv::Mat img = cv::imread( *file, CV_LOAD_IMAGE_GRAYSCALE );
        std::vector<cv::KeyPoint> keypoints = detector.detect( img, keypoints);
        cv::Mat descriptors;
        extractor->compute( img, keypoints, descriptors);
        if ( !descriptors.empty() ) bow.add( descriptors );
    }

    // Create the vocabulary with KMeans.
    cv::Mat vocabulary;
    vocabulary = bow.cluster();

    for( file = files.begin(); file != files.end(); file++)
    {
        // set training data using BOWImgDescriptorExtractor
        dextract.setVocabulary( vocabulary );
        std::vector<cv::KeyPoint> keypoints;
        cv::Mat img = cv::imread( *file, CV_LOAD_IMAGE_GRAYSCALE );
        detector.detect( img, keypoints);
        cv::Mat desc;
        dextract.compute( img, keypoints, desc );
        if ( !desc.empty() )
        {
            train.push_back( desc );            // update training data
            response.push_back( label );        // update response data
        }
    }
}

int trainSVM((std::vector<char*> positive, std::vector<char*> negative)
{
    // create training data
    cv::Mat train;
    cv::Mat response;
    createTrainDataUsingBow(positive, train, response, 1.0);
    createTrainDataUsingBow(negative, train, response, -1.0);

    // svm parameters
    CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON);
    CvSVMParams svm_param = CvSVMParams( CvSVM::C_SVC, CvSVM::RBF, 10.0, 8.0, 1.0, 10.0, 0.5, 0.1, NULL, criteria);

    // train svm
    cv::SVM svm;
    svm.train(train, response, cv::Mat(), cv::Mat(), svm_param);
    svm.save("svm-classifier.xml");

    return 0;
}

classifier xml file is successfully created, but exception occerred when I use SVM predict method. I doubt clusterCount is illegal ?

exception is below,

OpenCV Error: Sizes of input arguments do not match (The sample size is different from what has been used for training) in cvPreparePredictData, file ......\src\opencv\modules\ml\src\inner_functions.cpp, line 1114.

edit retag flag offensive close merge delete

3 answers

Sort by ยป oldest newest most voted
3

answered 2013-11-27 08:43:35 -0600

Guanta gravatar image

updated 2013-11-27 09:27:04 -0600

And this compiles? Actually these two lines:

std::vector<cv::KeyPoint> keypoints = detector.detect( img, keypoints);
cv::Mat img = cv::imread( *file, CV_LOAD_IMAGE_GRAYSCALE );

should be swapped.

The rest looks in principle fine, only that you should create one single dictionary, not for each class a separate dictionary. Otherwise it would be more difficult to measure a concrete distance between two resulting BoW descriptors (is that possible at all?).

Regarding your error: Do you also use the same BoW-extraction? i.e. do you use 'dextract' with the other images as well? Maybe you used your 'extractor' (or another SURF-descriptor-extractor).

edit flag offensive delete link more

Comments

thanks for comment, and sorry, acctually code is below,

cv::Mat img = cv::imread( *file, CV_LOAD_IMAGE_GRAYSCALE ); std::vector<cv::KeyPoint> keypoints = detector.detect( img, keypoints); cv::Mat desc; dextract.compute( img, keypoints, desc );

shige gravatar imageshige ( 2013-11-27 10:55:09 -0600 )edit

Thanks Guanta ! About exception case, I solved revising SurfDescriptorExtractor to BOWImgDescriptorExtractor. but I can not implement exact 2-class categolization, accuracy is about 30%. Indeed, I did not think about distance of BoW descriptors, I want more precise categolization. In that case, What parameter do I optimize at training sequence ?

shige gravatar imageshige ( 2013-11-28 18:56:22 -0600 )edit

What do you mean with "distance of BoW descriptors"? Have you also changed your two dictionary approach to an approach using only one? In the training phase you typically estimate only the parameters of the SVM (gamma and C if you use an RBF kernel, typically in a grid with 3- or 5-fold cross-validation).

Guanta gravatar imageGuanta ( 2013-11-29 07:25:22 -0600 )edit

Thank you for comment, Guanta. I think that SVM predit value is distance of BoW descriptors. I am wrong ? my predict code is below.

shige gravatar imageshige ( 2013-12-02 22:29:45 -0600 )edit
0

answered 2013-12-02 22:49:23 -0600

shige gravatar image

SVM predict code is, finally, I will determine class by predict value.

int svmPredict(const char* classifier, const char* vocaname, const char* query, const char* method)
{
    // load image
    cv::Mat img = cv::imread(query, CV_LOAD_IMAGE_GRAYSCALE);

    // load svm
    cv::SVM svm;
    svm.load(classifier);

    // declare BOWImgDescriptorExtractor
    cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("FlannBased");
    cv::Ptr<cv::DescriptorExtractor> extractor = new cv::SurfDescriptorExtractor();
    cv::BOWImgDescriptorExtractor dextract( extractor, matcher );

    // load vocabulary data
    cv::Mat vocabulary;
    cv::FileStorage fs( vocaname, cv::FileStorage::READ);
    fs["vocabulary data"] >> vocabulary;
    fs.release();
    if( vocabulary.empty()  ) return 1;

    // Set the vocabulary
    dextract.setVocabulary( vocabulary );
    std::vector<cv::KeyPoint> keypoints;
    detector.detect( img, keypoints);
    cv::Mat desc_bow;
    dextract.compute( img, keypoints, desc_bow );
    if( desc_bow.empty() )  return 1;

    // svm predict
    float predict = svm.predict(centroids, true);

    std::cout << predict << std::endl;

    return 0;
}
edit flag offensive delete link more

Comments

@shinge: in your "svmPredict()" , you are using "svm.predict(centroids, true);" but you have not created "centroids" anywhere in the code. Can you please tell me, how to have that "centroids" ?

user1234 gravatar imageuser1234 ( 2013-12-17 13:25:00 -0600 )edit

Can anybody tell me .... what do I pass as an argument for vocaname ??

Shaurya gravatar imageShaurya ( 2015-02-28 02:45:55 -0600 )edit
0

answered 2013-12-17 13:26:17 -0600

user1234 gravatar image

@shinge: in your svmPredict() , you are using svm.predict(centroids, true); but you have not created centroids anywhere in the code. Can you please tell me, how to have that centroids ?

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2013-11-27 06:42:03 -0600

Seen: 5,705 times

Last updated: Dec 17 '13