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