GSoC2011SfM
0.1
Google Summer of Code 2011: Structure from motion
|
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 }