1 // This is brl/bseg/bapl/bapl_keypoint_set.cxx
2 #include <iostream>
3 #include <set>
4 #include "bapl_keypoint_set.h"
5 //:
6 // \file
7 
8 #include "bapl_keypoint.h"
9 #include "bapl_lowe_keypoint.h"
10 #include "bapl_lowe_keypoint_sptr.h"
11 #include "bapl_keypoint_sptr.h"
12 #ifdef _MSC_VER
13 #  include "vcl_msvc_warnings.h"
14 #endif
15 
16 #include "vgl/vgl_point_2d.h"
17 #include "vpgl/vpgl_fundamental_matrix.h"
18 #include <bpgl/algo/bpgl_fm_compute_ransac.h>
19 #include <vgl/algo/vgl_h_matrix_2d_optimize_lmq.h>
20 
21 //: Binary io, NOT IMPLEMENTED, signatures defined to use bapl_keypoint_set as a brdb_value
vsl_b_write(vsl_b_ostream &,bapl_keypoint_set const &)22 void vsl_b_write(vsl_b_ostream & /*os*/, bapl_keypoint_set const & /*ph*/)
23 {
24   std::cerr << "vsl_b_write() -- Binary io, NOT IMPLEMENTED, signatures defined to use brec_part_hierarchy as a brdb_value\n";
25   return;
26 }
27 
vsl_b_read(vsl_b_istream &,bapl_keypoint_set &)28 void vsl_b_read(vsl_b_istream & /*is*/, bapl_keypoint_set & /*ph*/)
29 {
30   std::cerr << "vsl_b_read() -- Binary io, NOT IMPLEMENTED, signatures defined to use brec_part_hierarchy as a brdb_value\n";
31   return;
32 }
33 
vsl_b_read(vsl_b_istream & is,bapl_keypoint_set * ph)34 void vsl_b_read(vsl_b_istream& is, bapl_keypoint_set* ph)
35 {
36   delete ph;
37   bool not_null_ptr;
38   vsl_b_read(is, not_null_ptr);
39   if (not_null_ptr)
40   {
41     std::vector<bapl_keypoint_sptr> vec;
42     ph = new bapl_keypoint_set(vec);
43     vsl_b_read(is, *ph);
44   }
45   else
46     ph = nullptr;
47 }
48 
vsl_b_write(vsl_b_ostream & os,const bapl_keypoint_set * & ph)49 void vsl_b_write(vsl_b_ostream& os, const bapl_keypoint_set* &ph)
50 {
51   if (ph==nullptr)
52   {
53     vsl_b_write(os, false); // Indicate null pointer stored
54   }
55   else
56   {
57     vsl_b_write(os,true); // Indicate non-null pointer stored
58     vsl_b_write(os,*ph);
59   }
60 }
61 
62 
63 //: Binary io, NOT IMPLEMENTED, signatures defined to use bapl_keypoint_match_set as a brdb_value
vsl_b_write(vsl_b_ostream &,bapl_keypoint_match_set const &)64 void vsl_b_write(vsl_b_ostream & /*os*/, bapl_keypoint_match_set const & /*ph*/)
65 {
66   std::cerr << "vsl_b_write() -- Binary io, NOT IMPLEMENTED, signatures defined to use brec_part_hierarchy as a brdb_value\n";
67   return;
68 }
69 
vsl_b_read(vsl_b_istream &,bapl_keypoint_match_set &)70 void vsl_b_read(vsl_b_istream & /*is*/, bapl_keypoint_match_set & /*ph*/)
71 {
72   std::cerr << "vsl_b_read() -- Binary io, NOT IMPLEMENTED, signatures defined to use brec_part_hierarchy as a brdb_value\n";
73   return;
74 }
75 
vsl_b_read(vsl_b_istream & is,bapl_keypoint_match_set * ph)76 void vsl_b_read(vsl_b_istream& is, bapl_keypoint_match_set* ph)
77 {
78   delete ph;
79   bool not_null_ptr;
80   vsl_b_read(is, not_null_ptr);
81   if (not_null_ptr)
82   {
83     std::vector<bapl_key_match> vec;
84     ph = new bapl_keypoint_match_set(0,0,vec);  // dummy instance
85     vsl_b_read(is, *ph);
86   }
87   else
88     ph = nullptr;
89 }
90 
vsl_b_write(vsl_b_ostream & os,const bapl_keypoint_match_set * & ph)91 void vsl_b_write(vsl_b_ostream& os, const bapl_keypoint_match_set* &ph)
92 {
93   if (ph==nullptr)
94   {
95     vsl_b_write(os, false); // Indicate null pointer stored
96   }
97   else
98   {
99     vsl_b_write(os,true); // Indicate non-null pointer stored
100     vsl_b_write(os,*ph);
101   }
102 }
103 
104 //: remove spurious matches, i.e remove if a keypoint from J is shared : (i1,j) (i2,j), remove (i2,j) since one of them is definitely spurious
prune_spurious_matches(std::vector<bapl_key_match> & matches)105 void bapl_keypoint_match_set::prune_spurious_matches(std::vector<bapl_key_match>& matches)
106 {
107   std::set<int> helper;
108   int cnt = (int)matches.size();
109   for (int ii = 0; ii < cnt; ii++) {
110     auto it = helper.find(matches[ii].second->id());
111     if (it == helper.end()) {
112       helper.insert(matches[ii].second->id());
113     }
114     else {
115       matches.erase(matches.begin() + ii);
116       ii--;
117       cnt--;
118     }
119   }
120 }
121 
122 //: refine matches by computing F
refine_matches(float outlier_threshold,std::vector<bapl_key_match> & refined_matches)123 void bapl_keypoint_match_set::refine_matches(float outlier_threshold, std::vector<bapl_key_match>& refined_matches)
124 {
125   std::vector<vgl_point_2d<double> > lpts, rpts; std::vector<vgl_point_2d<double> > lpts_refined, rpts_refined;
126   for (const auto& m : matches_) {
127     bapl_lowe_keypoint_sptr kp1;
128     kp1.vertical_cast(m.first);
129     bapl_lowe_keypoint_sptr kp2;
130     kp2.vertical_cast(m.second);
131     vgl_point_2d<double> lpt(kp1->location_i(), kp1->location_j());
132     vgl_point_2d<double> rpt(kp2->location_i(), kp2->location_j());
133     lpts.push_back(lpt); rpts.push_back(rpt);
134   }
135 
136   vpgl_fundamental_matrix<double> fm;
137   bpgl_fm_compute_ransac fmcr;
138   fmcr.set_generate_all(true);
139   fmcr.set_outlier_threshold(outlier_threshold);
140   fmcr.compute( rpts, lpts, fm);
141   vnl_matrix_fixed<double,3,3> fm_vnl = fm.get_matrix();
142   std::cout << "\nRansac estimated fundamental matrix:\n" << fm_vnl << '\n';
143   std::vector<bool> outliers = fmcr.outliers;
144   std::vector<double> res = fmcr.residuals;
145 #ifdef DEBUG
146   std::cout << "\noutliers\n";
147   for (unsigned i = 0; i<outliers.size(); ++i)
148     std::cout << "O[" << i << "]= " << outliers[i]
149              << "  e "<< res[i] <<  '\n';
150 #endif
151   std::vector<vgl_homg_point_2d<double> > rpoints, lpoints;
152 
153   //: prune the outliers
154   for (unsigned i = 0; i<lpts.size(); ++i)
155   {
156     if (outliers[i])
157       continue;
158     refined_matches.push_back(matches_[i]);
159     lpoints.emplace_back(lpts[i]);
160     rpoints.emplace_back(rpts[i]);
161     lpts_refined.push_back(lpts[i]);
162     rpts_refined.push_back(rpts[i]);
163   }
164 
165 #if 0 // not implemented yet
166   //further refine F using Levenberg-Marquardt
167   .. refinement code here ... should compute:  vnl_matrix_fixed<double, 3, 3> F_optimized
168 
169   //: remove the matches that are outliers to the optimized F
170   rrel_fm_problem estimator( rpts_refined, lpts_refined ); // class to be used to compute residuals
171   vnl_vector<double> params;
172   vpgl_fundamental_matrix<double> fm_optimized(F_optimized);
173   estimator.fm_to_params(fm_optimized, params);
174   std::vector<double> residuals;
175   estimator.compute_residuals(params, residuals);
176 
177   std::vector<bool> outliers2;
178   for ( unsigned i = 0; i < rpts_refined.size(); i++ ){
179     if ( residuals[i] > outlier_threshold )
180       outliers2.push_back( true );
181     else
182       outliers2.push_back( false );
183   }
184 
185   std::vector<bapl_key_match> matches_pruned2;
186   for (unsigned i = 0; i < rpts_refined.size(); i++) {
187     if (outliers2[i])
188       continue;
189     matches_pruned2.push_back(matches_pruned[i]);
190   }
191 
192   std::cout << "After F optimization found: " << matches_pruned2.size() << " matches, initial number was: " << matches_pruned.size() << "!\n";
193 #endif
194 }
195