diff options
Diffstat (limited to 'extern')
-rw-r--r-- | extern/libmv/CMakeLists.txt | 8 | ||||
-rw-r--r-- | extern/libmv/SConscript | 3 | ||||
-rwxr-xr-x | extern/libmv/bundle.sh | 11 | ||||
-rw-r--r-- | extern/libmv/libmv-capi.cc | 53 | ||||
-rw-r--r-- | extern/libmv/libmv-capi.h | 3 | ||||
-rw-r--r-- | extern/libmv/libmv-capi_intern.h | 59 | ||||
-rw-r--r-- | extern/libmv/libmv-capi_stub.cc | 4 | ||||
-rw-r--r-- | extern/libmv/libmv/multiview/fundamental.cc | 91 | ||||
-rw-r--r-- | extern/libmv/libmv/multiview/fundamental.h | 37 | ||||
-rw-r--r-- | extern/libmv/libmv/multiview/homography.cc | 111 | ||||
-rw-r--r-- | extern/libmv/libmv/multiview/homography.h | 39 | ||||
-rw-r--r-- | extern/libmv/libmv/simple_pipeline/keyframe_selection.cc | 176 | ||||
-rw-r--r-- | extern/libmv/third_party/msinttypes/stdint.h | 12 |
13 files changed, 401 insertions, 206 deletions
diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt index 2c9a21965f0..80a212b64f8 100644 --- a/extern/libmv/CMakeLists.txt +++ b/extern/libmv/CMakeLists.txt @@ -32,15 +32,19 @@ set(INC set(SRC libmv-capi.h + libmv-capi_intern.h ) if(WITH_LIBMV) add_definitions( -DWITH_LIBMV + -DWITH_LIBMV_GUARDED_ALLOC + -DGOOGLE_GLOG_DLL_DECL= ) list(APPEND INC third_party/ceres/include + ../../intern/guardedalloc ) set(INC_SYS @@ -224,10 +228,6 @@ if(WITH_LIBMV) third_party/glog/src ) endif() - - add_definitions( - -DGOOGLE_GLOG_DLL_DECL= - ) else() list(APPEND SRC libmv-capi_stub.cc diff --git a/extern/libmv/SConscript b/extern/libmv/SConscript index f422eb08c58..6926b36f335 100644 --- a/extern/libmv/SConscript +++ b/extern/libmv/SConscript @@ -15,6 +15,7 @@ incs = '.' if env['WITH_BF_LIBMV']: defs.append('GOOGLE_GLOG_DLL_DECL=') defs.append('WITH_LIBMV') + defs.append('WITH_LIBMV_GUARDED_ALLOC') src = env.Glob("libmv-capi.cc") src += env.Glob('libmv/image/*.cc') @@ -25,7 +26,7 @@ if env['WITH_BF_LIBMV']: src += env.Glob('third_party/fast/*.c') src += env.Glob('third_party/gflags/*.cc') - incs += ' ../Eigen3 third_party/ceres/include' + incs += ' ../Eigen3 third_party/ceres/include ../../intern/guardedalloc' incs += ' ' + env['BF_PNG_INC'] incs += ' ' + env['BF_ZLIB_INC'] diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh index 16fb754d30a..57e3598a5ae 100755 --- a/extern/libmv/bundle.sh +++ b/extern/libmv/bundle.sh @@ -128,15 +128,19 @@ set(INC set(SRC libmv-capi.h + libmv-capi_intern.h ) if(WITH_LIBMV) add_definitions( -DWITH_LIBMV + -DWITH_LIBMV_GUARDED_ALLOC + -DGOOGLE_GLOG_DLL_DECL= ) list(APPEND INC third_party/ceres/include + ../../intern/guardedalloc ) set(INC_SYS @@ -203,10 +207,6 @@ ${third_glog_headers} third_party/glog/src ) endif() - - add_definitions( - -DGOOGLE_GLOG_DLL_DECL= - ) else() list(APPEND SRC libmv-capi_stub.cc @@ -238,11 +238,12 @@ incs = '.' if env['WITH_BF_LIBMV']: defs.append('GOOGLE_GLOG_DLL_DECL=') defs.append('WITH_LIBMV') + defs.append('WITH_LIBMV_GUARDED_ALLOC') src = env.Glob("libmv-capi.cc") $src - incs += ' ../Eigen3 third_party/ceres/include' + incs += ' ../Eigen3 third_party/ceres/include ../../intern/guardedalloc' incs += ' ' + env['BF_PNG_INC'] incs += ' ' + env['BF_ZLIB_INC'] diff --git a/extern/libmv/libmv-capi.cc b/extern/libmv/libmv-capi.cc index a8f396d5df1..11608318a40 100644 --- a/extern/libmv/libmv-capi.cc +++ b/extern/libmv/libmv-capi.cc @@ -43,10 +43,10 @@ # include <png.h> #endif +#include "libmv-capi_intern.h" #include "libmv/logging/logging.h" - +#include "libmv/multiview/homography.h" #include "libmv/tracking/track_region.h" - #include "libmv/simple_pipeline/callbacks.h" #include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/initialize_reconstruction.h" @@ -58,12 +58,6 @@ #include "libmv/simple_pipeline/reconstruction_scale.h" #include "libmv/simple_pipeline/keyframe_selection.h" -#include "libmv/multiview/homography.h" - -#ifdef _MSC_VER -# define snprintf _snprintf -#endif - struct libmv_Reconstruction { libmv::EuclideanReconstruction reconstruction; @@ -388,14 +382,15 @@ void libmv_samplePlanarPatch(const float *image, int width, int height, struct libmv_Tracks *libmv_tracksNew(void) { - libmv::Tracks *libmv_tracks = new libmv::Tracks(); + libmv::Tracks *libmv_tracks = LIBMV_OBJECT_NEW(libmv::Tracks); return (struct libmv_Tracks *)libmv_tracks; } void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks) { - delete (libmv::Tracks*) libmv_tracks; + using libmv::Tracks; + LIBMV_OBJECT_DELETE(libmv_tracks, Tracks); } void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y) @@ -578,7 +573,7 @@ struct libmv_Reconstruction *libmv_solveReconstruction(const struct libmv_Tracks reconstruct_progress_update_cb progress_update_callback, void *callback_customdata) { - struct libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction(); + struct libmv_Reconstruction *libmv_reconstruction = LIBMV_OBJECT_NEW(libmv_Reconstruction); libmv::Tracks &tracks = *((libmv::Tracks *) libmv_tracks); libmv::EuclideanReconstruction &reconstruction = libmv_reconstruction->reconstruction; @@ -660,7 +655,7 @@ struct libmv_Reconstruction *libmv_solveModal(const struct libmv_Tracks *libmv_t reconstruct_progress_update_cb progress_update_callback, void *callback_customdata) { - struct libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction(); + struct libmv_Reconstruction *libmv_reconstruction = LIBMV_OBJECT_NEW(libmv_Reconstruction); libmv::Tracks &tracks = *((libmv::Tracks *) libmv_tracks); libmv::EuclideanReconstruction &reconstruction = libmv_reconstruction->reconstruction; @@ -703,7 +698,7 @@ struct libmv_Reconstruction *libmv_solveModal(const struct libmv_Tracks *libmv_t void libmv_reconstructionDestroy(struct libmv_Reconstruction *libmv_reconstruction) { - delete libmv_reconstruction; + LIBMV_OBJECT_DELETE(libmv_reconstruction, libmv_Reconstruction); } int libmv_reprojectionPointForTrack(const struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]) @@ -850,7 +845,7 @@ struct libmv_Features *libmv_detectFeaturesFAST(const unsigned char *data, { libmv::Feature *features = NULL; std::vector<libmv::Feature> v; - struct libmv_Features *libmv_features = new libmv_Features(); + struct libmv_Features *libmv_features = LIBMV_STRUCT_NEW(libmv_Features, 1); int i = 0, count; if (margin) { @@ -864,7 +859,7 @@ struct libmv_Features *libmv_detectFeaturesFAST(const unsigned char *data, count = v.size(); if (count) { - features = new libmv::Feature[count]; + features = LIBMV_STRUCT_NEW(libmv::Feature, count); for(std::vector<libmv::Feature>::iterator it = v.begin(); it != v.end(); it++) { features[i++] = *it; @@ -883,7 +878,7 @@ struct libmv_Features *libmv_detectFeaturesMORAVEC(const unsigned char *data, int margin, int count, int min_distance) { libmv::Feature *features = NULL; - struct libmv_Features *libmv_features = new libmv_Features; + struct libmv_Features *libmv_features = LIBMV_STRUCT_NEW(libmv_Features, 1); if (count) { if (margin) { @@ -892,7 +887,7 @@ struct libmv_Features *libmv_detectFeaturesMORAVEC(const unsigned char *data, height -= 2 * margin; } - features = new libmv::Feature[count]; + features = LIBMV_STRUCT_NEW(libmv::Feature, count); libmv::DetectMORAVEC(data, stride, width, height, features, &count, min_distance, NULL); } @@ -905,10 +900,11 @@ struct libmv_Features *libmv_detectFeaturesMORAVEC(const unsigned char *data, void libmv_featuresDestroy(struct libmv_Features *libmv_features) { - if (libmv_features->features) - delete [] libmv_features->features; + if (libmv_features->features) { + LIBMV_STRUCT_DELETE(libmv_features->features); + } - delete libmv_features; + LIBMV_STRUCT_DELETE(libmv_features); } int libmv_countFeatures(const struct libmv_Features *libmv_features) @@ -930,14 +926,14 @@ void libmv_getFeature(const struct libmv_Features *libmv_features, int number, d struct libmv_CameraIntrinsics *libmv_cameraIntrinsicsNewEmpty(void) { - libmv::CameraIntrinsics *camera_intrinsics = new libmv::CameraIntrinsics(); + libmv::CameraIntrinsics *camera_intrinsics = LIBMV_OBJECT_NEW(libmv::CameraIntrinsics); return (struct libmv_CameraIntrinsics *) camera_intrinsics; } struct libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options) { - libmv::CameraIntrinsics *camera_intrinsics = new libmv::CameraIntrinsics(); + libmv::CameraIntrinsics *camera_intrinsics = LIBMV_OBJECT_NEW(libmv::CameraIntrinsics); cameraIntrinsicsFromOptions(libmv_camera_intrinsics_options, camera_intrinsics); @@ -947,16 +943,15 @@ struct libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(const libmv_CameraIntri struct libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(const libmv_CameraIntrinsics *libmvIntrinsics) { libmv::CameraIntrinsics *orig_intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics; - libmv::CameraIntrinsics *new_intrinsics = new libmv::CameraIntrinsics(*orig_intrinsics); + libmv::CameraIntrinsics *new_intrinsics = LIBMV_OBJECT_NEW(libmv::CameraIntrinsics, *orig_intrinsics); return (struct libmv_CameraIntrinsics *) new_intrinsics; } void libmv_cameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsics) { - libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics; - - delete intrinsics; + using libmv::CameraIntrinsics; + LIBMV_OBJECT_DELETE(libmvIntrinsics, CameraIntrinsics); } void libmv_cameraIntrinsicsUpdate(const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, @@ -1082,8 +1077,7 @@ void libmv_cameraIntrinsicsInvert(const libmv_CameraIntrinsicsOptions *libmv_cam } } -void libmv_homography2DFromCorrespondencesLinear(double (*x1)[2], double (*x2)[2], int num_points, - double H[3][3], double expected_precision) +void libmv_homography2DFromCorrespondencesEuc(double (*x1)[2], double (*x2)[2], int num_points, double H[3][3]) { libmv::Mat x1_mat, x2_mat; libmv::Mat3 H_mat; @@ -1099,7 +1093,8 @@ void libmv_homography2DFromCorrespondencesLinear(double (*x1)[2], double (*x2)[2 LG << "x1: " << x1_mat; LG << "x2: " << x2_mat; - libmv::Homography2DFromCorrespondencesLinear(x1_mat, x2_mat, &H_mat, expected_precision); + libmv::HomographyEstimationOptions options; + libmv::Homography2DFromCorrespondencesEuc(x1_mat, x2_mat, options, &H_mat); LG << "H: " << H_mat; diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h index 37aab2465ed..a872eeb60a1 100644 --- a/extern/libmv/libmv-capi.h +++ b/extern/libmv/libmv-capi.h @@ -159,8 +159,7 @@ void libmv_cameraIntrinsicsApply(const libmv_CameraIntrinsicsOptions *libmv_came void libmv_cameraIntrinsicsInvert(const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, double x, double y, double *x1, double *y1); -void libmv_homography2DFromCorrespondencesLinear(double (*x1)[2], double (*x2)[2], int num_points, - double H[3][3], double expected_precision); +void libmv_homography2DFromCorrespondencesEuc(double (*x1)[2], double (*x2)[2], int num_points, double H[3][3]); #ifdef __cplusplus } diff --git a/extern/libmv/libmv-capi_intern.h b/extern/libmv/libmv-capi_intern.h new file mode 100644 index 00000000000..90087c52a6c --- /dev/null +++ b/extern/libmv/libmv-capi_intern.h @@ -0,0 +1,59 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef LIBMV_C_API_INTERN_H +#define LIBMV_C_API_INTERN_H + +#if defined(_MSC_VER) +# define __func__ __FUNCTION__ +# define snprintf _snprintf +#endif + +#ifdef WITH_LIBMV_GUARDED_ALLOC +# include "MEM_guardedalloc.h" +# define LIBMV_OBJECT_NEW OBJECT_GUARDED_NEW +# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE +# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE +# define LIBMV_STRUCT_NEW(type, count) (type*)MEM_mallocN(sizeof(type) * count, __func__) +# define LIBMV_STRUCT_DELETE(what) MEM_freeN(what) +#else +// Need this to keep libmv-capi potentially standalone. +# if defined __GNUC__ || defined __sun +# define LIBMV_OBJECT_NEW(type, args ...) \ + new(malloc(sizeof(type))) type(args) +# else +# define LIBMV_OBJECT_NEW(type, ...) \ + new(malloc(sizeof(type))) type(__VA_ARGS__) +#endif +# define LIBMV_OBJECT_DELETE(what, type) \ + { if(what) { \ + ((type*)(what))->~type(); \ + free(what); \ + } } (void)0 +# define LIBMV_STRUCT_NEW(type, count) (type*)malloc(sizeof(type) * count) +# define LIBMV_STRUCT_DELETE(what) { if (what) free(what); } (void)0 +#endif + +#endif // LIBMV_C_API_INTERN_H diff --git a/extern/libmv/libmv-capi_stub.cc b/extern/libmv/libmv-capi_stub.cc index 4896f4c6949..e6d3753961b 100644 --- a/extern/libmv/libmv-capi_stub.cc +++ b/extern/libmv/libmv-capi_stub.cc @@ -277,8 +277,8 @@ void libmv_cameraIntrinsicsInvert(const libmv_CameraIntrinsicsOptions *libmv_cam *y1 = (y - principal_y) / focal_length; } -void libmv_homography2DFromCorrespondencesLinear(double (* /* x1 */)[2], double (* /* x2 */)[2], int /* num_points */, - double H[3][3], double /* expected_precision */) +void libmv_homography2DFromCorrespondencesEuc(double (* /* x1 */)[2], double (* /* x2 */)[2], int /* num_points */, + double H[3][3]) { memset(H, 0, sizeof(double[3][3])); H[0][0] = 1.0f; diff --git a/extern/libmv/libmv/multiview/fundamental.cc b/extern/libmv/libmv/multiview/fundamental.cc index a05ef7907a2..ec6c70d81cf 100644 --- a/extern/libmv/libmv/multiview/fundamental.cc +++ b/extern/libmv/libmv/multiview/fundamental.cc @@ -20,6 +20,7 @@ #include "libmv/multiview/fundamental.h" +#include "ceres/ceres.h" #include "libmv/logging/logging.h" #include "libmv/numeric/numeric.h" #include "libmv/numeric/poly.h" @@ -407,4 +408,94 @@ void FundamentalToEssential(const Mat3 &F, Mat3 *E) { *E = svd.matrixU() * diag.asDiagonal() * svd.matrixV().transpose(); } +FundamentalEstimationOptions::FundamentalEstimationOptions(void) : + use_refine_if_algebraic_fails(true), + max_num_iterations(50), + parameter_tolerance(1e-16), + function_tolerance(1e-16) { +} + +class FundamentalSymmetricEpipolarCostFunctor { + public: + FundamentalSymmetricEpipolarCostFunctor(const Vec2 &x, + const Vec2 &y) + : x_(x), y_(y) {} + + template<typename T> + bool operator()(const T *fundamental_parameters, T *residuals) const { + typedef Eigen::Matrix<T, 3, 3> Mat3; + typedef Eigen::Matrix<T, 3, 1> Vec3; + + Mat3 F(fundamental_parameters); + + Vec3 x(T(x_(0)), T(x_(1)), T(1.0)); + Vec3 y(T(y_(0)), T(y_(1)), T(1.0)); + + Vec3 F_x = F * x; + Vec3 Ft_y = F.transpose() * y; + T y_F_x = y.dot(F_x); + + residuals[0] = y_F_x * T(1) / F_x.head(2).norm(); + residuals[1] = y_F_x * T(1) / Ft_y.head(2).norm(); + + return true; + } + + const Mat x_; + const Mat y_; +}; + +/* Fundamental transformation estimation. */ +bool FundamentalFromCorrespondencesEuc( + const Mat &x1, + const Mat &x2, + const FundamentalEstimationOptions &options, + Mat3 *F) { + // Step 1: Algebraic fundamental estimation. + bool algebraic_success = NormalizedEightPointSolver(x1, x2, F); + + LG << "Algebraic result " << algebraic_success + << ", estimated matrix:\n" << *F; + + if (!algebraic_success && !options.use_refine_if_algebraic_fails) { + return false; + } + + // Step 2: Refine matrix using Ceres minimizer. + ceres::Problem problem; + for (int i = 0; i < x1.cols(); i++) { + FundamentalSymmetricEpipolarCostFunctor + *fundamental_symmetric_epipolar_cost_function = + new FundamentalSymmetricEpipolarCostFunctor(x1.col(i), + x2.col(i)); + + problem.AddResidualBlock( + new ceres::AutoDiffCostFunction< + FundamentalSymmetricEpipolarCostFunctor, + 2, // num_residuals + 9>(fundamental_symmetric_epipolar_cost_function), + NULL, + F->data()); + } + + // Configure the solve. + ceres::Solver::Options solver_options; + solver_options.linear_solver_type = ceres::DENSE_QR; + solver_options.max_num_iterations = options.max_num_iterations; + solver_options.update_state_every_iteration = true; + solver_options.parameter_tolerance = options.parameter_tolerance; + solver_options.function_tolerance = options.function_tolerance; + + // Run the solve. + ceres::Solver::Summary summary; + ceres::Solve(solver_options, &problem, &summary); + + VLOG(1) << "Summary:\n" << summary.FullReport(); + + LG << "Final refined matrix:\n" << *F; + + return !(summary.termination_type == ceres::DID_NOT_RUN || + summary.termination_type == ceres::NUMERICAL_FAILURE); +} + } // namespace libmv diff --git a/extern/libmv/libmv/multiview/fundamental.h b/extern/libmv/libmv/multiview/fundamental.h index 1ad184d8314..2961a46cdc4 100644 --- a/extern/libmv/libmv/multiview/fundamental.h +++ b/extern/libmv/libmv/multiview/fundamental.h @@ -144,6 +144,43 @@ bool MotionFromEssentialAndCorrespondence(const Mat3 &E, */ void FundamentalToEssential(const Mat3 &F, Mat3 *E); +/** + * This structure contains options that controls how the fundamental + * estimation operates. + * + * Defaults should be suitable for a wide range of use cases, but + * better performance and accuracy might require tweaking/ + */ +struct FundamentalEstimationOptions { + // Default constructor which sets up a options for generic usage. + FundamentalEstimationOptions(void); + + // Refine fundamental matrix even if algebraic estimation reported failure. + bool use_refine_if_algebraic_fails; + + // Maximal number of iterations for refinement step. + int max_num_iterations; + + // Paramaneter tolerance used by minimizer termination criteria. + float parameter_tolerance; + + // Function tolerance used by minimizer termination criteria. + float function_tolerance; +}; + +/** + * Fundamental transformation estimation. + * + * This function estimates the fundamental transformation from a list of 2D + * correspondences by doing algebraic estimation first followed with result + * refinement. + */ +bool FundamentalFromCorrespondencesEuc( + const Mat &x1, + const Mat &x2, + const FundamentalEstimationOptions &options, + Mat3 *F); + } // namespace libmv #endif // LIBMV_MULTIVIEW_FUNDAMENTAL_H_ diff --git a/extern/libmv/libmv/multiview/homography.cc b/extern/libmv/libmv/multiview/homography.cc index 317eb3f85c6..6041849d9fe 100644 --- a/extern/libmv/libmv/multiview/homography.cc +++ b/extern/libmv/libmv/multiview/homography.cc @@ -20,6 +20,7 @@ #include "libmv/multiview/homography.h" +#include "ceres/ceres.h" #include "libmv/logging/logging.h" #include "libmv/multiview/homography_parameterization.h" @@ -153,6 +154,116 @@ bool Homography2DFromCorrespondencesLinear(const Mat &x1, return false; } } + +HomographyEstimationOptions::HomographyEstimationOptions(void) : + expected_algebraic_precision(EigenDouble::dummy_precision()), + use_refine_if_algebraic_fails(true), + max_num_iterations(50), + parameter_tolerance(1e-16), + function_tolerance(1e-16) { +} + +class HomographySymmetricGeometricCostFunctor { + public: + HomographySymmetricGeometricCostFunctor(const Vec2 &x, + const Vec2 &y) + : x_(x), y_(y) { } + + template<typename T> + bool operator()(const T *homography_parameters, T *residuals) const { + typedef Eigen::Matrix<T, 3, 3> Mat3; + typedef Eigen::Matrix<T, 3, 1> Vec3; + + Mat3 H(homography_parameters); + + Vec3 x(T(x_(0)), T(x_(1)), T(1.0)); + Vec3 y(T(y_(0)), T(y_(1)), T(1.0)); + + Vec3 H_x = H * x; + Vec3 Hinv_y = H.inverse() * y; + + H_x /= H_x(2); + Hinv_y /= Hinv_y(2); + + // This is a forward error. + residuals[0] = H_x(0) - T(y_(0)); + residuals[1] = H_x(1) - T(y_(1)); + + // This is a backward error. + residuals[2] = Hinv_y(0) - T(x_(0)); + residuals[3] = Hinv_y(1) - T(x_(1)); + + return true; + } + + const Vec2 x_; + const Vec2 y_; +}; + +/** 2D Homography transformation estimation in the case that points are in + * euclidean coordinates. + */ +bool Homography2DFromCorrespondencesEuc( + const Mat &x1, + const Mat &x2, + const HomographyEstimationOptions &options, + Mat3 *H) { + // TODO(sergey): Support homogenous coordinates, not just euclidean. + + assert(2 == x1.rows()); + assert(4 <= x1.cols()); + assert(x1.rows() == x2.rows()); + assert(x1.cols() == x2.cols()); + + // Step 1: Algebraic homography estimation. + bool algebraic_success = + Homography2DFromCorrespondencesLinear(x1, x2, H, + options.expected_algebraic_precision); + + LG << "Algebraic result " << algebraic_success + << ", estimated matrix:\n" << *H; + + if (!algebraic_success && !options.use_refine_if_algebraic_fails) { + return false; + } + + // Step 2: Refine matrix using Ceres minimizer. + ceres::Problem problem; + for (int i = 0; i < x1.cols(); i++) { + HomographySymmetricGeometricCostFunctor + *homography_symmetric_geometric_cost_function = + new HomographySymmetricGeometricCostFunctor(x1.col(i), + x2.col(i)); + + problem.AddResidualBlock( + new ceres::AutoDiffCostFunction< + HomographySymmetricGeometricCostFunctor, + 4, // num_residuals + 9>(homography_symmetric_geometric_cost_function), + NULL, + H->data()); + } + + // Configure the solve. + ceres::Solver::Options solver_options; + solver_options.linear_solver_type = ceres::DENSE_QR; + solver_options.max_num_iterations = options.max_num_iterations; + solver_options.update_state_every_iteration = true; + solver_options.parameter_tolerance = options.parameter_tolerance; + solver_options.function_tolerance = options.function_tolerance; + + // Run the solve. + ceres::Solver::Summary summary; + ceres::Solve(solver_options, &problem, &summary); + + VLOG(1) << "Summary:\n" << summary.FullReport(); + + LG << "Final refined matrix:\n" << *H; + + return !(summary.termination_type == ceres::DID_NOT_RUN || + summary.termination_type == ceres::NUMERICAL_FAILURE); +} + /** * x2 ~ A * x1 * x2^t * Hi * A *x1 = 0 diff --git a/extern/libmv/libmv/multiview/homography.h b/extern/libmv/libmv/multiview/homography.h index 8d2dff930eb..1928e39dffb 100644 --- a/extern/libmv/libmv/multiview/homography.h +++ b/extern/libmv/libmv/multiview/homography.h @@ -54,6 +54,45 @@ bool Homography2DFromCorrespondencesLinear(const Mat &x1, EigenDouble::dummy_precision()); /** + * This structure contains options that controls how the homography + * estimation operates. + * + * Defaults should be suitable for a wide range of use cases, but + * better performance and accuracy might require tweaking/ + */ +struct HomographyEstimationOptions { + // Default constructor which sets up a options for generic usage. + HomographyEstimationOptions(void); + + // Expected precision of algebraic estimation. + double expected_algebraic_precision; + + // Refine homography even if algebraic estimation reported failure. + bool use_refine_if_algebraic_fails; + + // Maximal number of iterations for refinement step. + int max_num_iterations; + + // Paramaneter tolerance used by minimizer termination criteria. + float parameter_tolerance; + + // Function tolerance used by minimizer termination criteria. + float function_tolerance; +}; + +/** + * 2D homography transformation estimation. + * + * This function estimates the homography transformation from a list of 2D + * correspondences by doing algebraic estimation first followed with result + * refinement. + */ +bool Homography2DFromCorrespondencesEuc(const Mat &x1, + const Mat &x2, + const HomographyEstimationOptions &options, + Mat3 *H); + +/** * 3D Homography transformation estimation. * * This function can be used in order to estimate the homography transformation diff --git a/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc b/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc index 976adb288b3..d4ddee56fda 100644 --- a/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc +++ b/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc @@ -61,161 +61,6 @@ Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics &intrinsics) { return S * T; } -class HomographySymmetricGeometricCostFunctor { - public: - HomographySymmetricGeometricCostFunctor(const Vec2 &x, - const Vec2 &y) - : x_(x), y_(y) { } - - template<typename T> - bool operator()(const T *homography_parameters, T *residuals) const { - typedef Eigen::Matrix<T, 3, 3> Mat3; - typedef Eigen::Matrix<T, 3, 1> Vec3; - - Mat3 H(homography_parameters); - - Vec3 x(T(x_(0)), T(x_(1)), T(1.0)); - Vec3 y(T(y_(0)), T(y_(1)), T(1.0)); - - Vec3 H_x = H * x; - Vec3 Hinv_y = H.inverse() * y; - - H_x /= H_x(2); - Hinv_y /= Hinv_y(2); - - residuals[0] = H_x(0) - T(y_(0)); - residuals[1] = H_x(1) - T(y_(1)); - - residuals[2] = Hinv_y(0) - T(x_(0)); - residuals[3] = Hinv_y(1) - T(x_(1)); - - return true; - } - - const Vec2 x_; - const Vec2 y_; -}; - -void ComputeHomographyFromCorrespondences(const Mat &x1, const Mat &x2, - CameraIntrinsics &intrinsics, - Mat3 *H) { - // Algebraic homography estimation, happens with normalized coordinates - Homography2DFromCorrespondencesLinear(x1, x2, H, 1e-12); - - // Refine matrix using Ceres minimizer - - // TODO(sergey): look into refinement in pixel space. - ceres::Problem problem; - - for (int i = 0; i < x1.cols(); i++) { - HomographySymmetricGeometricCostFunctor - *homography_symmetric_geometric_cost_function = - new HomographySymmetricGeometricCostFunctor(x1.col(i), - x2.col(i)); - - problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - HomographySymmetricGeometricCostFunctor, - 4, /* num_residuals */ - 9>(homography_symmetric_geometric_cost_function), - NULL, - H->data()); - } - - // Configure the solve. - ceres::Solver::Options solver_options; - solver_options.linear_solver_type = ceres::DENSE_QR; - solver_options.max_num_iterations = 50; - solver_options.update_state_every_iteration = true; - solver_options.parameter_tolerance = 1e-16; - solver_options.function_tolerance = 1e-16; - - // Run the solve. - ceres::Solver::Summary summary; - ceres::Solve(solver_options, &problem, &summary); - - VLOG(1) << "Summary:\n" << summary.FullReport(); - - // Convert homography to original pixel space - Mat3 N = IntrinsicsNormalizationMatrix(intrinsics); - *H = N.inverse() * (*H) * N; -} - -class FundamentalSymmetricEpipolarCostFunctor { - public: - FundamentalSymmetricEpipolarCostFunctor(const Vec2 &x, - const Vec2 &y) - : x_(x), y_(y) {} - - template<typename T> - bool operator()(const T *fundamental_parameters, T *residuals) const { - typedef Eigen::Matrix<T, 3, 3> Mat3; - typedef Eigen::Matrix<T, 3, 1> Vec3; - - Mat3 F(fundamental_parameters); - - Vec3 x(T(x_(0)), T(x_(1)), T(1.0)); - Vec3 y(T(y_(0)), T(y_(1)), T(1.0)); - - Vec3 F_x = F * x; - Vec3 Ft_y = F.transpose() * y; - T y_F_x = y.dot(F_x); - - residuals[0] = y_F_x * T(1) / F_x.head(2).norm(); - residuals[1] = y_F_x * T(1) / Ft_y.head(2).norm(); - - return true; - } - - const Mat x_; - const Mat y_; -}; - -void ComputeFundamentalFromCorrespondences(const Mat &x1, const Mat &x2, - CameraIntrinsics &intrinsics, - Mat3 *F) { - // Algebraic fundamental estimation, happens with normalized coordinates - NormalizedEightPointSolver(x1, x2, F); - - // Refine matrix using Ceres minimizer - - // TODO(sergey): look into refinement in pixel space. - ceres::Problem problem; - - for (int i = 0; i < x1.cols(); i++) { - FundamentalSymmetricEpipolarCostFunctor - *fundamental_symmetric_epipolar_cost_function = - new FundamentalSymmetricEpipolarCostFunctor(x1.col(i), - x2.col(i)); - - problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - FundamentalSymmetricEpipolarCostFunctor, - 2, /* num_residuals */ - 9>(fundamental_symmetric_epipolar_cost_function), - NULL, - F->data()); - } - - // Configure the solve. - ceres::Solver::Options solver_options; - solver_options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY; - solver_options.max_num_iterations = 50; - solver_options.update_state_every_iteration = true; - solver_options.parameter_tolerance = 1e-16; - solver_options.function_tolerance = 1e-16; - - // Run the solve. - ceres::Solver::Summary summary; - ceres::Solve(solver_options, &problem, &summary); - - VLOG(1) << "Summary:\n" << summary.FullReport(); - - // Convert fundamental to original pixel space - Mat3 N = IntrinsicsNormalizationMatrix(intrinsics); - *F = N.inverse() * (*F) * N; -} - // P.H.S. Torr // Geometric Motion Segmentation and Model Selection // @@ -360,8 +205,25 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks, continue; Mat3 H, F; - ComputeHomographyFromCorrespondences(x1, x2, intrinsics, &H); - ComputeFundamentalFromCorrespondences(x1, x2, intrinsics, &F); + + // Estimate homography using default options. + HomographyEstimationOptions homography_estimation_options; + Homography2DFromCorrespondencesEuc(x1, + x2, + homography_estimation_options, + &H); + + // Convert homography to original pixel space. + H = N_inverse * H * N; + + FundamentalEstimationOptions fundamental_estimation_options; + FundamentalFromCorrespondencesEuc(x1, + x2, + fundamental_estimation_options, + &F); + + // Convert fundamental to original pixel space. + F = N_inverse * F * N; // TODO(sergey): STEP 2: Discard outlier matches diff --git a/extern/libmv/third_party/msinttypes/stdint.h b/extern/libmv/third_party/msinttypes/stdint.h index e236bb00015..189ee34571c 100644 --- a/extern/libmv/third_party/msinttypes/stdint.h +++ b/extern/libmv/third_party/msinttypes/stdint.h @@ -72,16 +72,16 @@ extern "C" { // realize that, e.g. char has the same size as __int8 // so we give up on __intX for them. #if (_MSC_VER < 1300) - typedef char int8_t; - typedef short int16_t; - typedef int int32_t; + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else - typedef __int8 int8_t; - typedef __int16 int16_t; - typedef __int32 int32_t; + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; |