Example #1
0
void RobustMatcher::robustMatch( const cv::Mat& frame, std::vector<cv::DMatch>& good_matches,
              std::vector<cv::KeyPoint>& keypoints_frame, const cv::Mat& descriptors_model )
{

  // 1a. Detection of the ORB features
  this->computeKeyPoints(frame, keypoints_frame);

  // 1b. Extraction of the ORB descriptors
  cv::Mat descriptors_frame;
  this->computeDescriptors(frame, keypoints_frame, descriptors_frame);

  // 2. Match the two image descriptors
  std::vector<std::vector<cv::DMatch> > matches12, matches21;

  // 2a. From image 1 to image 2
  matcher_->knnMatch(descriptors_frame, descriptors_model, matches12, 2); // return 2 nearest neighbours

  // 2b. From image 2 to image 1
  matcher_->knnMatch(descriptors_model, descriptors_frame, matches21, 2); // return 2 nearest neighbours

  // 3. Remove matches for which NN ratio is > than threshold
  // clean image 1 -> image 2 matches
  ratioTest(matches12);
  // clean image 2 -> image 1 matches
  ratioTest(matches21);

  // 4. Remove non-symmetrical matches
  symmetryTest(matches12, matches21, good_matches);

}
void SymmetryNNDRMatcher::match(Mat &descriptors_object, Mat &descriptors_scene, std::vector<DMatch> &good_matches)
{
  cv::BruteForceMatcher<cv::L2<float> > matcher;	

  // Match all keypoints from the object to the scene
  std::vector<std::vector<cv::DMatch> > matches1;
  matcher.knnMatch(descriptors_object, descriptors_scene,
      matches1, // Vector of matches
      2); // return 2 nearest neighbours

  // Match all keypoints from the scene with the object
  std::vector<std::vector<cv::DMatch> > matches2;
  matcher.knnMatch(descriptors_scene, descriptors_object,
      matches2, // Vector of matches
      2); // return 2 nearest neighbours


  // Check NNDR for both match vectors
  ratioTest(matches1);
  ratioTest(matches2);

  // Remove non-symmetrical matches
  // std::vector<cv::DMatch> symMatches;
  symmetryTest(matches1,matches2,good_matches);

}
// Main method:
cv::Mat RobustMatcher::match(cv::Mat &image1,
                             cv::Mat &image2,
                             std::vector<cv::DMatch> &matches,
                             std::vector<cv::KeyPoint> &keypoints1,
                             std::vector<cv::KeyPoint> &keypoints2){

    // 1a. Detection of the SURF features
    detector->detect(image1,keypoints1);
    detector->detect(image2,keypoints2);
    // 1b. Extraction of the SURF descriptors
    cv::Mat descriptors1, descriptors2;
    extractor->compute(image1,keypoints1,descriptors1);
    extractor->compute(image2,keypoints2,descriptors2);
    // 2. Match the two image descriptors
    // Construction of the matcher
    //cv::BruteForceMatcher< cv::L2<float> > matcher;
    cv::FlannBasedMatcher matcher;

    // from image 1 to image 2
    // based on k nearest neighbours (with k=2)
    std::vector< std::vector<cv::DMatch> > matches1;
    matcher.knnMatch(descriptors1,descriptors2,
                     matches1, // vector of matches (up to 2 per entry)
                     2);
     // return 2 nearest neighbours
     // from image 2 to image 1
     // based on k nearest neighbours (with k=2)
     std::vector< std::vector<cv::DMatch> > matches2;
     matcher.knnMatch(descriptors2,descriptors1,
     matches2, // vector of matches (up to 2 per entry)
     2);
     // return 2 nearest neighbours
     // 3. Remove matches for which NN ratio is
     // > than threshold
     // clean image 1 -> image 2 matches
     int removed= ratioTest(matches1);
     // clean image 2 -> image 1 matches
     removed= ratioTest(matches2);
     // 4. Remove non-symmetrical matches
     std::vector<cv::DMatch> symMatches;

     symmetryTest(matches1,matches2,symMatches);
     // 5. Validate matches using RANSAC
     cv::Mat fundemental= ransacTest(symMatches,
     keypoints1, keypoints2, matches);
     // return the found fundemental matrix
     return fundemental;
}
Example #4
0
void RobustMatcher::fastRobustMatch( const cv::Mat& frame, std::vector<cv::DMatch>& good_matches,
                                 std::vector<cv::KeyPoint>& keypoints_frame,
                                 const cv::Mat& descriptors_model )
{
  good_matches.clear();

  // 1a. Detection of the ORB features
  this->computeKeyPoints(frame, keypoints_frame);

  // 1b. Extraction of the ORB descriptors
  cv::Mat descriptors_frame;
  this->computeDescriptors(frame, keypoints_frame, descriptors_frame);

  // 2. Match the two image descriptors
  std::vector<std::vector<cv::DMatch> > matches;
  matcher_->knnMatch(descriptors_frame, descriptors_model, matches, 2);

  // 3. Remove matches for which NN ratio is > than threshold
  ratioTest(matches);

  // 4. Fill good matches container
  for ( std::vector<std::vector<cv::DMatch> >::iterator
         matchIterator= matches.begin(); matchIterator!= matches.end(); ++matchIterator)
  {
    if (!matchIterator->empty()) good_matches.push_back((*matchIterator)[0]);
  }

}
Example #5
0
// Match features and compute essential mat
bool RobustMatcher::robustMatchEssentialMat(const cv::Mat &frame1, const cv::Mat &frame2, const cv::Mat &K,
  KeyPointVec &kpts1_inliers, KeyPointVec &kpts2_inliers,
  DMatchVec &inliers_matches, cv::Mat &essentialMat)
{
  cv::Mat desc1, desc2, inliers_mask;
  KeyPointVec kpts1, kpts1_good, kpts2, kpts2_good;
  DMatchVec good_matches;
  DMatchVec2 nn_matches;

  // compute keypoints and decriptor and match
  nnMatch(frame1, kpts1, desc1, frame2, kpts2, desc2, nn_matches);

  // perform ratio test
  ratioTest(nn_matches, good_matches, kpts1, kpts1_good, kpts2, kpts2_good);

  // for essential mat we need
  // at least 4 points
  if(kpts2_good.size() >= 4)
  {
    computeEssentialMat(kpts1_good, kpts2_good, K, essentialMat, inliers_mask);
  }
  else
  {
    return false;
  }

  // extract inliers
  extractInliers(inliers_mask, kpts1_good, kpts2_good, kpts1_inliers, kpts2_inliers, inliers_matches);


  return true;
}
/* Calculation of Homography for feature based
 *
 **/
void AlignmentMatrixCalc::featureBasedHomography()
{
    std::vector<cv::DMatch> matchesPrevToCurrent;
    std::vector<cv::DMatch> matchesCurrentToPrev;
    std::vector<std::vector<cv::DMatch> > kmatchesPrevToCurrent;
    std::vector<std::vector<cv::DMatch> > kmatchesCurrentToPrev;
    std::vector<cv::DMatch> matchesPassed;

    // Matching Section begin
    if( matchType == normalMatch )
    {
        matcher->match( descriptorsPrev, descriptorsCurrent, matchesPrevToCurrent );
        matcher->match( descriptorsCurrent, descriptorsPrev, matchesCurrentToPrev );
        // Symmetry Test start
        symmetryTest(matchesPrevToCurrent, matchesCurrentToPrev, matchesPassed);

    }
    else if( matchType == knnMatch)
    {
 //       qDebug()<<"Match : "<<keypointsCurrent.size()<<"  "<<keypointsPrev.size()<<"\n";
        matcher->knnMatch(descriptorsPrev, descriptorsCurrent, kmatchesPrevToCurrent,2);
 //       qDebug()<<"Ratio Test 1 :"<<kmatchesPrevToCurrent.size()<<"\n";
        ratioTest(kmatchesPrevToCurrent);
 //       qDebug()<<"Ratio Test 1 End :"<<kmatchesPrevToCurrent.size()<<"\n";
        matcher->knnMatch(descriptorsCurrent,descriptorsPrev, kmatchesCurrentToPrev, 2);
 //       qDebug()<<"Ratio Test 2 :"<<kmatchesCurrentToPrev.size()<<"\n";
        ratioTest(kmatchesCurrentToPrev);
 //       qDebug()<<"Ratio Test 2 End :"<<kmatchesCurrentToPrev.size()<<"\n";
        // Symmetry Test not working for knn
        //matchesPassed=matchesPrevToCurrent;
        symmetryTest(kmatchesPrevToCurrent,kmatchesCurrentToPrev,matchesPassed);
 //       qDebug()<<"Sym Test  :"<<matchesPassed.size()<<"\n";

    }
    else if( matchType == radiusMatch)
    {
        // there is no documentation
        // matcher->radiusMatch(descriptorsPrev, descriptorsCurrent, kmatchesPrevToCurrent,maxRadius );
        // work but there is no matching back for any maxRadius
        //convertRMatches(kmatchesCurrentToPrev,matchesPassed);
        exc.showException("radiusMatch not working Dont use it!" );

    }


    // Matching Section end
    isHomographyCalc = false;

    pointsPrev.clear();
    pointsCurrent.clear();

    // Conversition of matched Keypoints to points
    for (int p = 0; p < (int)matchesPassed.size(); ++p)
    {
        pointsPrev.push_back(keypointsPrev[matchesPassed[p].queryIdx].pt);
        pointsCurrent.push_back(keypointsCurrent[matchesPassed[p].trainIdx].pt);
    }

    // if enough matched points exist
    if(pointsPrev.size() >= 4 && pointsCurrent.size() >= 4)
    {
        // Sub-pixsel Accuracy

        cv::cornerSubPix(prevFrame, pointsPrev, cv::Size(5,5), cv::Size(-1,-1),
                         cv::TermCriteria(cv::TermCriteria::MAX_ITER+cv::TermCriteria::EPS,30,0.1));

        cv::cornerSubPix(currentFrame, pointsCurrent, cv::Size(5,5), cv::Size(-1,-1),
                         cv::TermCriteria(cv::TermCriteria::MAX_ITER+cv::TermCriteria::EPS,30,0.1));

        homography = cv::findHomography(pointsPrev, pointsCurrent, homographyCalcMethod,
                                        ransacReprojThreshold);
        /*
         cv::findHomography can return empty matrix in some cases.
         This seems happen only when cv::RANSAC flag is passed.
         check the computed homography before using it
         */
        if(!homography.empty())
        {
            if(isHomographyValid()) //
            {
                isHomographyCalc = true;
            }
        }

    }

    if(isHomographyCalc == false)
    {
        // if valid homography not calculated returns to a second stage....
        stage=secondPass;

    }

}
// Match feature points using symmetry test and RANSAC
// returns fundemental matrix
bool feature_matcher::match(cv::Mat& image1, cv::Mat& image2, // input images
	                  std::vector<cv::DMatch>& matches, // output matches and keypoints
	                  std::vector<cv::KeyPoint>& keypoints1, std::vector<cv::KeyPoint>& keypoints2) {

	ros::Time startTime = ros::Time::now();
	cv::Mat matchesMat;
	std::stringstream onScreenText;
	// cleaning..
	int imageMatches;
	imageMatches= imageMatches+0;
	matches.clear();
	keypoints1.clear();
	highestComp = 0.;
/*
	cv::createTrackbar("ConfidenceLevel [%] : ", "FEATURE REF", &Trackbar1, 100, NULL);
	cv::createTrackbar("MinDistanceToEpipolar: ", "FEATURE REF", &Trackbar2, 10, NULL);
	cv::createTrackbar("Ratio [%]: ", "FEATURE REF", &Trackbar3, 100, NULL);
	cv::createTrackbar("Min. Matches: ", "FEATURE REF", &Trackbar4, 200, NULL);
*/
	// 1a. Detection of the SURF/SIFT features
	detector->detect(image1,keypoints1);

	std::cout << keypoints1.size() << " Keypoints extracted from Label" << std::endl;
	info_lastMatch.imageKeys = keypoints1.size();

	// 1b. Extraction of the SURF/SIFT descriptors
	cv::Mat descriptors1, descriptors2;
	extractor->compute(image1,keypoints1,descriptors1);
	//extractor->compute(image2,keypoints2,descriptors2);

	//std::cout << "descriptor matrix size: " << descriptors1.rows << " by " << descriptors1.cols << std::endl;

	cv::Mat tmp;
	this->allReferences.copyTo(tmp);

	onScreenText.str(std::string());
	onScreenText << "Keypoints on Scene-Label: " << keypoints1.size();
	cv::putText(tmp, onScreenText.str(), cv::Point(10, this->allReferences.rows - 50), CV_FONT_HERSHEY_SIMPLEX, 0.50, cv::Scalar(200, 200, 0), 1, CV_AA);


	std::cout << "Matching with references (ratio test) : " << std::endl;
	printf("Ref1\tRef2\tRef3\tRef4\tRef5\tRef6\tRef7\tRef8");
	std::cout << std::endl;

	if (descriptors1.rows == 0 || descriptors1.cols == 0) {
		printf("0\t0\t0\t0\t0\t0\t0\t0\n");
		printf("No Keypoints identified from camera. ??Looking at a plain scene??\n");
		return false;
	}


	int featureMatches[2][numOfRefPics];
	int positiveRef;
	float highestMatch;
	std::vector<std::vector<cv::DMatch> > bestMatches;
	cv::Mat bestDescriptors;
	std::vector<cv::KeyPoint> bestKeypoints;
	std::stringstream resultText;
	positiveRef=-1;
	highestMatch=-1;
	resultText.str(std::string());

	for (uint i = 0; (i < (this->referencePics).size()); i++) {

		// take the right Pic/KP/Desc of the Array and store it in XXX2 <- only for easier handling
		keypoints2 = this->refKeypoints[i];
		descriptors2 = this->refDescriptors[i];
		image2= this->referencePics[i];

		// 2. Match the two image descriptors

		// Construction of the matcher

		//cv::Ptr<cv::DescriptorMatcher> matcher = new cv::DescriptorMatcher::create("BruteForceMatcher");
		//OPEN CV 2.3 style:
		cv::BruteForceMatcher<cv::L2<float> > matcher;

		// from image 1 to image 2
		// based on k nearest neighbours (with k=2)
		std::vector<std::vector<cv::DMatch> > matches1;
		matches1.clear();
		matcher.knnMatch(descriptors1, descriptors2, matches1, // vector of matches (up to 2 per entry)
				2); // return 2 nearest neighbours

		// from image 2 to image 1
		// based on k nearest neighbours (with k=2)
		std::vector<std::vector<cv::DMatch> > matches2;
		matches2.clear();
		matcher.knnMatch(descriptors2, descriptors1, matches2, // vector of matches (up to 2 per entry)
				2); // return 2 nearest neighbours

	                //std::cout << "Number of matched points 1->2: " << matches1.size() << std::endl;
	                //std::cout << "Number of matched points 2->1: " << matches2.size() << std::endl;
	                //cv::waitKey(0);

		int stableMatches= 0;
		stableMatches = stableMatches+0;

		// 3. Remove matches for which NN ratio is > than threshold
		if (rTest12) {
			// clean image 1 -> image 2 matches
			int removed = ratioTest(matches1);
			printf("%i", (int)(matches1.size() - removed));
			resultText << (int)(matches1.size() - removed);
			onScreenText.str(std::string());
			onScreenText << "Matches (1->2): " << (matches1.size() - removed);
			cv::putText(tmp, onScreenText.str(), cv::Point(((this->allReferences.cols / this->referencePics.size()) * i + 10),15), CV_FONT_HERSHEY_SIMPLEX, 0.50, cv::Scalar(200, 200, 0), 1, CV_AA);
			stableMatches = matches1.size() - removed;
			featureMatches[0][i]= matches1.size() - removed;


			if (rTest21) {
				// clean image 2 -> image 1 matches
				removed = ratioTest(matches2);
				printf("/%i\t", (int)(matches2.size() - removed));
				resultText << "/" << (int)(matches2.size() - removed) << "  ";
				onScreenText.str(std::string());
				onScreenText << "Matches (1<-2): " << (matches2.size() - removed);
				cv::putText(tmp, onScreenText.str(), cv::Point(((this->allReferences.cols / this->referencePics.size()) * i + 10),35), CV_FONT_HERSHEY_SIMPLEX, 0.50, cv::Scalar(200, 200, 0), 1, CV_AA);
				stableMatches = matches2.size() - removed;
				featureMatches[1][i]= matches2.size() - removed;

				// 4. Remove non-symmetrical matches
				if (symTest) {
					std::vector<cv::DMatch> symMatches;
					symmetryTest(matches1, matches2, symMatches);
					std::cout << "Number of matched points (symmetry test): "
							<< symMatches.size() << std::endl;
					stableMatches = symMatches.size();
					featureMatches[1][i]= symMatches.size();

					// 5. Validate matches using RANSAC
					if (rsacTest) {
						cv::Mat fundemental = ransacTest(symMatches, keypoints1,
								keypoints2, matches);
						stableMatches = matches.size();
						featureMatches[1][i]= symMatches.size();
					}
				}
			}
		}
		// Wenn die Anzahl an Matches beidseitig größer als 15 ist
		if ((featureMatches[0][i] > minimumMatches) && (featureMatches[1][i] > minimumMatches)) {

			if (((featureMatches[1][i]) + (featureMatches[0][i])) > highestMatch) {
				highestMatch= ((featureMatches[1][i]) + (featureMatches[0][i]));
				positiveRef= i;
				bestKeypoints=keypoints2;
				bestMatches= matches2;
				info_lastMatch.positiveMatches1 = featureMatches[0][i];
				info_lastMatch.positiveMatches2 = featureMatches[1][i];
				//cv::waitKey(0);
			}
		}
	}
	std::cout << std::endl;

	// Now look for highest positive Match!
	// TODO: die refPic links und rechts von RefPic[highestMatch] auf Matches überprüfen -> sollten auch Matches haben!!
	highestComp= highestMatch;

	if (positiveRef > -1) {
		std::cout << "The Object was found. Reference picture number " << positiveRef+1 << " gave the best results." << std::endl;

		if (this->showWindows) {
			cv::drawMatches(image1, keypoints1, // 1st image and its keypoints
					this->referencePics[positiveRef], bestKeypoints, // 2nd image and its keypoints
					bestMatches, // the matches
					matchesMat, // the image produced
					cv::Scalar(0, 255, 0)); // color of the lines
			onScreenText.str(std::string());
			onScreenText << "Ref1   Ref2   Ref3   Ref4   Ref5   Ref6   Ref7   Ref8";
			cv::putText(matchesMat, onScreenText.str(), cv::Point(image1.cols/2 - 200, image1.rows/2 +30), CV_FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(10, 10, 255), 1, CV_AA);
			cv::putText(matchesMat, resultText.str(), cv::Point(image1.cols/2 - 200, image1.rows/2 + 50), CV_FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(10, 10, 255), 1, CV_AA);
			cv::namedWindow("Features", CV_WINDOW_AUTOSIZE);
			cv::imshow("Features", matchesMat);
		}
		info_lastMatch.processingTime = (ros::Time::now().nsec - startTime.nsec)/1000000;
		return true;
	}
	// "else"
	if (this->showWindows && (keypoints1.size() > 0)) {
		image1.copyTo(matchesMat);
		onScreenText.str(std::string());
		onScreenText << "This is not the wanted object!";
		cv::putText(matchesMat, onScreenText.str(), cv::Point(image1.cols/2 - 200, image1.rows/2), CV_FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(10, 10, 200), 2, CV_AA);
		onScreenText.str(std::string());
		onScreenText << "Ref1  Ref2  Ref3  Ref4  Ref5  Ref6  Ref7  Ref8";
		cv::putText(matchesMat, onScreenText.str(), cv::Point(image1.cols/2 - 200, image1.rows/2 +30), CV_FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(10, 10, 200), 1, CV_AA);
		cv::putText(matchesMat, resultText.str(), cv::Point(image1.cols/2 - 200, image1.rows/2 + 50), CV_FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(10, 10, 200), 1, CV_AA);
		cv::namedWindow("Features", CV_WINDOW_AUTOSIZE);
		cv::imshow("Features", matchesMat);
	}
	info_lastMatch.processingTime = (ros::Time::now().nsec - startTime.nsec)/1000000;
	return false;
}
bool performEstimation
(
    const FeatureAlgorithm& alg,
    const ImageTransformation& transformation,
    const cv::Mat& sourceImage,
    std::vector<FrameMatchingStatistics>& stat
)
{
  Keypoints   sourceKp;
  Descriptors sourceDesc;

  cv::Mat gray;
  if (sourceImage.channels() == 3)
      cv::cvtColor(sourceImage, gray, CV_BGR2GRAY);
  else if (sourceImage.channels() == 4)
      cv::cvtColor(sourceImage, gray, CV_BGRA2GRAY);
  else if(sourceImage.channels() == 1)
      gray = sourceImage;

  if (!alg.extractFeatures(gray, sourceKp, sourceDesc))
    return false;

  std::vector<float> x = transformation.getX();
  stat.resize(x.size());

  const int count = x.size();

  cv::Mat     transformedImage;
  Keypoints   resKpReal;
  Descriptors resDesc;
  Matches     matches;

  // To convert ticks to milliseconds
  const double toMsMul = 1000. / cv::getTickFrequency();

#pragma omp parallel for private(transformedImage, resKpReal, resDesc, matches)
  for (int i = 0; i < count; i++)
  {
    float       arg = x[i];
    FrameMatchingStatistics& s = stat[i];

    transformation.transform(arg, gray, transformedImage);

    int64 start = cv::getTickCount();

    alg.extractFeatures(transformedImage, resKpReal, resDesc);

    // Initialize required fields
    s.isValid        = resKpReal.size() > 0;
    s.argumentValue  = arg;

    if (!s.isValid)
        continue;

    if (alg.knMatchSupported)
    {
      std::vector<Matches> knMatches;
      alg.matchFeatures(sourceDesc, resDesc, 2, knMatches);
      ratioTest(knMatches, 0.75, matches);

      // Compute percent of false matches that were rejected by ratio test
      s.ratioTestFalseLevel = (float)(knMatches.size() - matches.size()) / (float) knMatches.size();
    }
    else
    {
      alg.matchFeatures(sourceDesc, resDesc, matches);
    }

    int64 end = cv::getTickCount();

    Matches correctMatches;
    cv::Mat homography;
    bool homographyFound = ImageTransformation::findHomography(sourceKp, resKpReal, matches, correctMatches, homography);

    // Some simple stat:
    s.isValid        = homographyFound;
    s.totalKeypoints = resKpReal.size();
    s.consumedTimeMs = (end - start) * toMsMul;

    // Compute overall percent of matched keypoints
    s.percentOfMatches      = (float) matches.size() / (float)(std::min(sourceKp.size(), resKpReal.size()));
    s.correctMatchesPercent = (float) correctMatches.size() / (float)matches.size();

    // Compute matching statistics
    computeMatchesDistanceStatistics(correctMatches, s.meanDistance, s.stdDevDistance);
  }

  return true;
}
/*****************************************************************************
 // The knn matching with k = 2
 // This code performs the matching and the refinement.
 // @paraam query_image: the input image
 // @param matches_out: a pointer that stores the output matches. It is necessary for
 //                     pose estimation.
 */
int knn_match(cv::Mat& query_image,  std::vector< cv::DMatch> * matches_out)
{
    // variabels that keep the query keypoints and query descriptors
    std::vector<cv::KeyPoint>           keypointsQuery;
    cv::Mat                             descriptorQuery;
    
    // Temporary variables for the matching results
    std::vector< std::vector< cv::DMatch> > matches1;
    std::vector< std::vector< cv::DMatch> > matches2;
    std::vector< std::vector< cv::DMatch> > matches_opt1;
    
    
    //////////////////////////////////////////////////////////////////////
    // 1. Detect the keypoints
    // This line detects keypoints in the query image
    _detector->detect(query_image, keypointsQuery);
    
    // If keypoints were found, descriptors are extracted.
    if(keypointsQuery.size() > 0)
    {
        // extract descriptors
        _extractor->compute( query_image, keypointsQuery, descriptorQuery);
        
    }
    
    //////////////////////////////////////////////////////////////////////////////
    // 2. Here we match the descriptors with the database descriptors.
    // with k-nearest neighbors with k=2
    _matcher.knnMatch(descriptorQuery , matches1, 2);
    
#ifdef DEBUG_OUT
    std::cout << "Found " << matches1.size() << " matching feature descriptors out of " << _matcher.getTrainDescriptors().size() << " database descriptors."  << std::endl;
#endif
    
    
    //////////////////////////////////////////////////////////////////////////////
    // 3 Filter the matches.
    // Accept only matches (knn with k=2) which belong ot one images
    // The database tree within _matcher contains descriptors of all input images.
    // We expect that both nearest neighbors must belong to one image.
    // Otherwise we can remove the result.
    // Along with this, we count which reference image has the highest number of matches.
    // At this time, we consinder this image as the searched image.
    
    // we init the variable hit with 0
    std::vector<int> hits(_num_ref_images);
    for (int i=0; i<_num_ref_images; i++)
    {
        hits[i] = 0;
    }
    
    // the loop runs through all matches and comparees the image indes
    // imgIdx. The must be equal otherwise the matches belong to two
    // different reference images.
    for (int i=0; i<matches1.size(); i++)
    {
        // The comparison.
        if(matches1[i].at(0).imgIdx == matches1[i].at(1).imgIdx)
        {
            // we keep it
            matches_opt1.push_back(matches1[i]);
            // and count a hit
            hits[matches1[i].at(0).imgIdx]++;
        }
    }
    
#ifdef DEBUG_OUT
    std::cout << "Optimized " << matches_opt1.size() << " feature descriptors." << std::endl;
#endif
    
    // Now we search for the highest number of hits in our hit array
    // The variable max_idx keeps the image id.
    // The variable max_value the amount of hits.
    int max_idx = -1;
    int max_value = 0;
    for (int i=0; i<_num_ref_images; i++)
    {
#ifdef DEBUG_OUT
        std::cout << "for " << i << " : " << hits[i] << std::endl;
#endif
        if(hits[i]  > max_value)
        {
            max_value = hits[i];
            max_idx = i;
        }
    }
    
    
    
    ///////////////////////////////////////////////////////
    // 4. The cross-match
    // At this time, we test the database agains the query descriptors.
    // The variable max_id stores the reference image id. Thus, we test only
    // the descriptors that belong to max_idx agains the query descriptors.
    _matcher.knnMatch(_descriptorsRefDB[max_idx], descriptorQuery, matches2, 2);
    
    
    ///////////////////////////////////////////////////////
    // 5. Refinement; Ratio test
    // The ratio test only accept matches which are clear without ambiguity.
    // The best hit must be closer to the query descriptors than the second hit.
    int removed = ratioTest(matches_opt1);
#ifdef DEBUG_OUT
    std::cout << "Removed " << removed << " matched."  << std::endl;
#endif
    
    removed = ratioTest(matches2);
#ifdef DEBUG_OUT
    std::cout << "Removed " << removed << " matched."  << std::endl;
#endif
    
    ///////////////////////////////////////////////////////
    // 6. Refinement; Symmetry test
    // We only accept matches which appear in both knn-matches.
    // It should not matter whether we test the database against the query desriptors
    // or the query descriptors against the database.
    // If we do not find the same solution in both directions, we toss the match.
    std::vector<cv::DMatch> symMatches;
    symmetryTest(  matches_opt1, matches2, symMatches);
#ifdef DEBUG_OUT
    std::cout << "Kept " << symMatches.size() << " matches after symetry test test."  << std::endl;
#endif
    
    ///////////////////////////////////////////////////////
    // 7. Refinement; Epipolar constraint
    // We perform a Epipolar test using the RANSAC method.
    if(symMatches.size() > 25)
    {
        matches_out->clear();
        ransacTest( symMatches,  _keypointsRefDB[max_idx], keypointsQuery, *matches_out);
        
        
    }
    
#ifdef DEBUG_OUT
    std::cout << "Kept " << matches_out->size() << " matches after RANSAC test."  << std::endl;
#endif
    
    ///////////////////////////////////////////////////////
    // 8.  Draw this image on screen.
    cv::Mat out;
    cv::drawMatches(feature_map_database[max_idx]._ref_image , _keypointsRefDB[max_idx], query_image, keypointsQuery, *matches_out, out, cv::Scalar(255,255,255), cv::Scalar(0,0,255));
    
    std::string num_matches_str;
    std::strstream conv;
    conv << matches_out->size();
    conv >> num_matches_str;
    
    std::string text;
    text.append( num_matches_str);
    text.append("( " + _num_ref_features_in_db_str + " total)");
    text.append(" matches were found in reference image ");
    text.append( feature_map_database[max_idx]._ref_image_str);
    
    putText(out, text, cvPoint(20,20),
            cv::FONT_HERSHEY_COMPLEX_SMALL, 1.0, cvScalar(0,255,255), 1, CV_AA);
    
    cv::imshow("result", out);
    if (run_video) cv::waitKey(1);
    else cv::waitKey();
    
    
    
    // Delete the images
    query_image.release();
    out.release();
    
    
    
    return max_idx;
    
}
/*****************************************************************************
 // This applies a brute force match without a trained datastructure.
 // It also calculates the two nearest neigbors.
 // @paraam query_image: the input image
 // @param matches_out: a pointer that stores the output matches. It is necessary for
 //                     pose estimation.
 */
int brute_force_match(cv::Mat& query_image,  std::vector< cv::DMatch> * matches_out)
{
    
    // variabels that keep the query keypoints and query descriptors
    std::vector<cv::KeyPoint>           keypointsQuery;
    cv::Mat                             descriptorQuery;
    
    // Temporary variables for the matching results
    std::vector< std::vector< cv::DMatch> > matches1;
    std::vector< std::vector< cv::DMatch> > matches2;
    std::vector< std::vector< cv::DMatch> > matches_opt1;
    
    
    //////////////////////////////////////////////////////////////////////
    // 1. Detect the keypoints
    // This line detects keypoints in the query image
    _detector->detect(query_image, keypointsQuery);
    
    
    
    // If keypoints were found, descriptors are extracted.
    if(keypointsQuery.size() > 0)
    {
        // extract descriptors
        _extractor->compute( query_image, keypointsQuery, descriptorQuery);
        
    }
    
#ifdef DEBUG_OUT
    std::cout << "Found " << descriptorQuery.size() << " feature descriptors in the image."  << std::endl;
#endif
    
    
    //////////////////////////////////////////////////////////////////////////////
    // 2. Here we match the descriptors with all descriptors in the database
    // with k-nearest neighbors with k=2
    
    int max_removed = INT_MAX;
    int max_id = -1;
    
    for(int i=0; i<_descriptorsRefDB.size(); i++)
    {
        std::vector< std::vector< cv::DMatch> > matches_temp1;
        
        // Here we match all query descriptors agains all db descriptors and try to find
        // matching descriptors
        _brute_force_matcher.knnMatch( descriptorQuery, _descriptorsRefDB[i],  matches_temp1, 2);
        
        
        ///////////////////////////////////////////////////////
        // 3. Refinement; Ratio test
        // The ratio test only accept matches which are clear without ambiguity.
        // The best hit must be closer to the query descriptors than the second hit.
        int removed = ratioTest(matches_temp1);
        
        
        
        // We only accept the match with the highest number of hits / the vector with the minimum revmoved features
        int num_matches = matches_temp1.size();
        if(removed < max_removed)
        {
            max_removed = removed;
            max_id = i;
            matches1.clear();
            matches1 = matches_temp1;
        }
    }
    
#ifdef DEBUG_OUT
    std::cout << "Feature map number " << max_id << " has the highest hit with "<< matches1.size() -  max_removed << " descriptors." << std::endl;
#endif
    
    
    std::vector< std::vector< cv::DMatch> > matches_temp2;
    
    // Here we match all query descriptors agains all db descriptors and try to find
    // matching descriptors
    _brute_force_matcher.knnMatch(_descriptorsRefDB[max_id],  descriptorQuery,  matches_temp2, 2);
    
    // The ratio test only accept matches which are clear without ambiguity.
    // The best hit must be closer to the query descriptors than the second hit.
    int removed = ratioTest(matches_temp2);
    
    
    
    
    ///////////////////////////////////////////////////////
    // 6. Refinement; Symmetry test
    // We only accept matches which appear in both knn-matches.
    // It should not matter whether we test the database against the query desriptors
    // or the query descriptors against the database.
    // If we do not find the same solution in both directions, we toss the match.
    std::vector<cv::DMatch> symMatches;
    symmetryTest(  matches1, matches_temp2, symMatches);
#ifdef DEBUG_OUT
    std::cout << "Kept " << symMatches.size() << " matches after symetry test test."  << std::endl;
#endif
    
    ///////////////////////////////////////////////////////
    // 7. Refinement; Epipolar constraint
    // We perform a Epipolar test using the RANSAC method.
    if(symMatches.size() > 25)
    {
        matches_out->clear();
        ransacTest( symMatches,  _keypointsRefDB[max_id], keypointsQuery, *matches_out);
        
        
    }
    
#ifdef DEBUG_OUT
    std::cout << "Kept " << matches_out->size() << " matches after RANSAC test."  << std::endl;
#endif
    
    ///////////////////////////////////////////////////////
    // 8.  Draw this image on screen.
    cv::Mat out;
    cv::drawMatches(feature_map_database[max_id]._ref_image , _keypointsRefDB[max_id], query_image, keypointsQuery, *matches_out, out, cv::Scalar(255,255,255), cv::Scalar(0,0,255));
    
    std::string num_matches_str;
    std::strstream conv;
    conv << matches_out->size();
    conv >> num_matches_str;
    
    std::string text;
    text.append( num_matches_str);
    text.append("( " + _num_ref_features_in_db_str + " total)");
    text.append(" matches were found in reference image ");
    text.append( feature_map_database[max_id]._ref_image_str);
    
    putText(out, text, cvPoint(20,20),
            cv::FONT_HERSHEY_COMPLEX_SMALL, 1.0, cvScalar(0,255,255), 1, CV_AA);
    
    cv::imshow("result", out);
    if (run_video) cv::waitKey(1);
    else cv::waitKey();
    
    
    
    // Delete the images
    query_image.release();
    out.release();
    
    
    return max_id;
    
}
Example #11
0
// Match feature points using symmetry test and RANSAC
// returns fundemental matrix
cv::Mat RobustMatcher::match(cv::Mat &image1,
		cv::Mat& image2, // input image
		// output matches and keypoints
		std::vector<cv::DMatch> &matches, std::vector<cv::KeyPoint> &keypoints1,
		std::vector<cv::KeyPoint> &keypoints2) {

	// 1a. Detection of the SURF features
	helper->detectKeypoints(image1, keypoints1);
	helper->detectKeypoints(image2, keypoints2);

	// 1b. Extraction of the SURF descriptors
	cv::Mat descriptors1, descriptors2;
	extractor->compute(image1, keypoints1, descriptors1);
	extractor->compute(image2, keypoints2, descriptors2);

	//cout << "RobustMatcher: Keypoints 1: " << keypoints1.size() << endl;
	//cout << "RobustMatcher: Keypoints 2: " << keypoints2.size() << endl;

	// 2. Match the two image descriptors
	// Construction of the matcher
	cv::BruteForceMatcher<cv::L2<float> > matcher;

	// from image 1 to image 2
	// based on k neares neighbours (with k=2)
	std::vector<std::vector<cv::DMatch> > matches1;
	matcher.knnMatch(descriptors1, descriptors2, matches1, // vector of matches (up to 2 per entry)
			2); // returns 2 nearest neighbours

	// from image 2 to image 1
	// based on k nearest neighbours (with k=2)
	std::vector<std::vector<cv::DMatch> > matches2;
	matcher.knnMatch(descriptors2, descriptors1, matches2, // vector of matches (up to 2 per entry)
			2); // return 2 nearest neighbours

	//cout << "Matchtes in Bild 2: " << matches1.size() << endl;
	// 3. Remove matches for which NN ratio is > than threshold
	// clean image 1 -> image 2 matches
	int removed = ratioTest(matches1);

	//cout << "Ratio; Entfernte Matches Bild 2: " << removed << endl;

	//cout << "Matchtes in Bild 1: " << matches2.size() << endl;
	// clean image 2 -> image 1 matches
	removed = ratioTest(matches2);

	//cout << "Ratio; Entfernte Matches Bild 1: " << removed << endl;

	// 4. Remove non-symmetrical matches
	std::vector<cv::DMatch> symMatches;
	symmetryTest(matches1, matches2, symMatches);

	//cout << "Symmetrische Matches: " << symMatches.size() << endl;


	matches = symMatches;
	// 5. Validate matches using RANSAC
	cv::Mat fundemental = ransacTest(symMatches, keypoints1, keypoints2,
			matches);

	// return the found fundemental matrix
	//cv::Mat fundemental;
	return fundemental;
}