Since you have already calculated the distance between the keypoints, in order to match them, sort them in increasing order of Euclidean distance, and consider only those keypoints which are a constant*min_distance [i.e: select on some %age of the sorted distances] as 'good matches'.
There is also BruteForceMatcher, KNNMatch and FlannBasedMatcher in OpenCV (URL Below)
http://docs.opencv.org/2.4/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.html#feature-flann-matcher
and
http://docs.opencv.org/2.4/modules/features2d/doc/common_interfaces_of_descriptor_matchers.html#descriptormatcher-knnmatch
Also, have a look at these questions and their responses.
1) Trying to match two images using sift in OpenCv, but too many matches
2) Efficient way for SIFT descriptor matching
Just for completeness, providing some very rough code for your reference.
If you have ;
class SIFTDemo
{
private:
Mat image;
vector<cv::KeyPoint> keypoints;
Mat descriptors;
Mat sift_output;
vector<DMatch> matches;
public:
SIFTDemo();
~SIFTDemo();
SIFTDemo(Mat m);
void extractSiftFeatures();
vector <DMatch> FindMatchesEuclidian(SIFTDemo &m2);
};
Then one can have something like this;
void SIFTDemo::extractSiftFeatures()
{
SIFT siftobject;
siftobject.operator()(image, Mat(), keypoints, descriptors);
}
vector<DMatch> SIFTDemo::FindMatchesEuclidian(SIFTDemo &m2)
{
// Calculate euclidian distance between keypoints to find best matching pairs.
// create two dimensional vector for storing euclidian distance
vector< vector<float> > vec1, unsortedvec1;
for (int i=0; i<this->keypoints.size(); i++)
{
vec1.push_back(vector<float>()); // Add an empty row
unsortedvec1.push_back(vector<float>());
}
// create vector of DMatch for storing matxhes point
vector<DMatch> matches1;
DMatch dm1;
// loop through keypoints1.size
for (int i=0; i<this->keypoints.size(); i++)
{
// get 128 dimensions in a vector
vector<float> k1;
for(int x=0; x<128; x++)
{
k1.push_back((float)this->descriptors.at<float>(i,x));
}
// loop through keypoints2.size
for (int j=0; j<m2.keypoints.size(); j++)
{
double temp=0;
// calculate euclidian distance
for(int x=0; x<128; x++)
{
temp += (pow((k1[x] - (float)m2.descriptors.at<float>(j,x)), 2.0));
}
vec1[i].push_back((float)sqrt(temp)); // store distance for each keypoints in image2
unsortedvec1[i] = vec1[i];
}
sort(vec1[i].begin(),vec1[i].end()); // sort the vector distances to get shortest distance
// find position of the shortest distance
int pos = (int)(find(unsortedvec1[i].begin(), unsortedvec1[i].end(), vec1[i][0]) - unsortedvec1[i].begin());
// assign that matchin feature to DMatch variable dm1
dm1.queryIdx = i;
dm1.trainIdx = pos;
dm1.distance = vec1[i][0];
matches1.push_back(dm1);
this->matches.push_back(dm1);
//cout << pos << endl;
}
// craete two dimensional vector for storing euclidian distance
vector<vector<float>> vec2, unsortedvec2;
for (int i=0; i<m2.keypoints.size(); i++)
{
vec2.push_back(vector<float>()); // Add an empty row
unsortedvec2.push_back(vector<float>());
}
// create vector of DMatch for storing matxhes point
vector<DMatch> matches2;
DMatch dm2;
// loop through keypoints2.size
for (int i=0; i<m2.keypoints.size(); i++)
{
// get 128 dimensions in a vector
vector<float> k1;
for(int x=0; x<128; x++)
{
k1.push_back((float)m2.descriptors.at<float>(i,x));
}
// loop through keypoints1.size
for (int j=0; j<this->keypoints.size(); j++)
{
double temp=0;
// calculate euclidian distance
for(int x=0; x<128; x++)
{
temp += (pow((k1[x] - (float)this->descriptors.at<float>(j,x)), 2.0));
}
vec2[i].push_back((float)sqrt(temp)); // store distance for each keypoints in image1
unsortedvec2[i] = vec2[i];
}
sort(vec2[i].begin(),vec2[i].end()); // sort the vector distances to get shortest distance
// find position of the shortest distance
int pos = (int)(find(unsortedvec2[i].begin(), unsortedvec2[i].end(), vec2[i][0]) - unsortedvec2[i].begin());
// assign that matchin feature to DMatch variable
dm2.queryIdx = i;
dm2.trainIdx = pos;
dm2.distance = vec2[i][0];
matches2.push_back(dm2);
m2.matches.push_back(dm2);
//cout << pos << endl;
}
// Ref : http://docs.opencv.org/2.4/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.html#feature-flann-matcher
//-- Quick calculation of max and min distances between keypoints1
double max_dist = 0;
double min_dist = 500.0;
for( int i = 0; i < matches1.size(); i++ )
{
double dist = matches1[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
// Draw only "good" matches1 (i.e. whose distance is less than 2*min_dist )
vector<DMatch> good_matches1;
for( int i = 0; i < matches1.size(); i++ )
{
if( matches1[i].distance <= 2*min_dist )
{
good_matches1.push_back( matches1[i]);
}
}
// Quick calculation of max and min distances between keypoints2 but not used
for( int i = 0; i < matches2.size(); i++ )
{
double dist = matches2[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
// Draw only "good" matches by comparing that (ft1 gives ft2) and (ft2 gives ft1)
vector<DMatch> good_matches;
for(unsigned int i=0; i<good_matches1.size(); i++)
{
// check ft1=ft2 and ft2=ft1
if(good_matches1[i].queryIdx == matches2[good_matches1[i].trainIdx].trainIdx)
good_matches.push_back(good_matches1[i]);
}
return good_matches;
}
FInally, as mentioned in the comment also look at RANSAC to do this. Not diving into that not to make the answer longer but you can find resources online and on SO.