BOF:sift,k-means,svm 环境:Opencv3.4,vs2015 xue.2018.5.2
[1]BOF算法+K-Means算法实现图像检索 [2]Bag-of-Features Descriptor on SIFT Features with OpenCV (BoF-SIFT)
对图像进行特征提取,可以采用sift,surf,mesr等特征提取。采用k-means将特征点聚类为200个,相当于词典中有200个基本词汇。
vector<KeyPoint> keypoints; Mat descriptor; Mat featuresUnclustered; Ptr<Feature2D> sift = xfeatures2d::SIFT::create(); //遍历文件夹 char billPicsPathName[256] = "C:\\tImg"; CStatDir statdir; if (!statdir.SetInitDir(billPicsPathName)) cout << "文件夹为空" << endl; vector<string> file_vec = statdir.BeginBrowseFilenames("*.jpg"); float idx = 0; for (auto itr = file_vec.begin(); itr < file_vec.end(); itr++,idx++) { Mat src = imread(*itr, IMREAD_GRAYSCALE); sift->detect(src, keypoints); sift->compute(src, keypoints, descriptor); featuresUnclustered.push_back(descriptor); float fR = idx / (float)(file_vec.size()); cout << "完成率:"<<fR<< endl; } int dictionarySize = 200; TermCriteria tc(CV_TERMCRIT_ITER, 100, 0.001); int retries = 1; int flags = KMEANS_PP_CENTERS; BOWKMeansTrainer bowTrainer(dictionarySize, tc, retries, flags); Mat dictionary = bowTrainer.cluster(featuresUnclustered); FileStorage fs("c:\\vocabulary.xml", FileStorage::WRITE); fs << "vocabulary" << dictionary; fs.release();统计每张图像在每个聚类中心的特征个数,这样图像可以由一个分布直方图表示,即每个图像可以由词典中的基本词汇构成。
clock_t startime = clock(); Mat dictionary; FileStorage fs("c:\\vocabulary.xml", FileStorage::READ); fs["vocabulary"] >> dictionary; fs.release(); Ptr<DescriptorMatcher> matcher(new FlannBasedMatcher); Ptr<Feature2D> sift = xfeatures2d::SIFT::create(); BOWImgDescriptorExtractor bowDE(sift, matcher); bowDE.setVocabulary(dictionary); vector<KeyPoint> keypoints; //遍历文件夹 char billPicsPathName[256] = "C:\\trainData"; CStatDir statdir; statdir.SetInitDir(billPicsPathName); vector<string> file_vec = statdir.BeginBrowseFilenames("*.*"); ofstream outfile("C:\\ticketName.txt"); Mat trainingData,labels; int idx = -1; string namePrev; for (auto itr = file_vec.begin(); itr != file_vec.end(); itr++) { string name = getImgName(*itr); if (-1 == idx) { namePrev = name; idx = 0; vNameIdx.push_back(name); } else { if (namePrev != name) { namePrev = name; idx++; vNameIdx.push_back(name); } } Mat img = imread(*itr, IMREAD_GRAYSCALE); sift->detect(img, keypoints); Mat bowDescriptor; bowDE.compute(img, keypoints, bowDescriptor); trainingData.push_back(bowDescriptor); labels.push_back(idx); } Ptr<SVM> model = SVM::create(); model->setType(SVM::Types::C_SVC); model->setKernel(SVM::KernelTypes::RBF); //核函数 model->setGamma(0.50625000000000009); model->setC(312.50000000000000); model->setTermCriteria(CvTermCriteria(CV_TERMCRIT_ITER, 1000, 0.000001)); model->train(trainingData,ROW_SAMPLE,labels); model->save("C:\\svm-classifier.xml");对于待检索的图像,首先获取图像特征,得到其根据聚类中心的直方分布图。
//这里并不是完整代码,是核心代码,基本推敲下都能写出来。 //读取SVM模型 Ptr<SVM> model = cv::ml::StatModel::load<SVM>("C:\\svm-classifier.xml"); //计算图像特征向量 //读取字典 Mat dictionary; FileStorage fs("C:\\vocabulary.xml", FileStorage::READ); fs["vocabulary"] >> dictionary; fs.release(); //声明 Ptr<Feature2D> sift = xfeatures2d::SIFT::create(); Ptr<DescriptorMatcher> matcher(new FlannBasedMatcher); BOWImgDescriptorExtractor bowDE(sift, matcher); bowDE.setVocabulary(dictionary); //计算特征向量 bowDE.compute(img, keypoints, bowDescriptor); //预测 int nIdx = model->predict(bowDescriptor);百度云:
链接:https://pan.baidu.com/s/1HuZeDZNvkyngf6R9P5wU-g 密码:wxxj 具体步骤请参阅上述文件中word文档,软件不太稳定,测试功能即可。
&emsp;笔者采用33中图像,训练样本330个,测试样本99个。各样本个数均匀分布,测试通过率100%,但速度有点慢(300像素,33种类别),单张识别时间2.5~3s。