GSoC2011SfM
0.1
Google Summer of Code 2011: Structure from motion
|
00001 00002 #include "TracksOfPoints.h" 00003 00004 #include "PointsToTrack.h" 00005 #include "PointOfView.h" 00006 #include "Camera.h" 00007 00008 namespace OpencvSfM{ 00009 using cv::KeyPoint; 00010 using std::vector; 00011 using cv::Point3d; 00012 using cv::DMatch; 00013 using cv::Ptr; 00014 using cv::Mat; 00015 00016 inline void quickSort( vector<ImageLink>& outLinks, 00017 vector<int>& arr, int left, int right ) { 00018 int i = left, j = right; 00019 int tmp; 00020 int pivot = arr[ ( left + right ) / 2 ]; 00021 00022 /* partition */ 00023 while ( i <= j ) { 00024 while ( arr[ i ] < pivot ) 00025 i++; 00026 while ( arr[ j ] > pivot ) 00027 j--; 00028 if ( i < j ) { 00029 tmp = arr[ i ]; 00030 arr[ i ] = arr[ j ]; 00031 arr[ j ] = tmp; 00032 00033 ImageLink tmp1 = outLinks[ i ]; 00034 outLinks[ i ] = outLinks[ j ]; 00035 outLinks[ j ] = tmp1; 00036 00037 } 00038 if ( i <= j ) { 00039 i++; 00040 j--; 00041 } 00042 }; 00043 00044 /* recursion */ 00045 if ( left < j ) 00046 quickSort( outLinks, arr, left, j ); 00047 if ( i < right ) 00048 quickSort( outLinks, arr, i, right ); 00049 } 00050 00051 TrackOfPoints::~TrackOfPoints() 00052 { 00053 point3D.release(); 00054 } 00055 00056 bool TrackOfPoints::addMatch( const int image_src, const int point_idx1 ) 00057 { 00058 if( track_consistance<0 ) 00059 {//add to track to remember us about this problem.... 00060 images_indexes_.push_back( image_src ); 00061 point_indexes_.push_back( point_idx1 ); 00062 good_values.push_back(false); 00063 return false; 00064 } 00065 00066 //If a track contains more than one keypoint in the same image but 00067 //a different keypoint, it is deemed inconsistent. 00068 vector<unsigned int>::iterator indexImg = images_indexes_.begin( ); 00069 vector<unsigned int>::iterator end_iter = images_indexes_.end( ); 00070 unsigned int index=0; 00071 while( indexImg != end_iter ) 00072 { 00073 if ( *indexImg == image_src ) 00074 { 00075 if( point_indexes_[ index ] == point_idx1 ) 00076 { 00077 if( track_consistance>=0 ) 00078 track_consistance++; 00079 } 00080 else 00081 track_consistance=-1; 00082 00083 return track_consistance>=0; 00084 } 00085 index++; 00086 indexImg++; 00087 } 00088 00089 images_indexes_.push_back( image_src ); 00090 point_indexes_.push_back( point_idx1 ); 00091 good_values.push_back(true); 00092 return track_consistance>=0; 00093 } 00094 00095 void TrackOfPoints::fusionDuplicates( std::vector<TrackOfPoints>& tracks ) 00096 { 00097 //add to tracks_ the new matches: 00098 00099 size_t i = 0, 00100 match_it_end = tracks.size( ); 00101 00102 while ( i < match_it_end ) 00103 { 00104 TrackOfPoints &point_matcher = tracks[i]; 00105 00106 size_t j = i+1;//if j<i, already tested, and if i==j, don't have to... 00107 while ( j < match_it_end ) 00108 { 00109 TrackOfPoints &point_matcher1 = tracks[j]; 00110 //look for a commun point: 00111 bool have_commun = false; 00112 size_t nbT1 = point_matcher.point_indexes_.size(), 00113 nbT2 = point_matcher1.point_indexes_.size(); 00114 for(size_t i1 = 0; i1<nbT2 && !have_commun; ++i1 ) 00115 { 00116 00117 for(size_t j1 = 0; j1<nbT1 && !have_commun; ++j1 ) 00118 { 00119 have_commun = 00120 ( point_matcher1.images_indexes_[ i1 ] == 00121 point_matcher.images_indexes_[ j1 ] ) && 00122 ( point_matcher1.point_indexes_[ i1 ] == 00123 point_matcher.point_indexes_[ j1 ] ); 00124 } 00125 } 00126 if( have_commun ) 00127 { 00128 //should mix and remove this track: 00129 for(size_t i1 = 0; i1<nbT2 && !have_commun; ++i1 ) 00130 {//mix all points match: 00131 point_matcher.addMatch( point_matcher1.images_indexes_[ i1 ], 00132 point_matcher1.point_indexes_[ i1 ] ); 00133 } 00134 int R, G, B; 00135 R = (point_matcher1.color>>16) & 0x000000FF; 00136 G = (point_matcher1.color>>8) & 0x000000FF; 00137 B = (point_matcher1.color) & 0x000000FF; 00138 R += (point_matcher.color>>16) & 0x000000FF; 00139 G += (point_matcher.color>>8) & 0x000000FF; 00140 B += (point_matcher.color) & 0x000000FF; 00141 R /= 2; G /= 2; B /= 2; 00142 point_matcher.color = (unsigned int)( 00143 ((R<<16) & 0x00FF0000) | ((R<<8) & 0x0000FF00)| (B & 0x000000FF)); 00144 //remove this track: 00145 match_it_end--; 00146 tracks[ j ] = tracks[ match_it_end ]; 00147 tracks.pop_back(); 00148 j--; 00149 } 00150 j++; 00151 } 00152 i++; 00153 } 00154 } 00155 00156 bool TrackOfPoints::containPoint( const int image_src, 00157 const int point_idx1 ) const 00158 { 00159 //we don't use find here because we want the number instead of iterator... 00160 vector<unsigned int>::const_iterator indexImg = images_indexes_.begin( ); 00161 vector<unsigned int>::const_iterator end_iter = images_indexes_.end( ); 00162 unsigned int index=0; 00163 while( indexImg != end_iter ) 00164 { 00165 if ( *indexImg == image_src ) 00166 { 00167 if( point_indexes_[ index ] == point_idx1 ) 00168 return good_values[ index ]; 00169 } 00170 index++; 00171 indexImg++; 00172 } 00173 return false; 00174 } 00175 00176 DMatch TrackOfPoints::toDMatch( const int img1,const int img2 ) const 00177 { 00178 DMatch outMatch; 00179 char nbFound=0; 00180 //we don't use find here because we want the number instead of iterator... 00181 vector<unsigned int>::const_iterator indexImg = images_indexes_.begin( ); 00182 vector<unsigned int>::const_iterator end_iter = images_indexes_.end( ); 00183 unsigned int index=0; 00184 while( indexImg != end_iter ) 00185 { 00186 if ( *indexImg == img1 ) 00187 { 00188 nbFound++; 00189 outMatch.trainIdx = point_indexes_[ index ]; 00190 if( nbFound==2 ) 00191 return outMatch; 00192 } 00193 if ( *indexImg == img2 ) 00194 { 00195 nbFound++; 00196 outMatch.queryIdx = point_indexes_[ index ]; 00197 if( nbFound==2 ) 00198 return outMatch; 00199 } 00200 index++; 00201 indexImg++; 00202 } 00203 return outMatch; 00204 }; 00205 00206 void TrackOfPoints::getMatch( const unsigned int index, 00207 int &idImage, int &idPoint ) const 00208 { 00209 char nbFound=0; 00210 if( index < images_indexes_.size( ) ) 00211 { 00212 idImage = images_indexes_[ index ]; 00213 idPoint = point_indexes_[ index ]; 00214 } 00215 }; 00216 00217 double TrackOfPoints::errorEstimate( std::vector<PointOfView>& cameras, 00218 const std::vector< cv::Ptr< PointsToTrack > > &points_to_track, 00219 cv::Vec3d& points3D, const std::vector<bool> &masks) const 00220 { 00221 double distance=0.0; 00222 unsigned int nviews = images_indexes_.size( ); 00223 double real_views = 0.0; 00224 for ( unsigned int cpt = 0; cpt < nviews; cpt++ ) { 00225 int num_camera=images_indexes_[ cpt ]; 00226 int num_point=point_indexes_[ cpt ]; 00227 if(( masks.size() == 0 ) || ( cpt<masks.size() && masks[cpt] )) 00228 { 00229 cv::Ptr<PointsToTrack> points2D = points_to_track[ num_camera ]; 00230 00231 const KeyPoint& p=points2D->getKeypoint( num_point ); 00232 cv::Vec2d projP = cameras[ num_camera ].project3DPointIntoImage( points3D ); 00233 00234 //compute back-projection 00235 distance += sqrt( (p.pt.x-projP[ 0 ] )*( p.pt.x-projP[ 0 ] ) + 00236 ( p.pt.y-projP[ 1 ] )*( p.pt.y-projP[ 1 ] ) ); 00237 real_views++; 00238 } 00239 } 00240 return distance/real_views; 00241 } 00242 double TrackOfPoints::triangulateLinear( vector<PointOfView>& cameras, 00243 const std::vector< cv::Ptr< PointsToTrack > > &points_to_track, 00244 cv::Vec3d& points3D, const vector<bool> &masks ) 00245 { 00246 unsigned int nviews = 0; 00247 bool hasMask=false; 00248 unsigned int i; 00249 if( masks.size( )==images_indexes_.size( ) ) 00250 { 00251 for ( i=0; i<images_indexes_.size( ); ++i ) 00252 { 00253 if( masks[ i ]!=0 ) 00254 nviews++; 00255 } 00256 hasMask=true; 00257 }else 00258 { 00259 nviews = images_indexes_.size( ); 00260 } 00261 00262 Mat design = Mat::zeros( 3*nviews, 4 + nviews,CV_64FC1 ); 00263 unsigned int real_position=0; 00264 i = 0; 00265 for ( real_position = 0; real_position < images_indexes_.size( ); 00266 ++real_position ) { 00267 if( !hasMask || ( hasMask && masks[ real_position ]!=0 )) 00268 { 00269 int num_camera=images_indexes_[ real_position ]; 00270 int num_point=point_indexes_[ real_position ]; 00271 cv::Ptr<PointsToTrack> points2D = points_to_track[ num_camera ]; 00272 const KeyPoint& p=points2D->getKeypoint( num_point ); 00273 00274 design( cv::Range( 3*i,3*i+3 ), cv::Range( 0,4 )) = 00275 -cameras[ num_camera ].getProjectionMatrix( ); 00276 design.at<double>( 3*i + 0, 4 + i ) = p.pt.x; 00277 design.at<double>( 3*i + 1, 4 + i ) = p.pt.y; 00278 design.at<double>( 3*i + 2, 4 + i ) = 1.0; 00279 i++; 00280 } 00281 } 00282 Mat X_and_alphas; 00283 cv::SVD::solveZ( design, X_and_alphas ); 00284 00285 double scal_factor=X_and_alphas.at<double>( 3,0 ); 00286 points3D[ 0 ]=X_and_alphas.at<double>( 0,0 )/scal_factor; 00287 points3D[ 1 ]=X_and_alphas.at<double>( 1,0 )/scal_factor; 00288 points3D[ 2 ]=X_and_alphas.at<double>( 2,0 )/scal_factor; 00289 00290 //update the point 3D: 00291 if( point3D.empty( ) ) 00292 point3D = Ptr<cv::Vec3d>( new cv::Vec3d( points3D ) ); 00293 else 00294 *point3D = points3D; 00295 00296 return errorEstimate( cameras, points_to_track, points3D, masks ); 00297 } 00298 00299 double TrackOfPoints::triangulateRobust( std::vector<PointOfView>& cameras, 00300 const std::vector< cv::Ptr< PointsToTrack > > &points_to_track, 00301 cv::Vec3d& points3D, double reproj_error, 00302 const std::vector<bool> &masksValues ) 00303 { 00304 cv::RNG& rng = cv::theRNG( ); 00305 unsigned int nviews = images_indexes_.size( ); 00306 double distance=0, best_distance=1e20; 00307 vector<bool> masks; 00308 cv::Vec3d bestPoints3D; 00309 00310 int ptSize = 0; 00311 bool has_mask = masksValues.size( ) == nviews; 00312 if( has_mask ) 00313 { 00314 for ( unsigned int i=0; i<nviews; ++i ) 00315 { 00316 if( masksValues[ i ]!=0 ) 00317 ptSize++; 00318 } 00319 } 00320 else 00321 ptSize = nviews; 00322 00323 int num_iter=0, max_iter=ptSize - 1; 00324 for( num_iter=0; num_iter<max_iter; ++num_iter ) 00325 { 00326 masks.clear( ); 00327 int nb_vals=0; 00328 for ( unsigned int cpt = 0; cpt < nviews; cpt++ ) { 00329 bool valTmp = ( rng( 2 ) != 0 ); 00330 if( has_mask ) 00331 valTmp = valTmp & masksValues[ cpt ]; 00332 if( valTmp ) 00333 nb_vals++; 00334 masks.push_back( valTmp ); 00335 } 00336 while( nb_vals<2 ) 00337 { 00338 int valTmp = rng( nviews ); 00339 while( !( masks[ valTmp ] == 0 && 00340 ( !has_mask || masksValues[ valTmp ] ) ) ) 00341 { 00342 valTmp = (valTmp + 1) % nviews; 00343 } 00344 masks[ valTmp ] = 1; 00345 nb_vals++; 00346 } 00347 //create mask: 00348 distance = triangulateLinear( cameras, points_to_track, points3D, masks ); 00349 00350 if( distance < best_distance ) 00351 { 00352 //new best model... 00353 bestPoints3D = points3D; 00354 best_distance = distance; 00355 if( best_distance<reproj_error ) 00356 num_iter=nviews;//quit the loop! 00357 } 00358 } 00359 points3D = bestPoints3D; 00360 //update the point 3D: 00361 if( point3D.empty( ) ) 00362 point3D = Ptr<cv::Vec3d>( new cv::Vec3d( points3D ) ); 00363 else 00364 *point3D = points3D; 00365 return best_distance; 00366 } 00367 00368 void TrackOfPoints::removeOutliers( std::vector<PointOfView>& cameras, 00369 const std::vector< cv::Ptr< PointsToTrack > > &points_to_track, 00370 double reproj_error, std::vector<bool> *masksValues ) 00371 { 00372 unsigned int nviews = images_indexes_.size( ); 00373 00374 int ptSize = 0; 00375 if(masksValues == NULL) 00376 good_values.assign(nviews , true); 00377 else 00378 good_values = *masksValues; 00379 00380 int nb_vals=0; 00381 for ( unsigned int cpt = 0; cpt < nviews; cpt++ ) { 00382 if(good_values[cpt]) 00383 { 00384 int num_camera=images_indexes_[ cpt ]; 00385 int num_point=point_indexes_[ cpt ]; 00386 cv::Ptr<PointsToTrack> points2D = points_to_track[ num_camera ]; 00387 const KeyPoint& p=points2D->getKeypoint( num_point ); 00388 00389 //project 3D point: 00390 cv::Vec2d projP = cameras[ num_camera ].project3DPointIntoImage( *point3D ); 00391 00392 //compute error: 00393 double error = sqrt( (p.pt.x-projP[ 0 ] )*( p.pt.x-projP[ 0 ] ) + 00394 ( p.pt.y-projP[ 1 ] )*( p.pt.y-projP[ 1 ] ) ); 00395 00396 if(error>reproj_error) 00397 good_values[cpt] = false; 00398 } 00399 } 00400 } 00401 00402 void TrackOfPoints::keepTrackHavingImage( unsigned int idx_image, 00403 vector<TrackOfPoints>& tracks ) 00404 { 00405 unsigned int cpt = 0, 00406 end = tracks.size(); 00407 for(cpt = 0; cpt<end-1; ++cpt) 00408 { 00409 if( !tracks[cpt].containImage(idx_image) ) 00410 { 00411 tracks[cpt] = tracks[ end-1 ]; 00412 end--;tracks.pop_back(); 00413 cpt--; 00414 } 00415 } 00416 //last one: 00417 if( !tracks[cpt].containImage(idx_image) ) 00418 tracks.pop_back(); 00419 } 00420 00421 00422 void TrackOfPoints::mixTracks( const std::vector<TrackOfPoints>& list_tracks, 00423 std::vector<TrackOfPoints>* mixed_tracks ) 00424 { 00425 //add to mixed_tracks the new tracks from list_tracks who are not in mixed_tracks: 00426 vector<TrackOfPoints>::const_iterator track_it = list_tracks.begin( ); 00427 vector<TrackOfPoints>::const_iterator track_end = list_tracks.end( ); 00428 00429 unsigned int mixed_size = mixed_tracks->size(); 00430 00431 while ( track_it != track_end ) 00432 { 00433 const TrackOfPoints& track = ( *track_it ); 00434 00435 unsigned int cpt = 0; 00436 00437 bool is_found=false; 00438 while ( cpt<mixed_size && !is_found ) 00439 { 00440 TrackOfPoints& track1 = (*mixed_tracks)[ cpt ]; 00441 for(size_t i=0; i<track1.images_indexes_.size()&&!is_found; ++i) 00442 { 00443 if( track.containPoint( track1.images_indexes_[i], 00444 track1.point_indexes_[i]) )//the same keypoint is found! 00445 is_found = true; 00446 } 00447 cpt++; 00448 } 00449 00450 if( is_found ) 00451 { 00452 cpt--; 00453 TrackOfPoints& track1 = (*mixed_tracks)[ cpt ]; 00454 for(size_t i=0; i<track.images_indexes_.size()&&!is_found; ++i) 00455 {//check of consistency is done via addMatch... 00456 track1.addMatch( track.images_indexes_[i], 00457 track.point_indexes_[i] ); 00458 } 00459 } 00460 else 00461 mixed_tracks->push_back( track ); 00462 00463 track_it++; 00464 } 00465 } 00466 00467 void TrackOfPoints::keepTrackWithImages( const 00468 std::vector<int>& imgList, 00469 std::vector<TrackOfPoints>& tracks ) 00470 { 00471 std::vector<int> cpt_Link; 00472 unsigned int cpt = 0, cpt1 = 0, 00473 end = tracks.size(), 00474 endImgL = imgList.size(); 00475 cpt_Link.assign(end,0); 00476 for(cpt = 0; cpt<end; ++cpt) 00477 { 00478 for(cpt1 = 0; cpt1<endImgL; ++cpt1) 00479 { 00480 if( tracks[cpt].containImage(cpt1) ) 00481 { 00482 cpt_Link[cpt]++; 00483 } 00484 } 00485 } 00486 //remove bad tracks: 00487 cpt1 = 0; 00488 for(cpt = 0; cpt<end-1; ++cpt) 00489 { 00490 if( cpt_Link[cpt]<2 ) 00491 { 00492 tracks[cpt1] = tracks[ tracks.size()-1 ]; 00493 cpt1--;tracks.pop_back(); 00494 } 00495 cpt1++; 00496 } 00497 //last one: 00498 if( cpt_Link[cpt]<2 ) 00499 tracks.pop_back(); 00500 } 00501 00502 int ImagesGraphConnection::getHighestLink( int &first_image, int &second_image, 00503 int max_number ) 00504 { 00505 cv::SparseMatConstIterator 00506 it = images_graph_.begin( ), 00507 it_end = images_graph_.end( ); 00508 double s = 0; 00509 const int dims = 2; 00510 int max_value=0; 00511 for( ; it != it_end; ++it ) 00512 { 00513 int currentValue=it.value<int>( ); 00514 if( currentValue < max_number && currentValue > max_value ) 00515 { 00516 max_value = currentValue; 00517 const cv::SparseMat::Node* n = it.node( ); 00518 first_image = n->idx[ 0 ]; 00519 second_image = n->idx[ 1 ]; 00520 } 00521 } 00522 return max_value; 00523 } 00524 00525 00526 void ImagesGraphConnection::getOrderedLinks( std::vector<ImageLink>& outLinks, 00527 int min_number, int max_number ) 00528 { 00529 cv::SparseMatConstIterator 00530 it = images_graph_.begin( ), 00531 it_end = images_graph_.end( ); 00532 00533 std::vector<int> distance; 00534 double s = 0; 00535 const int dims = 2; 00536 for( ; it != it_end; ++it ) 00537 { 00538 int currentValue=it.value<int>( ); 00539 const cv::SparseMat::Node* n = it.node( ); 00540 if( currentValue <= max_number && currentValue >= min_number ) 00541 { 00542 ImageLink link; 00543 link.imgSrc = n->idx[ 0 ]; 00544 link.imgDest = n->idx[ 1 ]; 00545 outLinks.push_back( link ); 00546 distance.push_back( currentValue ); 00547 } 00548 } 00549 //order the list: 00550 quickSort( outLinks, distance, 0, distance.size( )-1 ); 00551 } 00552 00553 void ImagesGraphConnection::getImagesRelatedTo( int first_image, 00554 std::vector<ImageLink>& outList, int min_number, int max_number ) 00555 { 00556 int it = 0, 00557 it_end = images_graph_.size( )[ 0 ]; 00558 for( ; it < first_image; ++it ) 00559 { 00560 uchar* currentValue=images_graph_.ptr( it, first_image, false ); 00561 if( currentValue != NULL ) 00562 { 00563 //we have a value here... Are there enough links: 00564 int &val = * reinterpret_cast<int*>( currentValue ); 00565 if( val > min_number && val < max_number ) 00566 { 00567 //it's a new link, add it: 00568 ImageLink link; 00569 link.imgSrc = it; 00570 link.imgDest = first_image; 00571 outList.push_back( link ); 00572 } 00573 } 00574 } 00575 ++it;//skip the diagonal 00576 for( ; it < it_end; ++it ) 00577 { 00578 uchar* currentValue=images_graph_.ptr( first_image, it, false ); 00579 if( currentValue != NULL ) 00580 { 00581 //we have a value here... Are there enough links: 00582 int &val = * reinterpret_cast<int*>( currentValue ); 00583 if( val > min_number && val < max_number ) 00584 { 00585 //it's a new link, add it: 00586 ImageLink link; 00587 link.imgSrc = first_image; 00588 link.imgDest = it; 00589 outList.push_back( link ); 00590 } 00591 } 00592 } 00593 00594 } 00595 }