10 #include "../lib/args.h" 11 #include "../lib/misc.h" 12 #include "../lib/intrinsics.h" 13 #include "../lib/json.h" 14 #include "../lib/eigen.h" 15 #include "../lib/assert.h" 16 #include <Eigen/Sparse> 17 #include <Eigen/IterativeLinearSolvers> 18 #include <Eigen/SparseLU> 19 #include <Eigen/SparseQR> 38 auto it1 = views1.begin();
39 auto it2 = views2.begin();
40 while(it1 != views1.end() && it2 != views2.end()) {
41 if(it1->first < it2->first) {
43 }
else if(it2->first < it1->first) {
64 explicit operator bool ()
const {
return ! std::isnan(scale); }
78 vec2 src_center_position = src_tg_positions.at(center_view).first;
79 vec2 tg_center_position = src_tg_positions.at(center_view).second;
81 real scales_sum = 0, scales_weights_sum = 0;
82 for(
const auto& kv : src_tg_positions) {
84 if(idx == center_view)
continue;
86 const vec2& src_position = p.first;
87 const vec2& tg_position = p.second;
89 const vec2& src_offset = src_position - src_center_position;
90 const vec2& tg_offset = tg_position - tg_center_position;
92 real x_scale = tg_offset[0] / src_offset[0];
93 real x_weight = std::max({
sq(src_offset[0]),
sq(tg_offset[0]) });
94 scales_sum += x_weight * x_scale;
95 scales_weights_sum += x_weight;
97 real y_scale = tg_offset[1] / src_offset[1];
98 real y_weight = std::max({
sq(src_offset[1]),
sq(tg_offset[1]) });
99 scales_sum += y_weight * y_scale;
100 scales_weights_sum += y_weight;
103 scale = scales_sum / scales_weights_sum;
104 translation = tg_center_position - src_center_position*scale;
108 std::size_t n = src_tg_positions.size();
113 std::ptrdiff_t row = 0;
114 for(
const auto& kv : src_tg_positions) {
116 const vec2& src_position = p.first;
117 const vec2& tg_position = p.second;
119 A(row, 0) = src_position[0];
122 b[row] = tg_position[0];
125 A(row, 0) = src_position[1];
128 b[row] = tg_position[1];
133 Eigen::ColPivHouseholderQR<Eigen_matXn<3>> solver(A);
139 translation =
vec2(x[1], x[2]);
146 for(
const auto& kv : src_tg_positions) {
148 const vec2& src_position = p.first;
149 const vec2& tg_position = p.second;
151 vec2 src_to_tg_position = scale*src_position + translation;
153 vec2 diff = tg_position - src_to_tg_position;
154 error +=
sq(diff[0]) +
sq(diff[1]);
156 error = std::sqrt(error /
real(src_tg_positions.size()));
162 real weight = (center_view ? 10.0 : 1.0) * 1.0/
sq(error);
169 std::size_t ratios_count = 0;
170 std::size_t features_count = ratios.rows();
171 for(
int ref = 0; ref < features_count; ++ref)
for(
int tg = ref+1; tg < features_count; ++tg)
172 if(weights(tg, ref) != 0.0) ++ratios_count;
174 std::size_t
rows = ratios_count + 1;
175 std::size_t
cols = features_count;
177 Eigen::SparseMatrix<real> A(rows, cols);
178 Eigen::SparseVector<real> b(rows);
179 std::ptrdiff_t row = 0;
180 for(
int ref = 0; ref < features_count; ++ref)
for(
int tg = ref+1; tg < features_count; ++tg) {
181 real weight = weights(tg, ref);
182 if(weight == 0.0)
continue;
184 A.insert(row, tg) = ratios(tg, ref);
185 A.insert(row, ref) = -1.0;
191 A.insert(row, 0) = 1.0;
195 Eigen::SparseQR<Eigen::SparseMatrix<real>, Eigen::COLAMDOrdering<int>> solver;
211 real ratios_sum = 0.0, known_sum = 0.0;
213 for(std::ptrdiff_t i = 0; i < known_depths.rows(); ++i) {
214 if(known_depths[i] == 0)
continue;
215 if(global_ratios[i] == 0)
continue;
217 ratios_sum += global_ratios[i];
218 known_sum += known_depths[i];
220 real scale = known_sum / ratios_sum;
224 real rms_error = 0.0;
226 for(std::ptrdiff_t i = 0; i < known_depths.rows(); ++i) {
227 if(known_depths[i] == 0)
continue;
228 if(depths[i] == 0)
continue;
230 real known = known_depths[i];
231 real re_known = depths[i];
233 rms_error +=
sq(known - re_known);
236 rms_error = std::sqrt(rms_error / count);
237 std::cout <<
"rms error: " << rms_error << std::endl;
244 int main(
int argc,
const char* argv[]) {
245 get_args(argc, argv,
"image_correspondences.json intrinsics.json R.json straight_depths.json out_straight_depths.json");
252 std::cout << std::setprecision(10);
253 Eigen::initParallel();
255 const int default_num_threads = Eigen::nbThreads();
256 Eigen::setNbThreads(0);
263 std::size_t features_count = all_features.size();
265 std::cout <<
"feature count: " << features_count << std::endl;
267 std::map<std::string, int> feature_indices;
268 for(std::ptrdiff_t i = 0; i < features_count; ++i)
269 feature_indices[all_features[i]] = i;
273 std::cout <<
"undistorting correspondences" << std::endl;
275 std::cout <<
"collecting unrotated view feature positions" << std::endl;
276 std::map<std::string, view_feature_positions> all_view_feature_xy;
277 for(
const auto& kv : undist_cors.
features) {
278 const std::string& feature_name = kv.first;
281 for(
const auto& kv2 : feature.
points) {
285 all_view_feature_xy[feature_name][idx] = unrotated_xy;
290 Eigen_matXX scale_ratios(features_count, features_count);
291 Eigen_matXX weights(features_count, features_count);
292 scale_ratios.setZero();
296 std::cout <<
"estimating pairwise relative scales of disparities" << std::endl;
297 #pragma omp parallel for schedule(guided) 298 for(
int ref = 0; ref < features_count; ++ref)
for(
int tg = ref+1; tg < features_count; ++tg) {
301 const std::string& src_feature_name = all_features.at(ref);
303 const std::string& tg_feature_name = all_features.at(tg);
316 if(! result)
continue;
318 scale_ratios(tg, ref) = result.
scale;
319 weights(tg, ref) = result.
weight;
322 std::cout << ref <<
"/" << (features_count-1) <<
" <--> " << tg <<
"/" << (features_count-1) << std::endl;
324 std::cout <<
'.' << std::flush;
326 std::cout << std::endl;
330 cv::Mat_<real> weights_img;
331 cv::eigen2cv(weights, weights_img);
332 cv::Mat_<uchar> weights_img2;
333 cv::normalize(weights_img, weights_img2, 0, 255, cv::NORM_MINMAX, CV_8UC1);
334 cv::resize(weights_img2, weights_img2, cv::Size(0,0), 3, 3, cv::INTER_NEAREST);
335 cv::imwrite(
"pairwise_scale_weights.png", weights_img2, { CV_IMWRITE_PNG_COMPRESSION, 9 });
337 cv::Mat_<real> ratios_img;
338 cv::eigen2cv(scale_ratios, ratios_img);
339 cv::Mat_<uchar> ratios_img2;
340 cv::normalize(ratios_img, ratios_img2, 0, 255, cv::NORM_MINMAX, CV_8UC1);
341 cv::resize(ratios_img2, ratios_img2, cv::Size(0,0), 5, 5, cv::INTER_NEAREST);
342 cv::imwrite(
"pairwise_scales.png", ratios_img2, { CV_IMWRITE_PNG_COMPRESSION, 9 });
346 std::cout <<
"calculating global scale ratios" << std::endl;
347 Eigen::setNbThreads(default_num_threads);
351 std::cout <<
"calculating depths" << std::endl;
353 known_depths.setZero();
354 for(
const auto& kv : in_depths) {
355 const std::string& feature_name = kv.first;
357 auto feature_index_it = feature_indices.find(feature_name);
358 if(feature_index_it != feature_indices.end()) {
359 int feature_index = feature_index_it->second;
360 known_depths[feature_index] = sdepth.
depth;
367 known_completed.setZero();
368 known_completed.block(0, 0, features_count, 1) = known_depths;
369 known_completed.block(0, 1, features_count, 1) = depths;
371 std::cout << std::setprecision(10);
372 std::cout <<
"known/completed:\n" << std::endl;
373 for(
int row = 0; row < features_count; ++row) {
374 if(known_depths[row] == 0)
continue;
375 if(depths[row] == 0)
continue;
376 std::cout << known_completed(row, 0) <<
";" << known_completed(row, 1) <<
"\n";
380 std::cout <<
"saving computed depths" << std::endl;
382 for(
int row = 0; row < features_count; ++row) {
383 if(depths[row] == 0)
continue;
384 real depth = depths[row];
385 out_straight_depths[all_features[row]] = depth;
estimate_relative_scale_result estimate_relative_scale(const view_feature_position_pairs &src_tg_positions, const view_index ¢er_view=view_index())
Numeric sq(Numeric n)
Compute square of a number.
std::map< view_index, vec2 > view_feature_positions
json encode_straight_depths(const straight_depths &depths)
std::vector< vec2 > positions(const feature_points &fpoints)
estimate_relative_scale_result(real sc, real w)
Eigen::Matrix< real, Eigen::Dynamic, Eigen::Dynamic > Eigen_matXX
std::vector< view_index > get_all_views(const image_correspondences &cors)
view_feature_position_pairs common_view_feature_positions(const view_feature_positions &views1, const view_feature_positions &views2)
std::map< view_index, view_feature_position_pair > view_feature_position_pairs
Set of features, each on set of views.
Eigen::Matrix< real, Rows, 1 > Eigen_vec
constexpr real max_relative_scale_error
Eigen::Matrix< real, Eigen::Dynamic, 1 > Eigen_vecX
vec3 mul_h(const mat44 &mat, const vec3 &vec)
cv::Mat_< real > decode_mat(const json &j)
std::map< std::string, image_correspondence_feature > features
intrinsics intrinsics_arg()
constexpr bool make_visualizations
cv::Matx< real, 3, 3 > mat33
Eigen::Matrix< real, Eigen::Dynamic, Cols > Eigen_matXn
std::vector< std::string > get_feature_names(const image_correspondences &cors)
std::map< std::string, straight_depth > straight_depths
void export_json_file(const json &j, const std::string &filename, bool compact)
image_correspondences image_correspondences_arg()
feature_points undistort(const feature_points &dist_fpoints, const intrinsics &intr)
straight_depths straight_depths_arg()
Eigen_vecX complete_depths(const Eigen_vecX &known_depths, const Eigen_vecX &global_ratios)
std::string out_filename_arg()
Feature on set of views. Optionally one view is "reference".
int main(int argc, const char *argv[])
Eigen_vecX compute_global_ratios(const Eigen_matXX &ratios, const Eigen_matXX &weights)
std::map< view_index, feature_point > points
std::pair< vec2, vec2 > view_feature_position_pair
constexpr int min_position_pairs_count
void get_args(int argc, const char *argv[], const std::string &usage)