Finding top similar images from a database using SIFT
I am working on project and using SIFT features (OpenCV implementation) for image matching. I need to return top 10-15 images in the database which are similar to the query image. I'm using a visual bag-of-words approach to make a vocabulary first and then do the matching. I've found similar questions but didn't find the appropriate answer.
Here is code to generate a dictionary from database images:
char * filename = new char[100];
Mat input;
//To store the keypoints that will be extracted by SIFT
vector<KeyPoint> keypoints;
//To store the SIFT descriptor of current image
Mat descriptor;
//To store all the descriptors that are extracted from all the images.
Mat featuresUnclustered;
//The SIFT feature extractor and descriptor
SiftDescriptorExtractor detector;
for(int f=1;f<20;f++) // 20 images in database
{
sprintf(filename,"/home/kamikaze/testing/bagofwords/images/%i.jpg",f);
input = imread(filename, CV_LOAD_IMAGE_GRAYSCALE); //Load as grayscale
//detect feature points
detector.detect(input, keypoints);
//compute the descriptors for each keypoint
detector.compute(input, keypoints,descriptor);
//put the all feature descriptors in a single Mat object
featuresUnclustered.push_back(descriptor);
}
int dictionarySize=200;
TermCriteria tc(CV_TERMCRIT_ITER,100,0.001);
int retries=1;
int flags=KMEANS_PP_CENTERS;
//Create the BoW (or BoF) trainer
BOWKMeansTrainer bowTrainer(dictionarySize,tc,retries,flags);
//cluster the feature vectors
Mat dictionary=bowTrainer.cluster(featuresUnclustered);
//store the vocabulary
FileStorage fs("dictionary.yml", FileStorage::WRITE);
fs << "vocabulary" << dictionary;
fs.release();
Here's my code to extract a BoW descriptor from query image using this vocabulary:
Mat dictionary;
FileStorage fs("dictionary.yml", FileStorage::READ);
fs["vocabulary"] >> dictionary;
fs.release();
Ptr<DescriptorMatcher> matcher(new FlannBasedMatcher);
Ptr<FeatureDetector> detector(new SiftFeatureDetector());
Ptr<DescriptorExtractor> extractor(new SiftDescriptorExtractor);
BOWImgDescriptorExtractor bowDE(extractor,matcher);
bowDE.setVocabulary(dictionary);
char * filename = new char[100];
char * imageTag = new char[10];
//open the file to write the resultant descriptor
FileStorage fs1("descriptor.yml", FileStorage::WRITE);
//the image file with the location.
sprintf(filename,"G:\\testimages\\image\\1.jpg");
Mat img=imread(filename,CV_LOAD_IMAGE_GRAYSCALE);
//To store the keypoints that will be extracted by SIFT
vector<KeyPoint> keypoints;
//Detect SIFT keypoints (or feature points)
detector->detect(img,keypoints);
//To store the BoW (or BoF) representation of the image
Mat bowDescriptor;
//extract BoW (or BoF) descriptor from given image
bowDE.compute(img,keypoints,bowDescriptor);
sprintf(imageTag,"img1");
fs1 << imageTag << bowDescriptor;
fs1.release();
I don't know how can I make use of bowDescriptor for getting similar images in the database.