| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <string.h> |
| | #include <iostream> |
| | #include <algorithm> |
| | #include <time.h> |
| | #include <iomanip> |
| | #include <fstream> |
| | #include <string> |
| |
|
| | using std::cout; |
| | using std::ofstream; |
| | using std::string; |
| |
|
| | #ifndef _WIN32 |
| | #include <sys/time.h> |
| | #endif |
| |
|
| | #include "ConfigBA.h" |
| |
|
| | #ifdef _MSC_VER |
| | #define strcpy strcpy_s |
| | #define sprintf sprintf_s |
| | #endif |
| |
|
| | namespace pba { |
| |
|
| | ConfigBA::ConfigBA() { |
| | __lm_max_iteration = 50; |
| | __lm_initial_damp = 1e-3f; |
| | __lm_minimum_damp = 1e-10f; |
| | __lm_maximum_damp = 1e+5f; |
| | __lm_delta_threshold = 1e-6f; |
| | __lm_gradient_threshold = 1e-10f; |
| | __lm_mse_threshold = 0.25f; |
| | __lm_use_diagonal_damp = true; |
| | __lm_check_gradient = false; |
| | __lm_damping_auto_switch = 0; |
| | __bundle_time_budget = 0; |
| | __bundle_mode_next = 0; |
| | __bundle_current_mode = 0; |
| |
|
| | |
| | __cg_max_iteration = 100; |
| | __cg_min_iteration = 10; |
| | __cg_recalculate_freq = 0; |
| | __cg_norm_threshold = 0.1f; |
| | __cg_norm_guard = 1.0f; |
| | __pba_experimental = 0; |
| | __cg_schur_complement = 0; |
| |
|
| | |
| | __fixed_intrinsics = false; |
| | __use_radial_distortion = 0; |
| | __reset_initial_distortion = false; |
| |
|
| | |
| | __verbose_level = 2; |
| | __verbose_cg_iteration = false; |
| | __verbose_function_time = false; |
| | __verbose_allocation = false; |
| | __verbose_sse = false; |
| | __save_gradient_norm = false; |
| | __stat_filename = NULL; |
| | __matlab_format_stat = true; |
| |
|
| | |
| | __jc_store_transpose = true; |
| | __jc_store_original = true; |
| | __no_jacobian_store = false; |
| |
|
| | __focal_normalize = true; |
| | __depth_normalize = true; |
| | __depth_degeneracy_fix = true; |
| | __jacobian_normalize = true; |
| | __data_normalize_median = 0.5f; |
| | __depth_check_epsilon = 0.01f; |
| |
|
| | |
| | __multiply_jx_usenoj = true; |
| |
|
| | |
| | __accurate_gain_ratio = true; |
| | |
| | __cpu_data_precision = 0; |
| | __current_device = -1; |
| | __selected_device = -1; |
| | __memory_usage = 0; |
| | __current_iteration = 0; |
| | __num_cpu_thread_all = 0; |
| |
|
| | |
| | __debug_pba = false; |
| | __profile_pba = 0; |
| | __cpu_thread_profile = false; |
| | __warmup_device = false; |
| |
|
| | |
| | __driver_output = NULL; |
| |
|
| | |
| | ResetBundleStatistics(); |
| | } |
| |
|
| | void ConfigBA::ResetBundleStatistics() { |
| | __abort_flag = false; |
| | __num_lm_success = 0; |
| | __num_lm_iteration = 0; |
| | __num_cg_iteration = 0; |
| | __num_projection_eval = 0; |
| | __num_jacobian_eval = 0; |
| | __num_camera_modified = 0; |
| | __num_point_behind = 0; |
| | __initial_mse = 0; |
| | __final_mse = 0; |
| | __final_mse_x = 0; |
| | __focal_scaling = 1.0f; |
| | __depth_scaling = 1.0f; |
| | __pba_return_code = 0; |
| | __current_iteration = 0; |
| | __warmup_device = false; |
| | __bundle_current_mode = __bundle_mode_next; |
| | for (int i = 0; i < NUM_TIMER; ++i) __timer_record[i] = 0; |
| | __bundle_records.resize(0); |
| | if (__num_cpu_thread_all) { |
| | std::cout << "WARNING: set all thread number to " << __num_cpu_thread_all |
| | << '\n'; |
| | for (int i = 0; i < NUM_FUNC; ++i) |
| | __num_cpu_thread[i] = __num_cpu_thread_all; |
| | } |
| | } |
| |
|
| | void ConfigBA::ResetTemporarySetting() { |
| | __reset_initial_distortion = false; |
| | __bundle_time_budget = 0; |
| | __bundle_mode_next = 0; |
| | __bundle_current_mode = 0; |
| | __stat_filename = NULL; |
| | if (__lm_damping_auto_switch > 0 && !__lm_use_diagonal_damp) |
| | __lm_use_diagonal_damp = true; |
| | } |
| |
|
| | void ConfigBA::SaveBundleStatistics(int ncam, int npt, int nproj) { |
| | if (__profile_pba) return; |
| | if (__stat_filename && __bundle_records.size() > 0) { |
| | char filenamebuf[1024]; |
| | char* ret = strchr(__stat_filename, '\r'); |
| | if (ret) ret[0] = 0; |
| | char* dot = strrchr(__stat_filename, '.'); |
| | if (dot && strchr(dot, '/') == NULL && strchr(dot, '\\') == NULL) |
| | strcpy(filenamebuf, __stat_filename); |
| | |
| | else |
| | sprintf(filenamebuf, "%s%s%s%s%s%s%s%s%s.%s", __stat_filename, |
| | __cpu_data_precision == 0 ? "_gpu" : "_cpu", |
| | __cpu_data_precision == sizeof(double) ? "d" : "", |
| | __cg_schur_complement ? "_schur" : "\0", |
| | __lm_use_diagonal_damp |
| | ? "\0" |
| | : (__lm_damping_auto_switch > 0 ? "_ad" : "_id"), |
| | __use_radial_distortion == -1 |
| | ? "_md" |
| | : (__use_radial_distortion ? "_pd" : "\0"), |
| | __jacobian_normalize ? "\0" : "_nojn", |
| | __focal_normalize || __depth_normalize ? "\0" : "_nodn", |
| | __depth_degeneracy_fix ? "\0" : "_nodf", |
| | __matlab_format_stat ? "m" : "log"); |
| |
|
| | |
| | ofstream out(filenamebuf); |
| | out << std::left; |
| |
|
| | float overhead = |
| | (BundleTimerGet(TIMER_OVERALL) - BundleTimerGet(TIMER_OPTIMIZATION)); |
| | if (__matlab_format_stat) |
| | out << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" |
| | << "ncam = " << ncam << "; npt = " << npt << "; nproj = " << nproj |
| | << ";\n" |
| | << "%% overhead = " << overhead << ";\n" |
| | << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" |
| | << "%% " << std::setw(10) << __num_lm_iteration |
| | << "\t linear systems solved;\n" |
| | << "%% " << std::setw(10) << __num_cg_iteration |
| | << "\t conjugated gradient steps;\n" |
| | << "%% " << std::setw(10) << BundleTimerGet(TIMER_OVERALL) |
| | << "\t seconds used overall;\n" |
| | << "%% " << std::setw(10) << BundleTimerGet(TIMER_PREPROCESSING) |
| | << "\t seconds on pre-processing;\n" |
| | << "%% " << std::setw(10) |
| | << BundleTimerGet(TIMER_GPU_UPLOAD) + |
| | BundleTimerGet(TIMER_GPU_ALLOCATION) |
| | << "\t seconds on upload;\n" |
| | << "%% " << std::setw(10) << BundleTimerGet(TIMER_OPTIMIZATION) |
| | << "\t seconds on optimization;\n" |
| | << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" |
| | << (__cpu_data_precision == 0 ? "gpustat" : "cpustat") |
| | << (__cpu_data_precision == sizeof(double) ? "_db" : "") |
| | << (__jacobian_normalize ? "" : "_nojn") |
| | << (__depth_degeneracy_fix ? "" : "_nodf") |
| | << (__cg_schur_complement ? "_schur" : "") << " = [\n"; |
| |
|
| | for (size_t i = 0; i < __bundle_records.size(); ++i) |
| | out << std::setw((i % 7 > 2) ? ((i % 7 > 4 && !__save_gradient_norm && |
| | !__lm_check_gradient) |
| | ? 0 |
| | : 12) |
| | : 5) |
| | << (__bundle_records[i] + (i == 1 ? overhead : 0)) |
| | << (i % 7 == 6 ? '\n' : '\t'); |
| |
|
| | if (__matlab_format_stat) out << "];\n\n"; |
| |
|
| | if (__verbose_level) |
| | std::cout << "\n---------------------------------------\n" << filenamebuf; |
| | } |
| | } |
| |
|
| | #define REPORT_FUNCTION_TIME(FID) \ |
| | std::setw(5) << (((int)(BundleTimerGet(FID) * 100 + 50)) * 0.01) << "(" \ |
| | << std::setw(2) \ |
| | << 0.1f * ((int)(1000 * BundleTimerGet(FID) / \ |
| | BundleTimerGet(TIMER_OPTIMIZATION))) \ |
| | << "%)" |
| |
|
| | void ConfigBA::PrintBundleStatistics() { |
| | if (__profile_pba) return; |
| |
|
| | if (__verbose_level) |
| | std::cout << "\n---------------------------------------\n" << std::setw(10) |
| | << __num_lm_success << "\t successful iterations;\n" |
| | << std::setw(10) << __num_lm_iteration |
| | << "\t linear systems solved;\n" << std::setw(10) |
| | << __num_cg_iteration << "\t conjugated gradient steps;\n" |
| | << std::setw(10) << BundleTimerGet(TIMER_OVERALL) |
| | << "\t seconds used overall;\n" << std::setw(10) |
| | << BundleTimerGet(TIMER_GPU_ALLOCATION) |
| | << "\t seconds on allocation;\n" << std::setw(10) |
| | << BundleTimerGet(TIMER_PREPROCESSING) |
| | << "\t seconds on pre-processing;\n" << std::setw(10) |
| | << BundleTimerGet(TIMER_GPU_UPLOAD) << "\t seconds on upload;\n" |
| | << std::setw(10) << BundleTimerGet(TIMER_OPTIMIZATION) |
| | << "\t seconds on optimization;\n"; |
| | if (__verbose_level && __cpu_data_precision) |
| | std::cout << REPORT_FUNCTION_TIME(TIMER_FUNCTION_JJ) |
| | << "\t seconds on jacobians;\n" |
| | << REPORT_FUNCTION_TIME(TIMER_FUNCTION_PJ) |
| | << "\t seconds on projections;\n" |
| | << REPORT_FUNCTION_TIME(TIMER_FUNCTION_JX) |
| | << "\t seconds on JX;\n" |
| | << REPORT_FUNCTION_TIME(TIMER_FUNCTION_JTE) |
| | << "\t seconds on JtE;\n" |
| | << REPORT_FUNCTION_TIME(TIMER_FUNCTION_BC) |
| | << "\t seconds to compute preconditioner;\n" |
| | << REPORT_FUNCTION_TIME(TIMER_FUNCTION_MP) |
| | << "\t seconds to apply preconditioner;\n" |
| | << REPORT_FUNCTION_TIME(TIMER_FUNCTION_UP) |
| | << "\t seconds to update parameters;\n"; |
| | if (__verbose_level) |
| | std::cout << "---------------------------------------\n" |
| | << "mse = " << __initial_mse << " -> " << __final_mse << "" |
| | << " (" << __final_mse_x |
| | << (__use_radial_distortion == -1 ? 'D' : 'U') << ")\n" |
| | << "---------------------------------------\n"; |
| | } |
| |
|
| | double ConfigBA::MyClock() { |
| | #ifdef _WIN32 |
| | return clock() / double(CLOCKS_PER_SEC); |
| | #else |
| | static int started = 0; |
| | static struct timeval tstart; |
| | if (started == 0) { |
| | gettimeofday(&tstart, NULL); |
| | started = 1; |
| | return 0; |
| | } else { |
| | struct timeval now; |
| | gettimeofday(&now, NULL); |
| | return ((now.tv_usec - tstart.tv_usec) / 1000000.0 + |
| | (now.tv_sec - tstart.tv_sec)); |
| | } |
| | #endif |
| | } |
| |
|
| | void ConfigBA::BundleTimerStart(int timer) { |
| | __timer_record[timer] = MyClock(); |
| | } |
| |
|
| | void ConfigBA::BundleTimerSwitch(int timer) { |
| | __timer_record[timer] = MyClock() - __timer_record[timer]; |
| | } |
| |
|
| | void ConfigBA::BundleTimerSwap(int timer1, int timer2) { |
| | BundleTimerSwitch(timer1); |
| | BundleTimerSwitch(timer2); |
| | } |
| |
|
| | float ConfigBA::BundleTimerGet(int timer) { |
| | return float(__timer_record[timer]); |
| | } |
| |
|
| | float ConfigBA::BundleTimerGetNow(int timer) { |
| | return 0.01f * ((int)(100 * (MyClock() - __timer_record[timer]))); |
| | } |
| |
|
| | bool ConfigBA::IsTimeBudgetAvailable() { |
| | if (__bundle_time_budget <= 0) return true; |
| | return BundleTimerGetNow(TIMER_OVERALL) < __bundle_time_budget; |
| | } |
| |
|
| | void ConfigBA::SaveBundleRecord(int iter, float res, float damping, float gn, |
| | float gi) { |
| | __bundle_records.push_back(float(iter)); |
| | __bundle_records.push_back(BundleTimerGetNow()); |
| | __bundle_records.push_back(float(__num_cg_iteration)); |
| | __bundle_records.push_back(res); |
| | __bundle_records.push_back(damping); |
| | __bundle_records.push_back(gn); |
| | __bundle_records.push_back(gi); |
| | } |
| |
|
| | void ConfigBA::ParseParam(int argc, char** argv) { |
| | #define CHAR1_TO_INT(x) ((x >= 'A' && x <= 'Z') ? x + 32 : x) |
| | #define CHAR2_TO_INT(str, i) \ |
| | (str[i] ? CHAR1_TO_INT(str[i]) + (CHAR1_TO_INT(str[i + 1]) << 8) : 0) |
| | #define CHAR3_TO_INT(str, i) \ |
| | (str[i] ? CHAR1_TO_INT(str[i]) + (CHAR2_TO_INT(str, i + 1) << 8) : 0) |
| | #define STRING_TO_INT(str) (CHAR1_TO_INT(str[0]) + (CHAR3_TO_INT(str, 1) << 8)) |
| |
|
| | #ifdef _MSC_VER |
| | |
| | #define MAKEINT1(a) (#@ a) |
| | #define sscanf sscanf_s |
| | #else |
| | #define mychar0 '0' |
| | #define mychar1 '1' |
| | #define mychar2 '2' |
| | #define mychar3 '3' |
| | #define mychara 'a' |
| | #define mycharb 'b' |
| | #define mycharc 'c' |
| | #define mychard 'd' |
| | #define mychare 'e' |
| | #define mycharf 'f' |
| | #define mycharg 'g' |
| | #define mycharh 'h' |
| | #define mychari 'i' |
| | #define mycharj 'j' |
| | #define mychark 'k' |
| | #define mycharl 'l' |
| | #define mycharm 'm' |
| | #define mycharn 'n' |
| | #define mycharo 'o' |
| | #define mycharp 'p' |
| | #define mycharq 'q' |
| | #define mycharr 'r' |
| | #define mychars 's' |
| | #define mychart 't' |
| | #define mycharu 'u' |
| | #define mycharv 'v' |
| | #define mycharw 'w' |
| | #define mycharx 'x' |
| | #define mychary 'y' |
| | #define mycharz 'z' |
| | #define MAKEINT1(a) (mychar##a) |
| | #endif |
| | #define MAKEINT2(a, b) (MAKEINT1(a) + (MAKEINT1(b) << 8)) |
| | #define MAKEINT3(a, b, c) (MAKEINT1(a) + (MAKEINT2(b, c) << 8)) |
| | #define MAKEINT4(a, b, c, d) (MAKEINT1(a) + (MAKEINT3(b, c, d) << 8)) |
| |
|
| | char *arg, *param, *opt; |
| | int opti, argi; |
| | float argf; |
| | for (int i = 0; i < argc; i++) { |
| | arg = argv[i]; |
| | if (arg == NULL || arg[0] != '-' || !arg[1]) continue; |
| | opt = arg + 1; |
| | opti = STRING_TO_INT(opt); |
| | param = argv[i + 1]; |
| |
|
| | |
| | switch (opti) { |
| | case MAKEINT3(l, m, i): |
| | if (i + 1 < argc && sscanf(param, "%d", &argi) && argi > 0) |
| | __lm_max_iteration = argi; |
| | break; |
| | case MAKEINT3(l, m, d): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf >= 0) |
| | __lm_delta_threshold = argf; |
| | break; |
| | case MAKEINT3(l, m, e): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf >= 0) |
| | __lm_mse_threshold = argf; |
| | break; |
| | case MAKEINT3(l, m, g): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf > 0) |
| | __lm_gradient_threshold = argf; |
| | break; |
| | case MAKEINT4(d, a, m, p): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf > 0) |
| | __lm_initial_damp = argf; |
| | break; |
| | case MAKEINT4(d, m, i, n): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf > 0) |
| | __lm_minimum_damp = argf; |
| | break; |
| | case MAKEINT4(d, m, a, x): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf > 0) |
| | __lm_maximum_damp = argf; |
| | break; |
| | case MAKEINT3(c, g, i): |
| | if (i + 1 < argc && sscanf(param, "%d", &argi) && argi > 0) |
| | __cg_max_iteration = argi; |
| | break; |
| | case MAKEINT4(c, g, i, m): |
| | if (i + 1 < argc && sscanf(param, "%d", &argi) && argi > 0) |
| | __cg_min_iteration = argi; |
| | break; |
| | case MAKEINT3(c, g, n): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf > 0) |
| | __cg_norm_threshold = argf; |
| | break; |
| | case MAKEINT3(c, g, g): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf > 0) |
| | __cg_norm_guard = argf; |
| | break; |
| | case MAKEINT4(c, g, r, f): |
| | if (i + 1 < argc && sscanf(param, "%d", &argi) && argi > 0) |
| | __cg_recalculate_freq = argi; |
| | break; |
| | case MAKEINT1(v): |
| | if (i + 1 < argc && sscanf(param, "%d", &argi) && argi >= 0) |
| | __verbose_level = argi; |
| | break; |
| | case MAKEINT4(d, e, v, i): |
| | if (i + 1 < argc && sscanf(param, "%d", &argi) && argi >= 0) |
| | __selected_device = argi; |
| | break; |
| | case MAKEINT4(b, u, d, g): |
| | if (i + 1 < argc && sscanf(param, "%d", &argi) && argi >= 0) |
| | __bundle_time_budget = argi; |
| | break; |
| | case MAKEINT3(e, x, p): |
| | if (i + 1 < argc && sscanf(param, "%d", &argi) && argi >= 0) |
| | __pba_experimental = argi; |
| | break; |
| | case MAKEINT4(t, n, u, m): |
| | if (i + 1 < argc && sscanf(param, "%d", &argi) && argi > 0) |
| | __num_cpu_thread_all = argi; |
| | break; |
| | case MAKEINT4(p, r, o, f): |
| | __profile_pba = (i + 1 < argc && sscanf(param, "%d", &argi)) |
| | ? std::max(10, argi) |
| | : 100; |
| | break; |
| | case MAKEINT4(t, p, r, o): |
| | __cpu_thread_profile = true; |
| | break; |
| | case MAKEINT4(c, a, l, i): |
| | __fixed_intrinsics = true; |
| | break; |
| | case MAKEINT4(s, c, h, u): |
| | case MAKEINT4(s, s, o, r): |
| | __cg_schur_complement = true; |
| | break; |
| | case MAKEINT2(m, d): |
| | case MAKEINT4(r, a, d, i): |
| | __use_radial_distortion = -1; |
| | break; |
| | case MAKEINT2(p, d): |
| | __use_radial_distortion = 1; |
| | break; |
| | case MAKEINT3(r, 0, 0): |
| | __reset_initial_distortion = true; |
| | break; |
| | case MAKEINT4(v, a, r, i): |
| | __fixed_intrinsics = false; |
| | break; |
| | case MAKEINT4(n, a, c, c): |
| | __accurate_gain_ratio = false; |
| | break; |
| | case MAKEINT4(v, c, g, i): |
| | __verbose_cg_iteration = true; |
| | break; |
| | case MAKEINT4(v, f, u, n): |
| | __verbose_function_time = true; |
| | break; |
| | case MAKEINT4(v, a, l, l): |
| | __verbose_allocation = true; |
| | break; |
| | case MAKEINT4(v, s, s, e): |
| | __verbose_sse = true; |
| | break; |
| | case MAKEINT4(s, v, g, n): |
| | __save_gradient_norm = true; |
| | break; |
| | case MAKEINT2(i, d): |
| | __lm_use_diagonal_damp = false; |
| | break; |
| | case MAKEINT3(d, a, s): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf > 0) |
| | __lm_damping_auto_switch = std::max(argf, 0.1f); |
| | else |
| | __lm_damping_auto_switch = 2.0f; |
| | break; |
| | case MAKEINT4(c, h, k, g): |
| | __lm_check_gradient = true; |
| | break; |
| | case MAKEINT4(n, o, j, n): |
| | __jacobian_normalize = false; |
| | break; |
| | case MAKEINT2(n, j): |
| | __no_jacobian_store = true; |
| | case MAKEINT3(n, j, c): |
| | __jc_store_transpose = false; |
| | __jc_store_original = false; |
| | break; |
| | case MAKEINT4(n, j, c, o): |
| | __jc_store_original = false; |
| | break; |
| | case MAKEINT4(n, j, c, t): |
| | __jc_store_transpose = false; |
| | break; |
| | case MAKEINT3(j, x, j): |
| | __multiply_jx_usenoj = false; |
| | break; |
| | case MAKEINT4(j, x, n, j): |
| | __multiply_jx_usenoj = true; |
| | break; |
| | case MAKEINT4(n, o, d, n): |
| | __depth_normalize = false; |
| | __focal_normalize = false; |
| | break; |
| | case MAKEINT4(n, o, d, f): |
| | __depth_degeneracy_fix = false; |
| | break; |
| | case MAKEINT4(n, o, r, m): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf > 0) |
| | __data_normalize_median = argf; |
| | break; |
| | case MAKEINT3(d, c, e): |
| | if (i + 1 < argc && sscanf(param, "%f", &argf) && argf > 0 && |
| | argf <= 0.01) |
| | __depth_check_epsilon = argf; |
| | break; |
| | case MAKEINT4(d, e, b, u): |
| | __debug_pba = true; |
| | break; |
| | case MAKEINT4(e, v, a, l): |
| | __lm_max_iteration = 100; |
| | __warmup_device = true; |
| | case MAKEINT4(s, t, a, t): |
| | __stat_filename = (i + 1 < argc && param[0] != '-') ? param : NULL; |
| | break; |
| | case MAKEINT3(o, u, t): |
| | __driver_output = (i + 1 < argc && param[0] != '-') ? param : NULL; |
| | break; |
| | case MAKEINT4(w, a, r, m): |
| | __warmup_device = true; |
| | break; |
| | case MAKEINT4(m, o, t, i): |
| | __bundle_mode_next = 1; |
| | break; |
| | case MAKEINT4(s, t, r, u): |
| | __bundle_mode_next = 2; |
| | break; |
| | } |
| | } |
| | } |
| |
|
| | } |
| |
|