Hi I was trying out the Bag of Words to classify images. I tried a simple example:
- train n images of same object (n = 4 for starter)
- create BoW vocabulary: I used ORB feature descriptors to create my BoW vocab
- train svm with the histogram responses from BoW
- use trained svm for prediction
The first 3 steps seems to be working fine: Here is code of training part (upto step 3):
// Read All image files in training directory and save their names //
std::vector<cv::String> filenames;
cv::String directory = argv[1];
cv::glob(directory, filenames);
// detect ORB features from each image and store them //
cv::Mat orb_cluster;
cv::Mat orb_descriptor;
cv::Ptr<cv::Feature2D> orb_detector = cv::ORB::create(500, 1.2f, 8, 31, 0,2, cv::ORB::HARRIS_SCORE, 31, 20);
cv::Ptr<cv::DescriptorExtractor> orb_extractor = cv::ORB::create();
std::vector<cv::KeyPoint> orb_kp;
for(size_t t = 0; t < filenames.size(); t++)
{
cv::Mat input;
input = cv::imread(filenames[t], 0);
orb_detector->detect(input, orb_kp); // detect keypoints
orb_extractor->compute(input, orb_kp, orb_descriptor); // extract orb descriptors
orb_cluster.push_back(orb_descriptor); // store the descriptors
}
cv::Mat orb_cluster_f(orb_cluster.rows, orb_cluster.cols, CV_32F);
orb_cluster.convertTo(orb_cluster_f, CV_32F);
cv::Mat orb_dictionary;
int bag_size = 100;
cv::TermCriteria bow_tc(CV_TERMCRIT_ITER,100,0.001);
cv::BOWKMeansTrainer bow_km_trainer(bag_size, bow_tc, 2);
orb_dictionary = bow_km_trainer.cluster(orb_cluster_f); // train the BoW and create the dictionary
std::cout << "ORB Dictionary Created" << std::endl;
// Store the dictionary //
cv::FileStorage orb_fs("./train_vocab/orb_dict.yml", cv::FileStorage::WRITE);
orb_fs << "orb_vocabulary" << orb_dictionary;
orb_fs.release();
std::cout << "ORB Dictionary Stored" << std::endl;
// *************** Create Training Data ********************* //
cv::Mat t_orb_dictionary_f;
cv::FileStorage t_orb_fs("./train_vocab/orb_dict.yml", cv::FileStorage::READ);
t_orb_fs["orb_vocabulary"] >> t_orb_dictionary_f;
t_orb_fs.release();
cv::Mat t_orb_dict(t_orb_dictionary_f.rows, t_orb_dictionary_f.cols, CV_8U);
t_orb_dictionary_f.convertTo(t_orb_dict, CV_8U);
cv::Mat bow_histogram;
cv::Mat train_data;
std::vector<cv::KeyPoint> t_orb_kp; // keypoints
cv::Ptr<cv::Feature2D> t_orb_detector = cv::ORB::create(500, 1.2f, 8, 31, 0,2, cv::ORB::HARRIS_SCORE, 31, 20); // detector
cv::Ptr<cv::DescriptorExtractor> t_orb_extractor = cv::ORB::create(); //extractor
cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("BruteForce-Hamming");
cv::Ptr<cv::BOWImgDescriptorExtractor> bow_de(new cv::BOWImgDescriptorExtractor(t_orb_extractor, matcher)); // BOW extractor
bow_de->setVocabulary(t_orb_dict); // set the vocabulary //
for(size_t t = 0; t < filenames.size(); t++)
{
cv::Mat t_input;
t_input = cv::imread(filenames[t], 0);
t_orb_detector->detect(t_input, t_orb_kp); // detect keypoints
bow_de->compute(t_input, t_orb_kp, bow_histogram); // create the response histogram
train_data.push_back(bow_histogram); // create the training data
}
std::cout << "Training SVM..." << std::endl;
//int labels[1] = {1};
//cv::Mat m_labels = cv::Mat::ones(train_data.rows, 1, CV_32SC1);
//cv::Mat m_labels(1, 1, CV_32SC1, labels);
// i have only 1 class, hence added labels 1 for all samples
std::vector<int> m_labels;
for(int i = 0; i < train_data.rows; i++)
{
m_labels.push_back(1);
}
cv::Ptr<cv::ml::SVM> svm_classifier = cv::ml::SVM::create();
svm_classifier->setType(cv::ml::SVM::ONE_CLASS);
svm_classifier->setKernel(cv::ml::SVM::POLY);
svm_classifier->setGamma(3);
svm_classifier->setDegree(2);
svm_classifier->setCoef0(1.0);
svm_classifier->setNu(0.5);
svm_classifier->train( train_data , cv::ml::ROW_SAMPLE , m_labels );
svm_classifier->save("./train_svm/svm_bow.yml");
up to this point the code runs fine. I get the .yml files.
This is the testing code:
// ************ Test the Classifier ************* //
cv::Ptr<cv::ml::SVM> test_svm = cv::ml::SVM::create();
test_svm->load("./train_svm/svm_bow.yml");
cv::Mat test_orb_dict_f;
cv::FileStorage test_orb_fs("./train_vocab/orb_dict.yml", cv::FileStorage::READ);
test_orb_fs["orb_vocabulary"] >> test_orb_dict_f;
test_orb_fs.release();
cv::Mat test_orb_dict(test_orb_dict_f.rows, test_orb_dict_f.cols, CV_8U);
test_orb_dict_f.convertTo(test_orb_dict, CV_8U);
std::vector<cv::KeyPoint> test_orb_kp; // keypoints
cv::Ptr<cv::Feature2D> test_orb_detector = cv::ORB::create(500, 1.2f, 8, 31, 0,2, cv::ORB::HARRIS_SCORE, 31, 20); // detector
cv::Ptr<cv::DescriptorExtractor> test_orb_extractor = cv::ORB::create(); //extractor
cv::Ptr<cv::DescriptorMatcher> test_matcher = cv::DescriptorMatcher::create("BruteForce-Hamming");
cv::Ptr<cv::BOWImgDescriptorExtractor> test_bow_de(new cv::BOWImgDescriptorExtractor(test_orb_extractor, test_matcher)); // BOW extractor
test_bow_de->setVocabulary(test_orb_dict); // set the vocabulary //
cv::Mat test_in = cv::imread("./test_img/t1.tif", 0);
cv::Mat test_bow_histogram;
test_orb_detector->detect(test_in, test_orb_kp); // detect keypoints
test_bow_de->compute(test_in, test_orb_kp, test_bow_histogram); // create the response histogram
cv::Mat test_bow_hist_f(test_bow_histogram.rows, test_bow_histogram.cols, CV_32FC1);
test_bow_histogram.convertTo(test_bow_hist_f, CV_32FC1);
cv::Mat result;
float r = test_svm->predict(test_bow_hist_f, result); // this is where the assertion falis
The error message:
OpenCV Error: Assertion failed (samples.cols == var_count && samples.type() == CV_32F) in predict, file /home/asa/asa_wd_mount/trunk/projects/mvs/3rd_party/opencv/opencv-master/modules/ml/src/svm.cpp, line 1930 terminate called after throwing an instance of 'cv::Exception' what(): /home/asa/asa_wd_mount/trunk/projects/mvs/3rd_party/opencv/opencv-master/modules/ml/src/svm.cpp:1930: error: (-215) samples.cols == var_count && samples.type() == CV_32F in function predict
Now, I am using one of the training image as test image. the svm .yml file says var_count = 100 part of the .yml file:
%YAML:1.0 opencv_ml_svm:
format: 3 svmType: ONE_CLASS
kernel: type: POLY degree: 2. gamma: 3. coef0: 1.
nu: 5.0000000000000000e-01
term_criteria: { epsilon:1.1920928955078125e-07, iterations:1000 }
var_count: 100
class_count: 1
sv_total: 2
I have also checked the size of the test histogram "test_bow_hist_f". it has 1 row and 100 columns. my training data has 4 training samples, each 100 columns.
I have been getting the same assertion fail.
any help on what am I doing wrong would be greatly appreciated.
Thanks