GSoC2011SfM  0.1
Google Summer of Code 2011: Structure from motion
D:/Travail/These/Determination caracteristiques camera/GSoC/SfM/src/PointsMatcher.cpp
00001 
00002 #include "macro.h" //SFM_EXPORTS
00003 
00004 #include <opencv2/imgproc/imgproc.hpp>
00005 #include <opencv2/video/tracking.hpp>
00006 #include <algorithm>
00007 
00008 #include "PointsMatcher.h"
00009 #include "PointsToTrack.h"
00010 
00011 namespace OpencvSfM{
00012   using cv::Mat;
00013   using cv::Ptr;
00014   using std::vector;
00015   using cv::KeyPoint;
00016   using cv::DMatch;
00017   using cv::Size;
00018   using cv::Rect;
00019 
00020   PointsMatcher::PointsMatcher( const cv::Ptr<cv::DescriptorMatcher>& matcher )
00021   {
00022     CV_DbgAssert( !matcher.empty( ) );
00023     matcher_ = matcher;
00024     INIT_MUTEX( thread_concurr );
00025   }
00026 
00027   PointsMatcher::PointsMatcher( )
00028   {
00029     matcher_ = NULL;
00030     INIT_MUTEX( thread_concurr );
00031   }
00032 
00033   PointsMatcher::PointsMatcher( const PointsMatcher& copy )
00034   {
00035     INIT_MUTEX( thread_concurr );
00036     pointCollection_=copy.pointCollection_;
00037     matcher_ = copy.matcher_->clone( true );
00038   }
00039 
00040   PointsMatcher::~PointsMatcher( void )
00041   {
00042     //matcher_ is freed thanks to cv::Ptr
00043     //idem for pointCollection_
00044   }
00045   const cv::KeyPoint &PointsMatcher::getKeypoint( int numKey ) const
00046   {
00047     CV_DbgAssert( pointCollection_.size( )>0 );
00048     return pointCollection_[ 0 ]->getKeypoint( numKey );
00049   }
00050 
00051   void PointsMatcher::add( Ptr<PointsToTrack> pointCollection )
00052   {
00053     P_MUTEX( thread_concurr );
00054     pointCollection_.push_back( pointCollection );
00055     V_MUTEX( thread_concurr );
00056   }
00057 
00058   void PointsMatcher::clear( )
00059   {
00060     P_MUTEX( thread_concurr );
00061     matcher_->clear( );
00062     /*
00063     for(size_t i = 0; i<pointCollection_.size(); ++i)
00064       pointCollection_[i]->free_descriptors();
00065       */
00066     V_MUTEX( thread_concurr );
00067   }
00068 
00069   void PointsMatcher::train( )
00070   {
00071     P_MUTEX( thread_concurr );
00072     matcher_->clear( );
00073 
00074     vector<Mat> pointsDesc;
00075     Ptr<PointsToTrack> pointCollection;
00076     vector< Ptr< PointsToTrack > >::iterator it =
00077       pointCollection_.begin( ),
00078       it_end = pointCollection_.end( );
00079     while( it != it_end )
00080     {
00081       pointCollection = *it;
00082       pointCollection->computeKeypointsAndDesc( false );
00083 
00084       pointsDesc.push_back( pointCollection->getDescriptors( ) );
00085 
00086       pointCollection->free_descriptors();//save memory...
00087 
00088       it++;
00089     }
00090 
00091 
00092     matcher_->add( pointsDesc );
00093     matcher_->train( );
00094     V_MUTEX( thread_concurr );
00095   }
00096 
00097   bool PointsMatcher::isMaskSupported( )
00098   {
00099     return matcher_->isMaskSupported( );
00100   }
00101 
00102   void PointsMatcher::match( cv::Ptr<PointsToTrack> queryPoints,
00103     std::vector<cv::DMatch>& matches,
00104     const std::vector<cv::Mat>& masks )
00105   {
00106     train( );
00107 
00108     P_MUTEX( thread_concurr );
00109     queryPoints->computeKeypointsAndDesc( false );
00110 
00111     vector<KeyPoint> keyPoints=queryPoints->getKeypoints( );
00112     Mat descMat=queryPoints->getDescriptors( );
00113 
00114     CV_DbgAssert( !keyPoints.empty( ) );
00115     CV_DbgAssert( !descMat.empty( ) );
00116 
00117     matcher_->match( descMat, matches, masks );
00118     V_MUTEX( thread_concurr );
00119 
00120     queryPoints->free_descriptors();
00121   }
00122 
00123   void PointsMatcher::knnMatch(  Ptr<PointsToTrack> queryPoints,
00124     vector<vector<DMatch> >& matches, int knn,
00125     const vector<Mat>& masks, bool compactResult )
00126   {
00127     train( );
00128 
00129     P_MUTEX( thread_concurr );
00130     queryPoints->computeKeypointsAndDesc( false );
00131 
00132     vector<KeyPoint> keyPoints=queryPoints->getKeypoints( );
00133     Mat descMat=queryPoints->getDescriptors( );
00134 
00135     CV_DbgAssert( !keyPoints.empty( ) );
00136     CV_DbgAssert( !descMat.empty( ) );
00137 
00138     matcher_->knnMatch( descMat, matches, knn, masks, compactResult );
00139     V_MUTEX( thread_concurr );
00140 
00141     queryPoints->free_descriptors();
00142   }
00143 
00144   void PointsMatcher::radiusMatch( cv::Ptr<PointsToTrack> queryPoints,
00145     vector<vector<DMatch> >& matches, float maxDistance,
00146     const vector<Mat>& masks, bool compactResult )
00147   {
00148     train( );
00149 
00150     P_MUTEX( thread_concurr );
00151     queryPoints->computeKeypointsAndDesc( false );
00152 
00153     vector<KeyPoint> keyPoints=queryPoints->getKeypoints( );
00154     Mat descMat=queryPoints->getDescriptors( );
00155 
00156     CV_DbgAssert( !keyPoints.empty( ) );
00157     CV_DbgAssert( !descMat.empty( ) );
00158 
00159     matcher_->radiusMatch( descMat, matches, maxDistance, masks, compactResult );
00160     V_MUTEX( thread_concurr );
00161 
00162     queryPoints->free_descriptors();
00163   }
00164 
00165   bool PointsMatcher::empty( ) const
00166   {
00167     return pointCollection_.empty( ) ||  matcher_->empty( );
00168   }
00169 
00170   Ptr<PointsMatcher> PointsMatcher::clone( bool emptyTrainData )
00171   {
00172     P_MUTEX( thread_concurr );
00173     Ptr<PointsMatcher> outPointMatcher=new PointsMatcher( matcher_->clone( emptyTrainData ) );
00174     if( !emptyTrainData )
00175       outPointMatcher->pointCollection_=pointCollection_;
00176     V_MUTEX( thread_concurr );
00177 
00178     return outPointMatcher;
00179   }
00180 
00181   void PointsMatcher::crossMatch( Ptr<PointsMatcher> otherMatcher,
00182     vector<DMatch>& matches,
00183     const std::vector<cv::Mat>& masks )
00184   {
00185     train( );
00186 
00187     //TODO: for now this function only work with matcher having only one picture
00188     CV_DbgAssert( this->pointCollection_.size( )==1 );
00189     CV_DbgAssert( otherMatcher->pointCollection_.size( )==1 );
00190 
00191     if( matches.empty( ) )
00192     {
00193       //as we don't have matches for img1 -> img2, compute them:
00194       this->match( otherMatcher->pointCollection_[ 0 ], matches, masks );
00195     }
00196 
00197 
00198     //now construct the vector of DMatch, but in the other way ( 2 -> 1 ):
00199     vector<DMatch> matchesOtherWay;
00200     P_MUTEX( thread_concurr );
00201     otherMatcher->match( pointCollection_[ 0 ], matchesOtherWay, masks );
00202     V_MUTEX( thread_concurr );
00203 
00204     //now check for reciprocity:
00205     size_t nbPoints = matches.size( ),
00206       nbPoints1 = matchesOtherWay.size( );
00207     for( size_t i=0; i<nbPoints; i++ )
00208     {
00209       DMatch d1=matches[ i ];
00210       bool found = false;
00211       for( size_t j=0; j<nbPoints1 && !found ; ++j )
00212       {
00213         DMatch d2=matchesOtherWay[ j ];
00214         found = (d1.trainIdx == d2.queryIdx) && (d1.queryIdx == d2.trainIdx);
00215       }
00216       if( !found )
00217       {
00218         //remove the current match!
00219         nbPoints--;//because we have a match less!
00220         matches[ i ]=matches[ nbPoints ];
00221         matches.pop_back( );
00222         i--;//because we have to retest ith point!
00223       }
00224     }
00225     matchesOtherWay.clear( );
00226   }
00227   void PointsMatcher::drawMatches( const Mat& img1,
00228     const vector<cv::KeyPoint>& keypoints1,
00229     const vector<cv::KeyPoint>& keypoints2,
00230     const vector<cv::DMatch>& matches1to2, Mat& outImg,
00231     const cv::Scalar& matchColor, const cv::Scalar& singlePointColor,
00232     const std::vector<char>& matchesMask, int flags )
00233   {
00234     Size size( img1.cols, img1.rows );
00235     if( flags & cv::DrawMatchesFlags::DRAW_OVER_OUTIMG )
00236     {
00237       if( size.width > outImg.cols || size.height > outImg.rows )
00238         CV_Error( CV_StsBadSize, "outImg has size less than needed to draw img1" );
00239     }
00240     else
00241     {
00242       outImg.create( size, CV_MAKETYPE( img1.depth( ), 3 ) );
00243 
00244       if( img1.type( ) == CV_8U )
00245         cv::cvtColor( img1, outImg, CV_GRAY2BGR );
00246       else
00247         img1.copyTo( outImg );
00248     }
00249 
00250     // draw keypoints
00251     if( !( flags & cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ) )
00252     {
00253       drawKeypoints( outImg, keypoints1, outImg, singlePointColor,
00254         flags + cv::DrawMatchesFlags::DRAW_OVER_OUTIMG );
00255     }
00256 
00257     cv::RNG& rng = cv::theRNG( );
00258     bool isRandMatchColor = matchColor == cv::Scalar::all( -1 );
00259     vector<DMatch>::size_type total_size=matches1to2.size( );
00260     // draw matches
00261     for( vector<DMatch>::size_type m = 0; m < total_size; m++ )
00262     {
00263       int i1 = matches1to2[ m ].trainIdx;
00264       int i2 = matches1to2[ m ].queryIdx;
00265       if( matchesMask.empty( ) || matchesMask[ m ] )
00266       {
00267         const KeyPoint &kp1 = keypoints1[ i1 ], &kp2 = keypoints2[ i2 ];
00268 
00269         cv::Scalar color = isRandMatchColor ?
00270           cv::Scalar( rng( 256 ), rng( 256 ), rng( 256 ) ) : matchColor;
00271 
00272         cv::Point center1( cvRound( kp1.pt.x ), cvRound( kp1.pt.y ) );
00273         cv::Point center2( cvRound( kp2.pt.x ), cvRound( kp2.pt.y ) );
00274         int radius = 1;
00275         cv::circle( outImg, center1, radius, color, 1, CV_AA );
00276         //cv::circle( outImg, center2, radius, color, 1, CV_AA );
00277         cv::line( outImg, center1, center2, color, 1, CV_AA );
00278       }
00279     }
00280 
00281   }
00282 
00283 
00284   void PointsMatcher::read( const cv::FileNode& node,
00285     PointsMatcher& points )
00286   {
00287     std::string myName=node.name( );
00288     if( myName != "PointsMatcher" )
00289       return;//this node is not for us...
00290 
00291     //This matcher need only point coordinates as the matcher is already loaded:
00292 
00293     if( node.empty( ) || !node.isSeq( ) )
00294       CV_Error( CV_StsError, "PointsMatcher FileNode is not correct!" );
00295 
00296     int numImg=0;
00297     cv::FileNodeIterator it = node.begin( ), it_end = node.end( );
00298     while( it != it_end )
00299     {
00300       Ptr<PointsToTrack> ptt_tmp = Ptr<PointsToTrack>( new PointsToTrack( numImg ));
00301       cv::FileNode node_tmp = ( *it )[ "PointsToTrack" ];
00302       PointsToTrack::read( node_tmp, *ptt_tmp );
00303       points.pointCollection_.push_back( ptt_tmp );
00304       it++;
00305       numImg++;
00306     }
00307   }
00308 
00309   void PointsMatcher::write ( cv::FileStorage& fs,
00310     const PointsMatcher& points )
00311   {
00312     vector<PointsToTrack>::size_type key_size = points.pointCollection_.size( );
00313 
00314     fs << "PointsMatcher" << "[";
00315 
00316     for ( vector<PointsToTrack>::size_type i=0; i < key_size; i++ )
00317     {
00318       PointsToTrack::write( fs, *points.pointCollection_[ i ] );
00319     }
00320     fs << "]";
00321   }
00322 
00323   
00324   PointsMatcherOpticalFlow::PointsMatcherOpticalFlow( std::string name_of_algo,
00325     double dist_allowed )
00326   {
00327     transform(name_of_algo.begin(), name_of_algo.end(),
00328       name_of_algo.begin(),tolower);
00329     id_algo = 0;
00330     max_distance = dist_allowed;
00331 
00332     if( name_of_algo == "opticalflowpyrlk" )
00333       id_algo = 1;
00334     if( name_of_algo == "opticalflowfarneback" )
00335       id_algo = 2;
00336     if( name_of_algo == "opticalflowbm" )
00337       id_algo = 3;
00338     if( name_of_algo == "opticalflowhs" )
00339       id_algo = 4;
00340     if( name_of_algo == "opticalflowlk" )
00341       id_algo = 5;
00342   }
00343 
00344   void PointsMatcherOpticalFlow::clear( )
00345   {
00346     //nothing to do...
00347   }
00348 
00349   void PointsMatcherOpticalFlow::train( )
00350   {
00351     //nothing to do...
00352   }
00353 
00354   bool PointsMatcherOpticalFlow::isMaskSupported( )
00355   {
00356     return false;
00357   }
00358 
00359   void PointsMatcherOpticalFlow::match( cv::Ptr<PointsToTrack> queryPoints,
00360     std::vector<cv::DMatch>& matches,
00361     const std::vector<cv::Mat>& masks )
00362   {
00363     P_MUTEX( thread_concurr );
00364 
00365     if(pointCollection_[0]->getKeypoints( ).empty())
00366       pointCollection_[0]->computeKeypoints();
00367     const vector<KeyPoint>& keyPoints=pointCollection_[0]->getKeypoints( );
00368     vector<cv::Point2f> keyPointsIn;
00369     vector<cv::Point2f> keyPointsOut;
00370     vector<uchar> status;
00371     vector<float> error;
00372 
00373     cv::Mat img1 = pointCollection_[0]->getImage();
00374     cv::Mat img2 = queryPoints->getImage();
00375     CV_Assert( !img1.empty() && !img2.empty()  );
00376 
00377     for( size_t cpt = 0; cpt<keyPoints.size(); cpt++)
00378     {
00379       const KeyPoint &kp = keyPoints[cpt];
00380       keyPointsIn.push_back( cv::Point2f(kp.pt.x, kp.pt.y) );
00381     }
00382 
00383     switch( id_algo )
00384     {
00385     case 1://1:  OpticalFlowPyrLK
00386       cv::calcOpticalFlowPyrLK(img1, img2, keyPointsIn, keyPointsOut,
00387         status, error );
00388       break;/*
00389     case 2://2:  OpticalFlowFarneback
00390       cv::OpticalFlowFarneback(img1, img2, keyPointsIn, keyPointsOut,
00391         status, error );
00392       break;
00393     case 3://3:  OpticalFlowBM
00394       cv::OpticalFlowBM(img1, img2, keyPointsIn, keyPointsOut,
00395         status, error );
00396       break;
00397     case 4://4:  OpticalFlowHS
00398       cv::OpticalFlowHS(img1, img2, keyPointsIn, keyPointsOut,
00399         status, error );
00400       break;
00401     case 5://5:  OpticalFlowLK
00402       cv::OpticalFlowLK(img1, img2, keyPointsIn, keyPointsOut,
00403         status, error );
00404       break;
00405     default:;*/
00406     }
00407 
00408     //construct the DMatch vector (find the closest point in queryPoints)
00409     if(queryPoints->getKeypoints( ).empty())
00410       queryPoints->computeKeypoints();
00411     const vector< KeyPoint >& points = queryPoints->getKeypoints();
00412     for( size_t cpt = 0; cpt<keyPointsOut.size(); cpt++)
00413     {
00414       if( status[cpt]!=0 )
00415       {
00416         float dist_min = 1e10;
00417         int idx_min = 0;
00418         for(size_t i = 0; i<points.size() ; ++i)
00419         {
00420           const cv::KeyPoint& kp = points[i];
00421           float dist = sqrt( (keyPointsOut[cpt].x - kp.pt.x)*(keyPointsOut[cpt].x - kp.pt.x)
00422             + (keyPointsOut[cpt].y - kp.pt.y)*(keyPointsOut[cpt].y - kp.pt.y) );
00423           if(dist<dist_min)
00424           {
00425             dist_min = dist;
00426             idx_min = i;
00427           }
00428         }
00429         if( dist_min<max_distance )
00430         matches.push_back( cv::DMatch(idx_min, cpt, dist_min) );//not really the correct dist...
00431       }
00432     }
00433     V_MUTEX( thread_concurr );
00434   }
00435 
00436   void PointsMatcherOpticalFlow::knnMatch(  Ptr<PointsToTrack> queryPoints,
00437     vector<vector<DMatch> >& matches, int knn,
00438     const vector<Mat>& masks, bool compactResult )
00439   {
00440     if( knn!=1 )
00441       CV_Error( CV_StsError, "not yet implemented..." );
00442 
00443     vector<DMatch> matchesTmp;
00444     match( queryPoints, matchesTmp, masks );
00445     matches.push_back(matchesTmp);
00446   }
00447 
00448   void PointsMatcherOpticalFlow::radiusMatch( cv::Ptr<PointsToTrack> queryPoints,
00449     vector<vector<DMatch> >& matches, float maxDistance,
00450     const vector<Mat>& masks, bool compactResult )
00451   {
00452     double tmp = max_distance;
00453     vector<DMatch> matchesTmp;
00454     match( queryPoints, matchesTmp, masks );
00455     matches.push_back(matchesTmp);
00456     max_distance = tmp;//restore the old value of max_distance
00457   }
00458 
00459   bool PointsMatcherOpticalFlow::empty( ) const
00460   {
00461     return pointCollection_.empty( );
00462   }
00463 
00464   Ptr<PointsMatcher> PointsMatcherOpticalFlow::clone( bool emptyTrainData )
00465   {
00466     P_MUTEX( thread_concurr );
00467     PointsMatcherOpticalFlow* outPointMatcher =
00468       new PointsMatcherOpticalFlow( "void" );
00469     outPointMatcher->id_algo = this->id_algo;
00470     if( !emptyTrainData )
00471       outPointMatcher->pointCollection_ = pointCollection_;
00472     V_MUTEX( thread_concurr );
00473 
00474     return outPointMatcher;
00475   }
00476 
00477 }
 All Classes Functions Variables