contrib/oxl/mvl/mvl_multi_view_matches.cxx
Go to the documentation of this file.
00001 // This is oxl/mvl/mvl_multi_view_matches.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 
00006 #include "mvl_multi_view_matches.h"
00007 
00008 #include <vcl_cassert.h>
00009 #include <vcl_cstdlib.h> // for vcl_abort()
00010 #include <vcl_set.h>
00011 #include <vcl_functional.h>
00012 #include <vcl_fstream.h>
00013 
00014 #include <vul/vul_awk.h>
00015 
00016 mvl_multi_view_matches::mvl_multi_view_matches(char const* filename)
00017 {
00018   read(filename);
00019 }
00020 
00021 mvl_multi_view_matches::mvl_multi_view_matches(vcl_vector<int> const& views)
00022 {
00023   set_views(views);
00024 }
00025 
00026 mvl_multi_view_matches::mvl_multi_view_matches(int start, int end, int step)
00027 {
00028   set_views(start,end,step);
00029 }
00030 
00031 mvl_multi_view_matches::mvl_multi_view_matches(int N)
00032 {
00033   set_views(N);
00034 }
00035 
00036 
00037 mvl_multi_view_matches::~mvl_multi_view_matches()
00038 {
00039 }
00040 
00041 void mvl_multi_view_matches::set_views(vcl_vector<int> const& views)
00042 {
00043   views_ = views;
00044   init();
00045 }
00046 
00047 void mvl_multi_view_matches::set_views(int start, int end, int step)
00048 {
00049   views_.clear();
00050   for (int i=start; i <= end; i+=step)
00051     views_.push_back(i);
00052   init();
00053 }
00054 
00055 void mvl_multi_view_matches::set_views(int N)
00056 {
00057   views_.clear();
00058   for (int i=0; i < N; ++i)
00059     views_.push_back(i);
00060   init();
00061 }
00062 
00063 void mvl_multi_view_matches::init()
00064 {
00065   view_to_internal_map_.clear();
00066   for (unsigned i=0; i < views_.size(); ++i)
00067     view_to_internal_map_[views_[i]] = i;
00068 
00069   corner_to_track_maps_ = vcl_vector<Map> (views_.size());
00070   tracks_.clear();
00071 }
00072 
00073 void mvl_multi_view_matches::add_pair(int view1, int corner1, int view2, int corner2)
00074 {
00075   vcl_vector<int> views(2);
00076   vcl_vector<int> corners(2);
00077   views[0] = view1;
00078   views[1] = view2;
00079   corners[0] = corner1;
00080   corners[1] = corner2;
00081   add_track(views, corners);
00082 }
00083 
00084 void mvl_multi_view_matches::add_triplet(int view1, int corner1, int view2, int corner2, int view3, int corner3)
00085 {
00086   vcl_vector<int> views(3);
00087   vcl_vector<int> corners(3);
00088   views[0] = view1;
00089   views[1] = view2;
00090   views[2] = view3;
00091   corners[0] = corner1;
00092   corners[1] = corner2;
00093   corners[2] = corner3;
00094   add_track(views, corners);
00095 }
00096 
00097 void mvl_multi_view_matches::add_track(vcl_vector<int> const& views, vcl_vector<int> const& corners)
00098 {
00099   assert(views.size() == corners.size());
00100 
00101   // gcc hack. It complains spuriously "`Map' is not an aggregate typedef" when
00102   // seeing this type on line 132. Making a typedef here gets around it. -- fsm
00103   typedef Map::iterator Map_iterator;
00104 
00105   int track_length = views.size();
00106 
00107   vcl_vector<int> internal_frames(track_length);
00108 
00109   // Map the given real views to our internal frame indices
00110   for (int i=0; i < track_length; ++i) {
00111     Map_iterator m = view_to_internal_map_.find(views[i]);
00112     if (m == view_to_internal_map_.end()) {
00113       vcl_cerr << __FILE__ << " : view specified outside range!\n";
00114       vcl_abort();
00115     }
00116     internal_frames[i] = (*m).second;  // holds the internal-frame index corresponding to given corner[i]
00117   }
00118 
00119   // Make a new track
00120   Map new_track;
00121   for (int i=0; i < track_length; ++i) {
00122     new_track[internal_frames[i]] = corners[i];
00123   }
00124   // Now see if this track shares any <frame,corner> with any existing tracks
00125   vcl_set<unsigned int, vcl_less<unsigned int> > friend_tracks;
00126   {
00127     for (int i=0; i < track_length; ++i) {
00128       Map_iterator m=corner_to_track_maps_[internal_frames[i]].find(corners[i]);
00129       if (m != corner_to_track_maps_[internal_frames[i]].end()) {
00130         if ((*m).second >= tracks_.size()) {
00131           vcl_cerr << __FILE__ << " : URK!" << internal_frames[i] << ' '
00132                    << corners[i] << ' ' << (*m).second << ' ' << tracks_.size() << vcl_endl;
00133           vcl_abort();
00134         }
00135         friend_tracks.insert((*m).second);
00136       }
00137     }
00138   }
00139 
00140   if (friend_tracks.empty()) {
00141     // No merging is necessary, so just add the brand new track to the back of the list
00142     tracks_.push_back(new_track);
00143     update_maps(tracks_.size() - 1);
00144   }
00145   else {
00146     // We have found one or more overlapping tracks, so try to merge them into the new track.
00147     // A set of tracks is consistent if they are identical in all non-wildcard (empty) positions
00148     bool consistency_okay = true;
00149     vcl_set<unsigned int, vcl_less<unsigned int> >::iterator t=friend_tracks.begin();
00150     for ( ; t != friend_tracks.end() && consistency_okay; ++t) {
00151       Map& friend_track = tracks_[(*t)];
00152       // See if friend_track[t] is consistent with the new track
00153       for (Map_iterator i = new_track.begin(); i != new_track.end() && consistency_okay; ++i) {
00154         unsigned int frame = (*i).first;
00155         unsigned int corner = (*i).second;
00156         Map_iterator m = friend_track.find(frame);
00157         if (m != friend_track.end() && (*m).second != corner) consistency_okay = false;
00158       }
00159       if (consistency_okay) {
00160         // Okay, we're good to merge friend_track[t] into the new track
00161         for (Map_iterator tp = friend_track.begin(); tp != friend_track.end(); ++tp)
00162           new_track.insert(*tp);
00163       }
00164     }
00165     // All friend tracks are now merged into new track, or inconsistency has been found
00166     if (consistency_okay) {
00167       // The new track can now replace friend_track[0], and the other friend tracks can be shuffle-removed
00168       // by moving the last track into the vacated position in track list. We must use a reverse iterator here
00169       // just in case the last track is one of those which has just been merged into the new track.
00170       int merged_track_index = *(friend_tracks.begin());
00171       friend_tracks.erase(merged_track_index);
00172       tracks_[merged_track_index] = new_track;
00173       update_maps(merged_track_index);
00174 
00175       vcl_set<unsigned int, vcl_less<unsigned int> >::reverse_iterator track_iterator = friend_tracks.rbegin();
00176       for ( ; !(track_iterator == friend_tracks.rend()); ++track_iterator) {
00177         unsigned int dead_track_index = (*track_iterator);
00178         if (dead_track_index+1 != tracks_.size()) {   // Don't try to shuffle the final track into itself
00179           tracks_[dead_track_index] = tracks_.back();
00180           update_maps(dead_track_index);
00181         }
00182         tracks_.pop_back();
00183       }
00184     }
00185     else {
00186       // URK! The tracks pass different corners in the same frame!
00187       // No choice, but to throw out the new track and all its friend_tracks.
00188       vcl_set<unsigned int, vcl_less<unsigned int> >::reverse_iterator track_iterator = friend_tracks.rbegin();
00189       for ( ; !(track_iterator == friend_tracks.rend()); ++track_iterator) {
00190         unsigned int dead_track_index = (*track_iterator);
00191         remove_maps(dead_track_index);
00192         if (dead_track_index+1 != tracks_.size()) {   // Don't try to shuffle the final track into itself
00193           tracks_[dead_track_index] = tracks_.back();
00194           update_maps(dead_track_index);
00195         }
00196         tracks_.pop_back();
00197       }
00198     }
00199   }
00200 }
00201 
00202 void mvl_multi_view_matches::add_matches(mvl_multi_view_matches const& /*matches*/)
00203 {
00204   vcl_cerr << __FILE__ ": mvl_multi_view_matches::add_matches() not implemented\n";
00205   vcl_abort();
00206 }
00207 
00208 void mvl_multi_view_matches::update_maps(int track_index)
00209 {
00210   for (Map::iterator i = tracks_[track_index].begin(); i != tracks_[track_index].end(); ++i) {
00211     int internal_frame = (*i).first;
00212     int corner = (*i).second;
00213     corner_to_track_maps_[internal_frame][corner] = track_index;
00214   }
00215 }
00216 
00217 void mvl_multi_view_matches::remove_maps(int track_index)
00218 {
00219   for (Map::iterator i = tracks_[track_index].begin(); i != tracks_[track_index].end(); ++i) {
00220     int internal_frame = (*i).first;
00221     int corner = (*i).second;
00222     corner_to_track_maps_[internal_frame].erase(corner);
00223   }
00224 }
00225 
00226 vcl_ostream& mvl_multi_view_matches::print(vcl_ostream& s) const
00227 {
00228   for (unsigned int i=0; i < tracks_.size(); ++i) {
00229     s << "Track " << i << " : ";
00230     for (Map::const_iterator m = tracks_[i].begin(); m != tracks_[i].end(); ++m)
00231       s << '(' << views_[(*m).first] << ',' << (*m).second << ") ";
00232     s << vcl_endl;
00233   }
00234   return s;
00235 }
00236 
00237 vcl_istream& mvl_multi_view_matches::read(vcl_istream& s)
00238 {
00239   if (!s.good()) return s;
00240 
00241   views_.clear();
00242   vul_awk awk(s);
00243   for (int i=0; i < awk.NF(); ++i)
00244     views_.push_back(atoi(awk[i]));
00245   ++awk;
00246 
00247   vcl_cerr << __FILE__ << " : reading views ( ";
00248   for (unsigned int i=0; i < views_.size(); ++i)
00249     vcl_cerr << views_[i] << ' ';
00250   vcl_cerr << ")\n";
00251 
00252   init();
00253 
00254   tracks_.resize(20000);
00255   int max_track = 0;
00256   for (; awk; ++awk) {
00257     if (awk.NF() != 3) vcl_abort();
00258     int track = atoi(awk[0]);
00259     int frame = atoi(awk[1]);
00260     int corner = atoi(awk[2]);
00261     tracks_[track][frame] = corner;
00262     if (track > max_track) max_track = track;
00263   }
00264   tracks_.resize(max_track);
00265 
00266   for (unsigned int i=0; i < tracks_.size(); ++i)
00267     update_maps(i);
00268 
00269   vcl_cerr << __FILE__ << " : read " << tracks_.size() << " tracks\n";
00270 
00271   return s;
00272 }
00273 
00274 vcl_ostream& mvl_multi_view_matches::write(vcl_ostream& s) const
00275 {
00276   if (!s.good()) return s;
00277 
00278   // Output the view indices on the first line
00279   for (unsigned int i=0; i < views_.size(); ++i)
00280     s << i << ' ';
00281   s << vcl_endl;
00282 
00283   // Now output the (track, internal frame, corner_index) triplets on each line
00284   for (unsigned int i=0; i < tracks_.size(); ++i)
00285     for (Map::const_iterator m = tracks_[i].begin(); m != tracks_[i].end(); ++m)
00286       s << i << ' ' << (*m).first << ' ' << (*m).second << vcl_endl;
00287 
00288   vcl_cerr << __FILE__ << " : wrote " << tracks_.size() << " tracks\n";
00289 
00290   return s;
00291 }
00292 
00293 void mvl_multi_view_matches::read(char const* filename)
00294 {
00295   vcl_ifstream fin(filename);
00296   read(fin);
00297 }
00298 
00299 void mvl_multi_view_matches::write(char const* filename) const
00300 {
00301   vcl_ofstream fout(filename);
00302   write(fout);
00303 }