contrib/oxl/mvl/NViewMatches.cxx
Go to the documentation of this file.
00001 // This is oxl/mvl/NViewMatches.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 //  \file
00007 
00008 #include "NViewMatches.h"
00009 
00010 #include <vcl_cassert.h>
00011 #include <vcl_cstdlib.h> // for vcl_abort()
00012 #include <vcl_fstream.h>
00013 #include <vul/vul_awk.h>
00014 #include <vul/vul_printf.h>
00015 
00016 /////////////////////////////////////////////////////////////////////////////
00017 
00018 vcl_ostream& operator<<(vcl_ostream& s, const NViewMatch& c)
00019 {
00020   for (unsigned i = 0; i < c.size(); ++i)
00021     vul_printf(s, "%-4d ", c[i]);
00022 
00023   return s;
00024 }
00025 
00026 //: Return true if B is consistent with this match.
00027 //  Matches are consistent if they are identical in all non-wildcard positions.
00028 //  However, it additionally requires that they share at least min_overlap
00029 //  non-wildcard positions.
00030 bool NViewMatch::matches(const NViewMatch& b, int min_overlap) const
00031 {
00032   unsigned l = size();
00033 
00034   if (l != b.size()) {
00035     vcl_cerr << "NViewMatch::matches(B): matching vectors of different lengths\n";
00036     return false;
00037   }
00038 
00039   int overlap = 0;
00040   for (unsigned i = 0; i < l; ++i)
00041     if ((*this)[i] != NViewMatch::nomatch && b[i] != NViewMatch::nomatch) {
00042       if ((*this)[i] != b[i])
00043         return false;
00044       ++overlap;
00045     }
00046   return overlap >= min_overlap;
00047 }
00048 
00049 //: Fill any wildcard positions with the corresponding position in B.
00050 void NViewMatch::incorporate(const NViewMatch& b)
00051 {
00052   unsigned l = size();
00053   for (unsigned i = 0; i < l; ++i)
00054     if ((*this)[i] == NViewMatch::nomatch)
00055       (*this)[i] = b[i];
00056 }
00057 
00058 //: Check for any inconsistencies between matches
00059 bool NViewMatch::is_consistent(const NViewMatch& b) const
00060 {
00061   unsigned l = size();
00062   for (unsigned i = 0; i < l; ++i)
00063     if ((*this)[i] != NViewMatch::nomatch && b[i] != NViewMatch::nomatch)
00064       if ((*this)[i] != b[i])
00065         return false;
00066   return true;
00067 }
00068 
00069 //: Count how many non-wildcard entries are in this NViewMatch
00070 int NViewMatch::count_observations() const
00071 {
00072   unsigned l = size();
00073   int c = 0;
00074   for (unsigned i = 0; i < l; ++i)
00075     if ((*this)[i] != NViewMatch::nomatch)
00076       ++c;
00077   return c;
00078 }
00079 
00080 /////////////////////////////////////////////////////////////////////////////
00081 
00082 // Default ctor
00083 NViewMatches::NViewMatches():
00084   min_overlap_(2)
00085 {
00086 }
00087 
00088 NViewMatches::NViewMatches(vcl_istream& s)
00089 {
00090   load(s);
00091 }
00092 
00093 NViewMatches::NViewMatches(const char* filename)
00094 {
00095   load(filename);
00096 }
00097 
00098 NViewMatches::NViewMatches(int nviews, int min_overlap):
00099   nviews_(nviews), min_overlap_(min_overlap)
00100 {
00101 }
00102 
00103 NViewMatches::~NViewMatches()
00104 {
00105   //  delete indx_array_;
00106 }
00107 
00108 void NViewMatches::clear()
00109 {
00110   resize(0);
00111 }
00112 
00113 bool NViewMatches::load(const char* filename)
00114 {
00115   vcl_ifstream s(filename);
00116   if (!s.good()) {
00117     vcl_cerr << "NViewMatches::load(" << filename << ") - bad filename\n";
00118     return false;
00119   }
00120   return load(s);
00121 }
00122 
00123 bool NViewMatches::load(vcl_istream& s)
00124 {
00125   clear();
00126   for (vul_awk awk(s); awk; ++awk) {
00127     // On first line, set nviews_ to field count
00128     // On subsequent lines, check the field count matches the first line.
00129     if (awk.NR() == 1)
00130       nviews_ = awk.NF();
00131     else
00132       if (awk.NF() != nviews_) {
00133         vcl_cerr << "NViewMatches::load() ERROR: only " << awk.NF() << " fields on line " << awk.NR() << '\n';
00134         return false;
00135       }
00136 
00137     // Build NViewMatch from this line and add it.
00138     NViewMatch v(nviews_);
00139     for (int j = 0; j < nviews_; ++j) {
00140       char const* cp = awk[j];
00141       if (cp[0] == '*')
00142         v[j] = NViewMatch::nomatch;
00143       else
00144         v[j] = atoi(cp);
00145     }
00146     push_back(v);
00147   }
00148 
00149   return true;
00150 }
00151 
00152 bool NViewMatches::save(vcl_ostream& s)
00153 {
00154   for (unsigned i = 0; i < size(); ++i)
00155     s << (*this)[i] << '\n';
00156   return s.good() != 0;
00157 }
00158 
00159 bool NViewMatches::save(const char* filename)
00160 {
00161   vcl_ofstream o(filename);
00162   return save(o);
00163 }
00164 
00165 //: Count how many matches are consistent with \p match
00166 int NViewMatches::count_matches(const NViewMatch& match)
00167 {
00168   int nmatches = 0;
00169   for (unsigned i = 0; i < size(); ++i)
00170     if ((*this)[i].matches(match,min_overlap_))
00171       ++nmatches;
00172   return nmatches;
00173 }
00174 
00175 //: Return an array of the indices that match the given \p match
00176 vcl_vector<int> NViewMatches::get_matches(const NViewMatch& match)
00177 {
00178   vcl_vector<int> ret;
00179   for (unsigned i = 0; i < size(); ++i)
00180     if (operator[](i).matches(match,min_overlap_))
00181       ret.push_back(i);
00182   return ret;
00183 }
00184 
00185 //: Add a new nview match to the set.
00186 // If it is just an update of an existing match (filling in a wildcard),
00187 // merge it.  Otherwise add it at the end.
00188 //
00189 // If the new match is consistent with two existing consistent matches
00190 // then all 3 are merged.
00191 //
00192 // If the new match is consistent with two existing inconsistent matches
00193 // they are both removed.
00194 //
00195 // Returns the index of the match into which the new match was merged, or
00196 // the index of the new match if it was consistent with nothing.
00197 // Returns -1 if inconsistency was found.
00198 
00199 int NViewMatches::incorporate(const NViewMatch& newtrack)
00200 {
00201   int nmatches = 0;
00202   iterator merged = end();
00203   vcl_abort(); // This routine is untested.....
00204   for (iterator i = begin(); i != end(); ++i) {
00205     if ((*i).matches(newtrack,min_overlap_)) {
00206       if (nmatches == 0) {
00207         // This is the first consistent match found for newtrack
00208         (*i).incorporate(newtrack);
00209         ++nmatches;
00210         merged = i;
00211       }
00212       else if ((*i).is_consistent(*merged)) {
00213         vcl_cerr << "Merge : " << (*i) << '\n'
00214                  << "        " << (*merged) << '\n';
00215         // A further consistent match, so merge the two match tracks
00216         (*merged).incorporate((*i));
00217         erase(i);
00218         --i; // step back so we don't skip any matches
00219         ++nmatches;
00220       }
00221       else {
00222         // Two matches are inconsistent so remove them both and return -1
00223         //  vcl_cerr << "NViewMatches::incorporate(): Doh! Found inconsistent matches - removing them\n";
00224         erase(i);
00225         erase(merged);
00226         return -1;
00227       }
00228     }
00229   }
00230   if (nmatches == 0) {
00231     push_back(newtrack);
00232     return size() - 1;
00233   }
00234 
00235 #ifdef DEBUG
00236   if (nmatches > 1) {
00237     vcl_cerr << "NViewMatches::incorporate(): " << nmatches << " consistent matches merged\n";
00238   }
00239 #endif
00240   return merged - begin();
00241 }
00242 
00243 //: Build an NViewMatch from the triplet \p (base_view..base_view+2)
00244 NViewMatch NViewMatches::make_triplet_match(int base_view, int c1, int c2, int c3)
00245 {
00246   assert(base_view+2 < nviews_);
00247   NViewMatch newtrack(nviews_);
00248   newtrack[base_view] = c1;
00249   newtrack[base_view+1] = c2;
00250   newtrack[base_view+2] = c3;
00251   return newtrack;
00252 }
00253 
00254 //: Build an NViewMatch from the triplet \p (base_view..base_view+2), and incorporate.
00255 int NViewMatches::incorporate_triplet(int base_view, int c1, int c2, int c3)
00256 {
00257   assert(base_view+2 < nviews_);
00258   NViewMatch newtrack(nviews_);
00259   newtrack[base_view] = c1;
00260   newtrack[base_view+1] = c2;
00261   newtrack[base_view+2] = c3;
00262   return incorporate(newtrack);
00263 }
00264 
00265 // Should ALWAYS be called before using the match matrix!
00266 // Efficiently checks for inconsistencies and removes them.
00267 void NViewMatches::remove_inconsistencies()
00268 {
00269 }