GSoC2011SfM  0.1
Google Summer of Code 2011: Structure from motion
D:/Travail/These/Determination caracteristiques camera/GSoC/SfM/src/MatcherSparseFlow.cpp
00001 #include "MatcherSparseFlow.h"
00002 
00003 #include <opencv2/imgproc/imgproc.hpp>
00004 #include <opencv2/video/tracking.hpp>
00005 #include <opencv2/calib3d/calib3d.hpp>
00006 #include <algorithm>
00007 
00008 
00009 #include "PointsMatcher.h"
00010 #include "PointsToTrack.h"
00011 #include "PointsToTrackWithImage.h"
00012 
00013 namespace OpencvSfM{
00014   using cv::Mat;
00015   using cv::Ptr;
00016   using std::vector;
00017   using cv::KeyPoint;
00018   using cv::DMatch;
00019   using cv::Size;
00020   using cv::Rect;
00021 
00022   MatcherSparseFlow::MatcherSparseFlow( 
00023     const cv::Ptr<cv::DescriptorMatcher>& matcher, double dist_allowed )
00024     : PointsMatcher( matcher )
00025   {
00026     max_distance_ = dist_allowed;
00027   };
00028   
00029   cv::Ptr<PointsMatcher> MatcherSparseFlow::clone( bool emptyTrainData )
00030   {
00031     P_MUTEX( thread_concurr );
00032     MatcherSparseFlow* outPointMatcher =
00033       new MatcherSparseFlow( matcher_->clone( emptyTrainData ), max_distance_ );
00034     if( !emptyTrainData )
00035       outPointMatcher->pointCollection_ = pointCollection_;
00036     V_MUTEX( thread_concurr );
00037 
00038     return outPointMatcher;
00039   };
00040   
00041   void MatcherSparseFlow::match( cv::Ptr<PointsToTrack> queryPoints,
00042       std::vector<cv::DMatch>& matches,
00043       const std::vector<cv::Mat>& masks )
00044   {
00045     //first match using classical matcher:
00046     //Ptr<PointsMatcher> simple_matcher = new PointsMatcher( this->matcher_->clone( true ) );
00047     //simple_matcher->add( queryPoints );
00048     //simple_matcher->match( pointCollection_[0], matches, masks );
00049     PointsMatcher::match( queryPoints,matches );
00050 
00051     P_MUTEX( thread_concurr );
00052 
00053 
00055     //Using fundamental function from OpenCV, improve the matches
00056 
00057     //First compute points matches:
00058     int size_match=matches.size( );
00059     Mat srcP( 1,size_match,CV_32FC2 );
00060     Mat destP( 1,size_match,CV_32FC2 );
00061     vector<uchar> status;
00062 
00063     //vector<KeyPoint> points1 = point_matcher->;
00064     for( int i = 0; i < size_match; i ++ ){
00065       const KeyPoint &key1 = pointCollection_[0]->getKeypoint(
00066         matches[ i ].trainIdx );
00067       const KeyPoint &key2 = queryPoints->getKeypoint(
00068         matches[ i ].queryIdx );
00069       srcP.at<float[ 2 ]>( 0,i )[ 0 ] = key1.pt.x;
00070       srcP.at<float[ 2 ]>( 0,i )[ 1 ] = key1.pt.y;
00071       destP.at<float[ 2 ]>( 0,i )[ 0 ] = key2.pt.x;
00072       destP.at<float[ 2 ]>( 0,i )[ 1 ] = key2.pt.y;
00073       status.push_back( 1 );
00074     }
00075     
00076     Mat fundam = cv::findFundamentalMat( srcP, destP, status, cv::FM_RANSAC, 1 );
00077 
00078     //refine the mathing :
00079     for( int i = 0; i < size_match; ++i ){
00080       if( status[ i ] == 0 )
00081       {
00082         status[ i ] = status[ --size_match ];
00083         status.pop_back( );
00084         matches[ i-- ] = matches[ size_match ];
00085         matches.pop_back( );
00086       }
00087     }
00088     //now using optical flow, improve this:
00089 
00090     const vector<KeyPoint>& keyPoints=pointCollection_[0]->getKeypoints( );
00091     const vector<KeyPoint>& keyPoints1=queryPoints->getKeypoints( );
00092     vector<cv::Point2f> keyPointsIn;
00093     vector<cv::Point2f> keyPointsOut;
00094     vector<float> error;
00095 
00096     cv::Mat img1 = pointCollection_[0]->getImage();
00097     cv::Mat img2 = queryPoints->getImage();
00098     CV_Assert( !img1.empty() && !img2.empty() );
00099     vector< int > corresponding_point;
00100 
00101     int nbIn = 0, nbOut = 0;
00102     for( size_t cpt = 0; cpt<keyPoints.size(); cpt++)
00103     {
00104       //is this keypoint in matches?
00105       int has_keypoint = -1;
00106 
00107       for( size_t cpt1 = 0; has_keypoint<0 && cpt1 < matches.size(); cpt1++ )
00108         has_keypoint = matches[ cpt1 ].trainIdx == cpt? cpt1 : -1;
00109 
00110       const KeyPoint &kp = keyPoints[cpt];
00111       bool point_added = false;
00112       if( has_keypoint<0 )
00113       {//TODO: find the closest point and set him the same displacement
00114 
00115         size_t nb_points = keyPoints.size();
00116         int idx_min = -1;
00117         float dist_min = 1e10;
00118         for(size_t i = 0; i<nb_points ; ++i)
00119         {
00120           if(cpt!=i)
00121           {
00122             const cv::KeyPoint& kp_i = keyPoints[i];
00123             float dist = sqrt( (kp.pt.x - kp_i.pt.x)*(kp.pt.x - kp_i.pt.x)
00124               + (kp.pt.y - kp_i.pt.y) * (kp.pt.y - kp_i.pt.y) );
00125             if( dist<dist_min )
00126             {//is this point in matches?
00127               has_keypoint = -1;
00128               for( size_t cpt2 = 0; has_keypoint<0 && cpt2 < matches.size(); cpt2++ )
00129                 has_keypoint = matches[ cpt2 ].trainIdx == i? cpt2 : -1;
00130 
00131               if( has_keypoint>0 )
00132               {
00133                 dist_min = dist;
00134                 idx_min = has_keypoint;
00135               }
00136             }
00137           }
00138         }
00139 
00140         if( idx_min>0 )
00141         {
00142           size_t pt_idx = matches[ idx_min ].trainIdx;
00143           size_t pt_idx1 = matches[ idx_min ].queryIdx;
00144           const KeyPoint &kp_src = keyPoints[ pt_idx ];
00145           const KeyPoint &kp_dest = keyPoints1[ pt_idx1 ];
00146           float dx = kp_dest.pt.x - kp_src.pt.x,
00147             dy = kp_dest.pt.y - kp_src.pt.y;
00148           //if( kp.pt.x + dx>0 && kp.pt.x + dx<img2.cols &&
00149           //  kp.pt.y + dy>0 && kp.pt.y + dy<img2.rows )
00150           {
00151             keyPointsOut.push_back( cv::Point2f(kp.pt.x + dx, kp.pt.y + dy) );
00152             point_added = true;
00153           }
00154         }
00155       }
00156       else
00157       {
00158         size_t pt_idx = matches[ has_keypoint ].queryIdx;
00159         const KeyPoint &kp1 = keyPoints1[ pt_idx ];
00160         keyPointsOut.push_back( cv::Point2f(kp1.pt.x, kp1.pt.y) );
00161         point_added = true;
00162       }
00163       if( point_added )
00164       {
00165         nbIn++;
00166         keyPointsIn.push_back( cv::Point2f(kp.pt.x, kp.pt.y) );
00167         corresponding_point.push_back( cpt );
00168       }
00169     }
00170     cv::calcOpticalFlowPyrLK(img1, img2, keyPointsIn, keyPointsOut,
00171       status, error, cv::Size(31,31),4, cv::TermCriteria(
00172       cv::TermCriteria::COUNT+cv::TermCriteria::EPS,30, 0.01),
00173       0.75, cv::OPTFLOW_USE_INITIAL_FLOW );
00174     queryPoints->free_descriptors( true );//descriptors are not needed now!
00175     
00176     std::vector<cv::DMatch> final_matches;
00177     //construct the DMatch vector (find the closest point in queryPoints)
00178     int idxPointsAdd = keyPoints1.size() - 1;
00179     vector<cv::KeyPoint> keypoints_to_add;
00180     vector< int > idx_to_add;
00181     for( size_t cpt = 0; cpt<keyPointsOut.size(); cpt++)
00182     {
00183       if( cpt>=status.size() || status[cpt]!=0 )
00184       {
00185         cv::Point2f& kp = keyPointsOut[ cpt ];
00186         size_t idx = queryPoints->getClosestKeypoint( kp );
00187         const cv::KeyPoint& kpClose = queryPoints->getKeypoint( idx );
00188         float dist = sqrt( (kpClose.pt.x - kp.x)*(kpClose.pt.x - kp.x)
00189           + (kpClose.pt.y - kp.y) * (kpClose.pt.y - kp.y) );
00190         if( dist<max_distance_ )
00191           final_matches.push_back( cv::DMatch(idx, corresponding_point[cpt], dist) );
00192       }
00193     }
00194 
00195     matches = final_matches;
00196     /*
00197     queryPoints->addKeypoints( keypoints_to_add );
00198     for( size_t cpt = 0; cpt<keypoints_to_add.size(); cpt++)
00199     {
00200       cv::KeyPoint& kp = keypoints_to_add[ cpt ];
00201       int idx_min = queryPoints->getClosestKeypoint( kp.pt );
00202       const cv::KeyPoint& kpClose = queryPoints->getKeypoint( idx_min );
00203       float dist = sqrt( (kpClose.pt.x - kp.pt.x)*(kpClose.pt.x - kp.pt.x)
00204         + (kpClose.pt.y - kp.pt.y) * (kpClose.pt.y - kp.pt.y) );
00205       if( dist<max_distance_ )
00206         matches.push_back( cv::DMatch(idx_min, idx_to_add[cpt], dist_min) );
00207     }*/
00208     V_MUTEX( thread_concurr );
00209   }
00210 
00211   void MatcherSparseFlow::knnMatch( cv::Ptr<PointsToTrack> queryPoints,
00212       std::vector<std::vector<cv::DMatch> >& matches, int k,
00213       const std::vector<cv::Mat>& masks, bool compactResult )
00214   {
00215     if( k!=1 )
00216       CV_Error( CV_StsError, "not yet implemented..." );
00217 
00218     vector<DMatch> matchesTmp;
00219     match( queryPoints, matchesTmp, masks );
00220     matches.push_back(matchesTmp);
00221   }
00222   
00223   void MatcherSparseFlow::radiusMatch( cv::Ptr<PointsToTrack> queryPoints,
00224     std::vector<std::vector<cv::DMatch> >& matches, float maxDistance,
00225       const std::vector<cv::Mat>& masks, bool compactResult )
00226   {
00227     double tmp = max_distance_;
00228     vector<DMatch> matchesTmp;
00229     match( queryPoints, matchesTmp, masks );
00230     matches.push_back(matchesTmp);
00231     max_distance_ = tmp;
00232   }
00233 
00234 }
 All Classes Functions Variables