GSoC2011SfM  0.1
Google Summer of Code 2011: Structure from motion
D:/Travail/These/Determination caracteristiques camera/GSoC/SfM/src/TracksOfPoints.cpp
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 }
 All Classes Functions Variables