From ba432299cdd4382130103cf5a84c34693d4a3bdc Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 4 Jan 2016 18:22:27 +0500 Subject: Move Libmv from extern/ to intern/ Logically it is intern library since being mainly developed by 1.5 blender guys. --- extern/libmv/CMakeLists.txt | 238 --- extern/libmv/ChangeLog | 609 -------- extern/libmv/bundle.sh | 187 --- extern/libmv/files.txt | 138 -- extern/libmv/intern/autotrack.cc | 99 -- extern/libmv/intern/autotrack.h | 71 - extern/libmv/intern/camera_intrinsics.cc | 355 ----- extern/libmv/intern/camera_intrinsics.h | 138 -- extern/libmv/intern/detector.cc | 148 -- extern/libmv/intern/detector.h | 77 - extern/libmv/intern/frame_accessor.cc | 164 -- extern/libmv/intern/frame_accessor.h | 79 - extern/libmv/intern/homography.cc | 59 - extern/libmv/intern/homography.h | 43 - extern/libmv/intern/image.cc | 272 ---- extern/libmv/intern/image.h | 99 -- extern/libmv/intern/logging.cc | 55 - extern/libmv/intern/logging.h | 47 - extern/libmv/intern/reconstruction.cc | 542 ------- extern/libmv/intern/reconstruction.h | 102 -- extern/libmv/intern/region.h | 43 - extern/libmv/intern/stub.cc | 403 ----- extern/libmv/intern/track_region.cc | 177 --- extern/libmv/intern/track_region.h | 81 - extern/libmv/intern/tracks.cc | 52 - extern/libmv/intern/tracks.h | 51 - extern/libmv/intern/tracksN.cc | 138 -- extern/libmv/intern/tracksN.h | 129 -- extern/libmv/intern/utildefines.h | 62 - extern/libmv/libmv-capi.h | 42 - extern/libmv/libmv/autotrack/autotrack.cc | 291 ---- extern/libmv/libmv/autotrack/autotrack.h | 226 --- extern/libmv/libmv/autotrack/callbacks.h | 38 - extern/libmv/libmv/autotrack/frame_accessor.h | 86 -- extern/libmv/libmv/autotrack/marker.h | 144 -- extern/libmv/libmv/autotrack/model.h | 44 - extern/libmv/libmv/autotrack/predict_tracks.cc | 316 ---- extern/libmv/libmv/autotrack/predict_tracks.h | 37 - .../libmv/libmv/autotrack/predict_tracks_test.cc | 201 --- extern/libmv/libmv/autotrack/quad.h | 57 - extern/libmv/libmv/autotrack/reconstruction.h | 89 -- extern/libmv/libmv/autotrack/region.h | 67 - extern/libmv/libmv/autotrack/tracks.cc | 193 --- extern/libmv/libmv/autotrack/tracks.h | 82 - extern/libmv/libmv/autotrack/tracks_test.cc | 52 - extern/libmv/libmv/base/aligned_malloc.cc | 74 - extern/libmv/libmv/base/aligned_malloc.h | 34 - extern/libmv/libmv/base/id_generator.h | 37 - extern/libmv/libmv/base/scoped_ptr.h | 105 -- extern/libmv/libmv/base/scoped_ptr_test.cc | 79 - extern/libmv/libmv/base/vector.h | 176 --- extern/libmv/libmv/base/vector_test.cc | 223 --- extern/libmv/libmv/base/vector_utils.h | 34 - extern/libmv/libmv/image/array_nd.cc | 108 -- extern/libmv/libmv/image/array_nd.h | 497 ------ extern/libmv/libmv/image/array_nd_test.cc | 324 ---- extern/libmv/libmv/image/convolve.cc | 344 ----- extern/libmv/libmv/image/convolve.h | 107 -- extern/libmv/libmv/image/convolve_test.cc | 110 -- extern/libmv/libmv/image/correlation.h | 74 - extern/libmv/libmv/image/image.h | 155 -- extern/libmv/libmv/image/image_converter.h | 81 - extern/libmv/libmv/image/image_drawing.h | 285 ---- extern/libmv/libmv/image/image_test.cc | 45 - extern/libmv/libmv/image/sample.h | 138 -- extern/libmv/libmv/image/sample_test.cc | 89 -- extern/libmv/libmv/image/tuple.h | 90 -- extern/libmv/libmv/image/tuple_test.cc | 83 - extern/libmv/libmv/logging/logging.h | 31 - extern/libmv/libmv/multiview/conditioning.cc | 99 -- extern/libmv/libmv/multiview/conditioning.h | 59 - .../libmv/libmv/multiview/euclidean_resection.cc | 774 ---------- extern/libmv/libmv/multiview/euclidean_resection.h | 148 -- .../libmv/multiview/euclidean_resection_test.cc | 237 --- extern/libmv/libmv/multiview/fundamental.cc | 544 ------- extern/libmv/libmv/multiview/fundamental.h | 187 --- extern/libmv/libmv/multiview/fundamental_test.cc | 162 -- extern/libmv/libmv/multiview/homography.cc | 465 ------ extern/libmv/libmv/multiview/homography.h | 145 -- extern/libmv/libmv/multiview/homography_error.h | 248 --- .../libmv/multiview/homography_parameterization.h | 91 -- extern/libmv/libmv/multiview/homography_test.cc | 261 ---- extern/libmv/libmv/multiview/nviewtriangulation.h | 80 - .../libmv/multiview/nviewtriangulation_test.cc | 94 -- extern/libmv/libmv/multiview/panography.cc | 125 -- extern/libmv/libmv/multiview/panography.h | 99 -- extern/libmv/libmv/multiview/panography_kernel.cc | 51 - extern/libmv/libmv/multiview/panography_kernel.h | 54 - extern/libmv/libmv/multiview/panography_test.cc | 144 -- extern/libmv/libmv/multiview/projection.cc | 224 --- extern/libmv/libmv/multiview/projection.h | 231 --- extern/libmv/libmv/multiview/projection_test.cc | 115 -- extern/libmv/libmv/multiview/resection.h | 62 - extern/libmv/libmv/multiview/resection_test.cc | 61 - extern/libmv/libmv/multiview/test_data_sets.cc | 196 --- extern/libmv/libmv/multiview/test_data_sets.h | 105 -- extern/libmv/libmv/multiview/triangulation.cc | 50 - extern/libmv/libmv/multiview/triangulation.h | 38 - extern/libmv/libmv/multiview/triangulation_test.cc | 47 - extern/libmv/libmv/multiview/two_view_kernel.h | 137 -- extern/libmv/libmv/numeric/dogleg.h | 261 ---- extern/libmv/libmv/numeric/dogleg_test.cc | 95 -- extern/libmv/libmv/numeric/function_derivative.h | 107 -- .../libmv/numeric/function_derivative_test.cc | 57 - extern/libmv/libmv/numeric/levenberg_marquardt.h | 183 --- .../libmv/numeric/levenberg_marquardt_test.cc | 56 - extern/libmv/libmv/numeric/numeric.cc | 136 -- extern/libmv/libmv/numeric/numeric.h | 502 ------ extern/libmv/libmv/numeric/numeric_test.cc | 439 ------ extern/libmv/libmv/numeric/poly.cc | 23 - extern/libmv/libmv/numeric/poly.h | 123 -- extern/libmv/libmv/numeric/poly_test.cc | 98 -- extern/libmv/libmv/simple_pipeline/bundle.cc | 658 -------- extern/libmv/libmv/simple_pipeline/bundle.h | 148 -- extern/libmv/libmv/simple_pipeline/callbacks.h | 34 - .../libmv/simple_pipeline/camera_intrinsics.cc | 293 ---- .../libmv/simple_pipeline/camera_intrinsics.h | 406 ----- .../libmv/simple_pipeline/camera_intrinsics_impl.h | 192 --- .../simple_pipeline/camera_intrinsics_test.cc | 239 --- extern/libmv/libmv/simple_pipeline/detect.cc | 361 ----- extern/libmv/libmv/simple_pipeline/detect.h | 113 -- extern/libmv/libmv/simple_pipeline/detect_test.cc | 230 --- .../libmv/simple_pipeline/distortion_models.cc | 197 --- .../libmv/simple_pipeline/distortion_models.h | 131 -- .../simple_pipeline/initialize_reconstruction.cc | 195 --- .../simple_pipeline/initialize_reconstruction.h | 74 - extern/libmv/libmv/simple_pipeline/intersect.cc | 254 ---- extern/libmv/libmv/simple_pipeline/intersect.h | 77 - .../libmv/libmv/simple_pipeline/intersect_test.cc | 81 - .../libmv/simple_pipeline/keyframe_selection.cc | 450 ------ .../libmv/simple_pipeline/keyframe_selection.h | 53 - .../simple_pipeline/keyframe_selection_test.cc | 307 ---- extern/libmv/libmv/simple_pipeline/modal_solver.cc | 251 --- extern/libmv/libmv/simple_pipeline/modal_solver.h | 48 - .../libmv/simple_pipeline/modal_solver_test.cc | 79 - extern/libmv/libmv/simple_pipeline/pipeline.cc | 368 ----- extern/libmv/libmv/simple_pipeline/pipeline.h | 98 -- .../libmv/libmv/simple_pipeline/reconstruction.cc | 191 --- .../libmv/libmv/simple_pipeline/reconstruction.h | 217 --- .../libmv/simple_pipeline/reconstruction_scale.cc | 68 - .../libmv/simple_pipeline/reconstruction_scale.h | 36 - extern/libmv/libmv/simple_pipeline/resect.cc | 270 ---- extern/libmv/libmv/simple_pipeline/resect.h | 86 -- extern/libmv/libmv/simple_pipeline/resect_test.cc | 234 --- extern/libmv/libmv/simple_pipeline/tracks.cc | 187 --- extern/libmv/libmv/simple_pipeline/tracks.h | 138 -- .../libmv/libmv/tracking/brute_region_tracker.cc | 331 ---- extern/libmv/libmv/tracking/brute_region_tracker.h | 49 - .../libmv/tracking/brute_region_tracker_test.cc | 51 - .../libmv/libmv/tracking/hybrid_region_tracker.cc | 67 - .../libmv/libmv/tracking/hybrid_region_tracker.h | 52 - extern/libmv/libmv/tracking/kalman_filter.h | 112 -- extern/libmv/libmv/tracking/klt_region_tracker.cc | 162 -- extern/libmv/libmv/tracking/klt_region_tracker.h | 55 - .../libmv/tracking/klt_region_tracker_test.cc | 51 - .../libmv/libmv/tracking/pyramid_region_tracker.cc | 98 -- .../libmv/libmv/tracking/pyramid_region_tracker.h | 46 - .../libmv/tracking/pyramid_region_tracker_test.cc | 80 - extern/libmv/libmv/tracking/region_tracker.h | 48 - .../libmv/libmv/tracking/retrack_region_tracker.cc | 47 - .../libmv/libmv/tracking/retrack_region_tracker.h | 48 - extern/libmv/libmv/tracking/track_region.cc | 1601 -------------------- extern/libmv/libmv/tracking/track_region.h | 170 --- .../libmv/libmv/tracking/trklt_region_tracker.cc | 176 --- extern/libmv/libmv/tracking/trklt_region_tracker.h | 65 - extern/libmv/mkfiles.sh | 6 - extern/libmv/third_party/msinttypes/README.libmv | 5 - extern/libmv/third_party/msinttypes/inttypes.h | 305 ---- extern/libmv/third_party/msinttypes/stdint.h | 247 --- 169 files changed, 27995 deletions(-) delete mode 100644 extern/libmv/CMakeLists.txt delete mode 100644 extern/libmv/ChangeLog delete mode 100755 extern/libmv/bundle.sh delete mode 100644 extern/libmv/files.txt delete mode 100644 extern/libmv/intern/autotrack.cc delete mode 100644 extern/libmv/intern/autotrack.h delete mode 100644 extern/libmv/intern/camera_intrinsics.cc delete mode 100644 extern/libmv/intern/camera_intrinsics.h delete mode 100644 extern/libmv/intern/detector.cc delete mode 100644 extern/libmv/intern/detector.h delete mode 100644 extern/libmv/intern/frame_accessor.cc delete mode 100644 extern/libmv/intern/frame_accessor.h delete mode 100644 extern/libmv/intern/homography.cc delete mode 100644 extern/libmv/intern/homography.h delete mode 100644 extern/libmv/intern/image.cc delete mode 100644 extern/libmv/intern/image.h delete mode 100644 extern/libmv/intern/logging.cc delete mode 100644 extern/libmv/intern/logging.h delete mode 100644 extern/libmv/intern/reconstruction.cc delete mode 100644 extern/libmv/intern/reconstruction.h delete mode 100644 extern/libmv/intern/region.h delete mode 100644 extern/libmv/intern/stub.cc delete mode 100644 extern/libmv/intern/track_region.cc delete mode 100644 extern/libmv/intern/track_region.h delete mode 100644 extern/libmv/intern/tracks.cc delete mode 100644 extern/libmv/intern/tracks.h delete mode 100644 extern/libmv/intern/tracksN.cc delete mode 100644 extern/libmv/intern/tracksN.h delete mode 100644 extern/libmv/intern/utildefines.h delete mode 100644 extern/libmv/libmv-capi.h delete mode 100644 extern/libmv/libmv/autotrack/autotrack.cc delete mode 100644 extern/libmv/libmv/autotrack/autotrack.h delete mode 100644 extern/libmv/libmv/autotrack/callbacks.h delete mode 100644 extern/libmv/libmv/autotrack/frame_accessor.h delete mode 100644 extern/libmv/libmv/autotrack/marker.h delete mode 100644 extern/libmv/libmv/autotrack/model.h delete mode 100644 extern/libmv/libmv/autotrack/predict_tracks.cc delete mode 100644 extern/libmv/libmv/autotrack/predict_tracks.h delete mode 100644 extern/libmv/libmv/autotrack/predict_tracks_test.cc delete mode 100644 extern/libmv/libmv/autotrack/quad.h delete mode 100644 extern/libmv/libmv/autotrack/reconstruction.h delete mode 100644 extern/libmv/libmv/autotrack/region.h delete mode 100644 extern/libmv/libmv/autotrack/tracks.cc delete mode 100644 extern/libmv/libmv/autotrack/tracks.h delete mode 100644 extern/libmv/libmv/autotrack/tracks_test.cc delete mode 100644 extern/libmv/libmv/base/aligned_malloc.cc delete mode 100644 extern/libmv/libmv/base/aligned_malloc.h delete mode 100644 extern/libmv/libmv/base/id_generator.h delete mode 100644 extern/libmv/libmv/base/scoped_ptr.h delete mode 100644 extern/libmv/libmv/base/scoped_ptr_test.cc delete mode 100644 extern/libmv/libmv/base/vector.h delete mode 100644 extern/libmv/libmv/base/vector_test.cc delete mode 100644 extern/libmv/libmv/base/vector_utils.h delete mode 100644 extern/libmv/libmv/image/array_nd.cc delete mode 100644 extern/libmv/libmv/image/array_nd.h delete mode 100644 extern/libmv/libmv/image/array_nd_test.cc delete mode 100644 extern/libmv/libmv/image/convolve.cc delete mode 100644 extern/libmv/libmv/image/convolve.h delete mode 100644 extern/libmv/libmv/image/convolve_test.cc delete mode 100644 extern/libmv/libmv/image/correlation.h delete mode 100644 extern/libmv/libmv/image/image.h delete mode 100644 extern/libmv/libmv/image/image_converter.h delete mode 100644 extern/libmv/libmv/image/image_drawing.h delete mode 100644 extern/libmv/libmv/image/image_test.cc delete mode 100644 extern/libmv/libmv/image/sample.h delete mode 100644 extern/libmv/libmv/image/sample_test.cc delete mode 100644 extern/libmv/libmv/image/tuple.h delete mode 100644 extern/libmv/libmv/image/tuple_test.cc delete mode 100644 extern/libmv/libmv/logging/logging.h delete mode 100644 extern/libmv/libmv/multiview/conditioning.cc delete mode 100644 extern/libmv/libmv/multiview/conditioning.h delete mode 100644 extern/libmv/libmv/multiview/euclidean_resection.cc delete mode 100644 extern/libmv/libmv/multiview/euclidean_resection.h delete mode 100644 extern/libmv/libmv/multiview/euclidean_resection_test.cc delete mode 100644 extern/libmv/libmv/multiview/fundamental.cc delete mode 100644 extern/libmv/libmv/multiview/fundamental.h delete mode 100644 extern/libmv/libmv/multiview/fundamental_test.cc delete mode 100644 extern/libmv/libmv/multiview/homography.cc delete mode 100644 extern/libmv/libmv/multiview/homography.h delete mode 100644 extern/libmv/libmv/multiview/homography_error.h delete mode 100644 extern/libmv/libmv/multiview/homography_parameterization.h delete mode 100644 extern/libmv/libmv/multiview/homography_test.cc delete mode 100644 extern/libmv/libmv/multiview/nviewtriangulation.h delete mode 100644 extern/libmv/libmv/multiview/nviewtriangulation_test.cc delete mode 100644 extern/libmv/libmv/multiview/panography.cc delete mode 100644 extern/libmv/libmv/multiview/panography.h delete mode 100644 extern/libmv/libmv/multiview/panography_kernel.cc delete mode 100644 extern/libmv/libmv/multiview/panography_kernel.h delete mode 100644 extern/libmv/libmv/multiview/panography_test.cc delete mode 100644 extern/libmv/libmv/multiview/projection.cc delete mode 100644 extern/libmv/libmv/multiview/projection.h delete mode 100644 extern/libmv/libmv/multiview/projection_test.cc delete mode 100644 extern/libmv/libmv/multiview/resection.h delete mode 100644 extern/libmv/libmv/multiview/resection_test.cc delete mode 100644 extern/libmv/libmv/multiview/test_data_sets.cc delete mode 100644 extern/libmv/libmv/multiview/test_data_sets.h delete mode 100644 extern/libmv/libmv/multiview/triangulation.cc delete mode 100644 extern/libmv/libmv/multiview/triangulation.h delete mode 100644 extern/libmv/libmv/multiview/triangulation_test.cc delete mode 100644 extern/libmv/libmv/multiview/two_view_kernel.h delete mode 100644 extern/libmv/libmv/numeric/dogleg.h delete mode 100644 extern/libmv/libmv/numeric/dogleg_test.cc delete mode 100644 extern/libmv/libmv/numeric/function_derivative.h delete mode 100644 extern/libmv/libmv/numeric/function_derivative_test.cc delete mode 100644 extern/libmv/libmv/numeric/levenberg_marquardt.h delete mode 100644 extern/libmv/libmv/numeric/levenberg_marquardt_test.cc delete mode 100644 extern/libmv/libmv/numeric/numeric.cc delete mode 100644 extern/libmv/libmv/numeric/numeric.h delete mode 100644 extern/libmv/libmv/numeric/numeric_test.cc delete mode 100644 extern/libmv/libmv/numeric/poly.cc delete mode 100644 extern/libmv/libmv/numeric/poly.h delete mode 100644 extern/libmv/libmv/numeric/poly_test.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/bundle.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/bundle.h delete mode 100644 extern/libmv/libmv/simple_pipeline/callbacks.h delete mode 100644 extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/camera_intrinsics.h delete mode 100644 extern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h delete mode 100644 extern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/detect.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/detect.h delete mode 100644 extern/libmv/libmv/simple_pipeline/detect_test.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/distortion_models.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/distortion_models.h delete mode 100644 extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h delete mode 100644 extern/libmv/libmv/simple_pipeline/intersect.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/intersect.h delete mode 100644 extern/libmv/libmv/simple_pipeline/intersect_test.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/keyframe_selection.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/keyframe_selection.h delete mode 100644 extern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/modal_solver.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/modal_solver.h delete mode 100644 extern/libmv/libmv/simple_pipeline/modal_solver_test.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/pipeline.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/pipeline.h delete mode 100644 extern/libmv/libmv/simple_pipeline/reconstruction.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/reconstruction.h delete mode 100644 extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/reconstruction_scale.h delete mode 100644 extern/libmv/libmv/simple_pipeline/resect.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/resect.h delete mode 100644 extern/libmv/libmv/simple_pipeline/resect_test.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/tracks.cc delete mode 100644 extern/libmv/libmv/simple_pipeline/tracks.h delete mode 100644 extern/libmv/libmv/tracking/brute_region_tracker.cc delete mode 100644 extern/libmv/libmv/tracking/brute_region_tracker.h delete mode 100644 extern/libmv/libmv/tracking/brute_region_tracker_test.cc delete mode 100644 extern/libmv/libmv/tracking/hybrid_region_tracker.cc delete mode 100644 extern/libmv/libmv/tracking/hybrid_region_tracker.h delete mode 100644 extern/libmv/libmv/tracking/kalman_filter.h delete mode 100644 extern/libmv/libmv/tracking/klt_region_tracker.cc delete mode 100644 extern/libmv/libmv/tracking/klt_region_tracker.h delete mode 100644 extern/libmv/libmv/tracking/klt_region_tracker_test.cc delete mode 100644 extern/libmv/libmv/tracking/pyramid_region_tracker.cc delete mode 100644 extern/libmv/libmv/tracking/pyramid_region_tracker.h delete mode 100644 extern/libmv/libmv/tracking/pyramid_region_tracker_test.cc delete mode 100644 extern/libmv/libmv/tracking/region_tracker.h delete mode 100644 extern/libmv/libmv/tracking/retrack_region_tracker.cc delete mode 100644 extern/libmv/libmv/tracking/retrack_region_tracker.h delete mode 100644 extern/libmv/libmv/tracking/track_region.cc delete mode 100644 extern/libmv/libmv/tracking/track_region.h delete mode 100644 extern/libmv/libmv/tracking/trklt_region_tracker.cc delete mode 100644 extern/libmv/libmv/tracking/trklt_region_tracker.h delete mode 100755 extern/libmv/mkfiles.sh delete mode 100644 extern/libmv/third_party/msinttypes/README.libmv delete mode 100644 extern/libmv/third_party/msinttypes/inttypes.h delete mode 100644 extern/libmv/third_party/msinttypes/stdint.h (limited to 'extern/libmv') diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt deleted file mode 100644 index 375031fd1cb..00000000000 --- a/extern/libmv/CMakeLists.txt +++ /dev/null @@ -1,238 +0,0 @@ -# ***** 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) 2011, Blender Foundation -# All rights reserved. -# -# Contributor(s): Blender Foundation, -# Sergey Sharybin -# -# ***** END GPL LICENSE BLOCK ***** - -# NOTE: This file is automatically generated by bundle.sh script -# If you're doing changes in this file, please update template -# in that script too - -set(INC - . -) - -set(INC_SYS -) - -set(SRC - libmv-capi.h -) - -add_definitions(${GFLAGS_DEFINES}) -add_definitions(${GLOG_DEFINES}) -add_definitions(${CERES_DEFINES}) - -if(WITH_LIBMV) - list(APPEND INC - ../gflags/src - ../glog/src - third_party/ceres/include - third_party/ceres/config - ../../intern/guardedalloc - ) - - list(APPEND INC_SYS - ${EIGEN3_INCLUDE_DIRS} - ${PNG_INCLUDE_DIRS} - ${ZLIB_INCLUDE_DIRS} - ) - - add_definitions( - -DWITH_LIBMV_GUARDED_ALLOC - -DLIBMV_NO_FAST_DETECTOR= - ) - - list(APPEND SRC - intern/autotrack.cc - intern/camera_intrinsics.cc - intern/detector.cc - intern/frame_accessor.cc - intern/homography.cc - intern/image.cc - intern/logging.cc - intern/reconstruction.cc - intern/track_region.cc - intern/tracks.cc - intern/tracksN.cc - libmv/autotrack/autotrack.cc - libmv/autotrack/predict_tracks.cc - libmv/autotrack/tracks.cc - libmv/base/aligned_malloc.cc - libmv/image/array_nd.cc - libmv/image/convolve.cc - libmv/multiview/conditioning.cc - libmv/multiview/euclidean_resection.cc - libmv/multiview/fundamental.cc - libmv/multiview/homography.cc - libmv/multiview/panography.cc - libmv/multiview/panography_kernel.cc - libmv/multiview/projection.cc - libmv/multiview/triangulation.cc - libmv/numeric/numeric.cc - libmv/numeric/poly.cc - libmv/simple_pipeline/bundle.cc - libmv/simple_pipeline/camera_intrinsics.cc - libmv/simple_pipeline/detect.cc - libmv/simple_pipeline/distortion_models.cc - libmv/simple_pipeline/initialize_reconstruction.cc - libmv/simple_pipeline/intersect.cc - libmv/simple_pipeline/keyframe_selection.cc - libmv/simple_pipeline/modal_solver.cc - libmv/simple_pipeline/pipeline.cc - libmv/simple_pipeline/reconstruction.cc - libmv/simple_pipeline/reconstruction_scale.cc - libmv/simple_pipeline/resect.cc - libmv/simple_pipeline/tracks.cc - libmv/tracking/brute_region_tracker.cc - libmv/tracking/hybrid_region_tracker.cc - libmv/tracking/klt_region_tracker.cc - libmv/tracking/pyramid_region_tracker.cc - libmv/tracking/retrack_region_tracker.cc - libmv/tracking/track_region.cc - libmv/tracking/trklt_region_tracker.cc - - - intern/autotrack.h - intern/camera_intrinsics.h - intern/detector.h - intern/frame_accessor.h - intern/homography.h - intern/image.h - intern/logging.h - intern/reconstruction.h - intern/track_region.h - intern/tracks.h - intern/tracksN.h - libmv/autotrack/autotrack.h - libmv/autotrack/callbacks.h - libmv/autotrack/frame_accessor.h - libmv/autotrack/marker.h - libmv/autotrack/model.h - libmv/autotrack/predict_tracks.h - libmv/autotrack/quad.h - libmv/autotrack/reconstruction.h - libmv/autotrack/region.h - libmv/autotrack/tracks.h - libmv/base/aligned_malloc.h - libmv/base/id_generator.h - libmv/base/scoped_ptr.h - libmv/base/vector.h - libmv/base/vector_utils.h - libmv/image/array_nd.h - libmv/image/convolve.h - libmv/image/correlation.h - libmv/image/image_converter.h - libmv/image/image_drawing.h - libmv/image/image.h - libmv/image/sample.h - libmv/image/tuple.h - libmv/logging/logging.h - libmv/multiview/conditioning.h - libmv/multiview/euclidean_resection.h - libmv/multiview/fundamental.h - libmv/multiview/homography_error.h - libmv/multiview/homography.h - libmv/multiview/homography_parameterization.h - libmv/multiview/nviewtriangulation.h - libmv/multiview/panography.h - libmv/multiview/panography_kernel.h - libmv/multiview/projection.h - libmv/multiview/resection.h - libmv/multiview/triangulation.h - libmv/multiview/two_view_kernel.h - libmv/numeric/dogleg.h - libmv/numeric/function_derivative.h - libmv/numeric/levenberg_marquardt.h - libmv/numeric/numeric.h - libmv/numeric/poly.h - libmv/simple_pipeline/bundle.h - libmv/simple_pipeline/callbacks.h - libmv/simple_pipeline/camera_intrinsics.h - libmv/simple_pipeline/camera_intrinsics_impl.h - libmv/simple_pipeline/detect.h - libmv/simple_pipeline/distortion_models.h - libmv/simple_pipeline/initialize_reconstruction.h - libmv/simple_pipeline/intersect.h - libmv/simple_pipeline/keyframe_selection.h - libmv/simple_pipeline/modal_solver.h - libmv/simple_pipeline/pipeline.h - libmv/simple_pipeline/reconstruction.h - libmv/simple_pipeline/reconstruction_scale.h - libmv/simple_pipeline/resect.h - libmv/simple_pipeline/tracks.h - libmv/tracking/brute_region_tracker.h - libmv/tracking/hybrid_region_tracker.h - libmv/tracking/kalman_filter.h - libmv/tracking/klt_region_tracker.h - libmv/tracking/pyramid_region_tracker.h - libmv/tracking/region_tracker.h - libmv/tracking/retrack_region_tracker.h - libmv/tracking/track_region.h - libmv/tracking/trklt_region_tracker.h - - third_party/msinttypes/inttypes.h - third_party/msinttypes/stdint.h - ) - - - if(WITH_GTESTS) - blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "" "") - - BLENDER_SRC_GTEST("libmv_predict_tracks" "./libmv/autotrack/predict_tracks_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_tracks" "./libmv/autotrack/tracks_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_scoped_ptr" "./libmv/base/scoped_ptr_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_vector" "./libmv/base/vector_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_array_nd" "./libmv/image/array_nd_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_convolve" "./libmv/image/convolve_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_image" "./libmv/image/image_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_sample" "./libmv/image/sample_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_tuple" "./libmv/image/tuple_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_euclidean_resection" "./libmv/multiview/euclidean_resection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_fundamental" "./libmv/multiview/fundamental_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_homography" "./libmv/multiview/homography_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_nviewtriangulation" "./libmv/multiview/nviewtriangulation_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_panography" "./libmv/multiview/panography_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_projection" "./libmv/multiview/projection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_resection" "./libmv/multiview/resection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_triangulation" "./libmv/multiview/triangulation_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_dogleg" "./libmv/numeric/dogleg_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_function_derivative" "./libmv/numeric/function_derivative_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_levenberg_marquardt" "./libmv/numeric/levenberg_marquardt_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_numeric" "./libmv/numeric/numeric_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_poly" "./libmv/numeric/poly_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_camera_intrinsics" "./libmv/simple_pipeline/camera_intrinsics_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_detect" "./libmv/simple_pipeline/detect_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_intersect" "./libmv/simple_pipeline/intersect_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_keyframe_selection" "./libmv/simple_pipeline/keyframe_selection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_modal_solver" "./libmv/simple_pipeline/modal_solver_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_resect" "./libmv/simple_pipeline/resect_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_brute_region_tracker" "./libmv/tracking/brute_region_tracker_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_klt_region_tracker" "./libmv/tracking/klt_region_tracker_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - BLENDER_SRC_GTEST("libmv_pyramid_region_tracker" "./libmv/tracking/pyramid_region_tracker_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres") - endif() -else() - list(APPEND SRC - intern/stub.cc - ) -endif() - -blender_add_lib(extern_libmv "${SRC}" "${INC}" "${INC_SYS}") diff --git a/extern/libmv/ChangeLog b/extern/libmv/ChangeLog deleted file mode 100644 index 63c9963a22f..00000000000 --- a/extern/libmv/ChangeLog +++ /dev/null @@ -1,609 +0,0 @@ -commit d3537e3709fe11f42312e82cb1c9837c9e742385 -Author: Sergey Sharybin -Date: Sun Jan 3 14:17:10 2016 +0500 - - GLog/GFlags: Reduce difference between upstream and bundled versions - - Several things here: - - - Re-bundled sources using own fork with pull-requests applied on the sources. - - - Got rid of changes around include "config.h", it was needed by Blender to - make it's include directories configuration to work. This could be addressed - differently from Blender side. - - - Moved some customization to defines set by CMakeLists. - -commit 1ec37bba2cfbbf0d6568429fa3035ee2164c23e6 -Author: Sergey Sharybin -Date: Sat Jan 2 12:42:55 2016 +0500 - - GFlags linking errors fix for MSVC - -commit df7642b270e8e43685e9ffb404b59d7b226a9f60 -Author: Sergey Sharybin -Date: Thu Dec 31 17:56:12 2015 +0500 - - Alternative fix for missing prototype for a couple of functions - -commit 08f685797b7d776cdaa579136c82b15ddc6ffb30 -Author: Sergey Sharybin -Date: Thu Dec 31 17:33:05 2015 +0500 - - Update GFlags to the latest upstream version - - Makes it easier to synchronize some compiler/warning fixes. - -commit e0ef5b09203e3906a555e6c2010f25cb667da9cd -Author: Sergey Sharybin -Date: Thu Dec 31 16:15:59 2015 +0500 - - GLog: Solve some compilation warnings - - Those are actually sent to a pull-request, see - - https://github.com/google/glog/pull/81 - -commit 2072b213d4d3a55d099a063ed1e7331cc773454e -Author: Sergey Sharybin -Date: Thu Dec 31 16:13:53 2015 +0500 - - Add Martijn Berger to the AUTHORS file - -commit 4dd0770d98d67896e4f936356e281f63d927410e -Author: Martijn Berger -Date: Thu Dec 31 16:13:08 2015 +0500 - - Fix compilation error of Glog and Gflags with MSVC2015 - -commit 2712f42be2ad79e7d3a6c9905f6d8d1e3b7133ac -Author: Brecht Van Lommel -Date: Thu Dec 31 14:00:58 2015 +0500 - - Fix OS X (with 10.11 SDK) glog build errors due to using deprecated code. - - Some values are now restored to the ones from before the upgrade today. - -commit d249280fdf7c937fd6ebbc465508843a70aafd4c -Author: Sergey Sharybin -Date: Wed Dec 30 16:59:28 2015 +0500 - - Tweaks to Glog to support building on all platforms - - This makes it possible to compile Libmv on all platforms, - amount of hacks is lower, which could bring some warnings - up, but those are better be addressed via upstream which - is now rather active. - -commit 86c57750ddb857643fb5dd2c83b4953da83dd57d -Author: Sergey Sharybin -Date: Wed Dec 30 16:15:47 2015 +0500 - - Enable explicit Schur complement matrix by default - - Gives up to 2x speed up of camera solving process in average scene. - In the really huge one it might be slower, but that we need to investigate. - -commit d6c52a70b5a0664b7c74bda68f59a895fe8aa235 -Author: Sergey Sharybin -Date: Wed Dec 30 16:13:03 2015 +0500 - - Fix one frame memory leak when tracking last frame - -commit 6e2ac41d25d5923b2a62c96d27d919a36eff9b48 -Author: Brecht Van Lommel -Date: Wed Dec 30 16:11:24 2015 +0500 - - Motion tracking not workig with Xcode 7 on OS X. - - Caused by use of the uninitialized shape_ variable in Resize(). - -commit fc72ae06fb4ae559ac37d14d1b34d6669505cc86 -Author: Sergey Sharybin -Date: Wed Dec 30 15:56:40 2015 +0500 - - Update GLog to latest upstream - - Should fix issues building with MSVC2015. - -commit d4b2d15bd3d195074b074331354de96a1b51042f -Author: Sergey Sharybin -Date: Wed Dec 30 16:01:10 2015 +0500 - - Fix wrong README file reference - -commit 2b4aa0b7720cae9a408284834559bea9960157ee -Author: Keir Mierle -Date: Mon May 11 02:16:53 2015 -0700 - - Make README more informative for GitHub viewers - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D1295 - -commit 514e4491aea655d20be047ed87f002fb7854d5c9 -Author: Keir Mierle -Date: Mon May 11 01:54:09 2015 -0700 - - Simplify the modal solver Ceres cost function - - Fix test by flipping the quaternion. - - Reviewers: sergey - - Reviewed By: sergey - - Projects: #libmv - - Differential Revision: https://developer.blender.org/D756 - -commit e55fafd31f7d53d42af7c6b7df2eebe3c2568da9 -Author: Sergey Sharybin -Date: Wed Dec 31 19:05:51 2014 +0500 - - Synchronize MSVC compilation fixes from Blender - -commit 7d6020d2ec42c6cb2749bc891186b4880d26d40b -Author: Sergey Sharybin -Date: Wed Dec 31 15:32:07 2014 +0500 - - Update GLog to latest upstream revision 143 - - Mainly to solve compilation error with demangle.cc. - -commit 5dc746700eaf85cb674f0fb73ff3c1b49a7f6315 -Author: Sergey Sharybin -Date: Fri Dec 12 14:59:55 2014 +0500 - - Update GFlags to latest release 2.1.1 - - Main purpose of this (andsome of upcoming) update is to check if the - upstream sources are useable without any modifications for us. And if - not, then we'll need to consider moving some changes into upstream. - - This commit contains an one-to-one copy of the upstream GFlags library - and also changes namespace usage since it's changed in the upstream. - -commit 6fe6d75f7e90e161b44643b953f058a3829a5247 -Author: Sergey Sharybin -Date: Sat Nov 1 02:53:36 2014 +0500 - - Libmv: Code cleanup, mixed class/struct in declaration/definition - -commit d2a5f7953812d2d09765431b59c6c4ac72faf35b -Author: Sergey Sharybin -Date: Thu Oct 30 23:13:53 2014 +0500 - - Libmv: Support disabled color channels in tracking settings - - This was never ported to a new tracking pipeline and now it's done using - FrameAccessor::Transform routines. Quite striaghtforward, but i've changed - order of grayscale conversion in blender side with call of transform callback. - - This way it's much easier to perform rescaling in libmv side. - -commit d976e034cdf74b34860e0632d7b29713f47c5756 -Author: Keir Mierle -Date: Sat Aug 23 00:38:01 2014 -0700 - - Minor keyframe selection cleanups - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D757 - -commit bc99ca55dadfca89fde0f93764397c2fe028943d -Author: Sergey Sharybin -Date: Sat Aug 23 01:55:32 2014 +0600 - - implement backward prediction - - The title actually says it all, just extend current implementation - of PredictMarkerPosition() to cases when tracking happens in the reverse - order (from the end frame to start). - - it's still doesn't solve all the ambiguity happening in the function - in cases when one tracks the feature and then re-tracks it in order - to refine the sliding. This is considered a separate TODO for now and - will likely be solved by passing tracking direction to the prediction - function. - - Reviewers: keir - - Reviewed By: keir - - Differential Revision: https://developer.blender.org/D663 - -commit 5b87682d98df65ade02638bc6482d824cf0dd0b3 -Author: Keir Mierle -Date: Thu Aug 21 22:45:22 2014 -0700 - - Make libmv compile on Ubuntu 14.04 - - Reviewers: fsiddi - - Reviewed By: fsiddi - - Subscribers: sergey - - Differential Revision: https://developer.blender.org/D755 - -commit 0a81db623c458e0384b4f7060d1bcff8993fb469 -Author: Sergey Sharybin -Date: Wed Jul 23 00:42:00 2014 +0600 - - Fix wrong residual blocks counter - - This happened in cases when having zero-weighted tracks - and could lead to some assert failures on marking parameter - block constant. - -commit 2824dbac54cacf74828678be7a5c9fd960ce83e2 -Author: Sergey Sharybin -Date: Fri Jul 18 12:52:03 2014 +0600 - - Fix search area sliding issue - - The only way to do this is to store search region in floats - and round when we need to sample it. Otherwise you'll always - have sliding effect caused by rounding the issues, especially - when doing incremental offset (thing which happens in the - prediction code). - - Pretty much straightforward change apart from stuff to be kept - in mind: offset calculation int should happen relative to the - rounded search region. This is because tracker works in the space - of the search window image which get's rounded on the frame access, - - This makes API a bit creepy because frame accessor uses the same - Region struct as the search window in Marker and ideally we would - need to have either IntRegion or Region in order to make - Libmv fully track on what's getting rounded and when. - - Reviewers: keir - - Reviewed By: keir - - Differential Revision: https://developer.blender.org/D616 - -commit 04862c479332308be47a0f27361402444ace8880 -Author: Keir Mierle -Date: Fri May 9 23:00:03 2014 +0200 - - Start the automatic 2D tracking code - - This starts the 2D automatic tracking code. It is totally unfinished. - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D523 - -commit be679f67d807a2139c1f7d7e2ca45141940b30d5 -Author: Keir Mierle -Date: Fri May 9 14:36:04 2014 +0200 - - Also shift the search window - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D520 - -commit 66b8f5eef2633ebcde32a388fc14c60171011821 -Author: Keir Mierle -Date: Fri May 9 13:06:28 2014 +0200 - - Change the search region to absolute frame coordinates - - Smarter Eigen usage - - Better error logging - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D519 - -commit a08193319ae409fad8f08887eae1f79f02e91eaa -Author: Keir Mierle -Date: Fri May 9 12:02:47 2014 +0200 - - First cut at predictive tracing - - This adds a Kalman filter-based approach to predict where a marker - will go in the next frame to track. Hopefully this will make the - tracker work faster by avoiding lengthy searches. This code - compiles, but is otherwise untested, and likely does not work. - - Fix else branch - - Add some tests - - Update patch coordinates as well (and test) - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D518 - -commit 607ffb2f62b56e34a841abbb952d83e19cd1e23c -Author: Keir Mierle -Date: Thu May 8 16:05:28 2014 +0200 - - Add constructor to AutoTrack - -commit c39e20a0c27da3733804c3848454b5d4c4f0e66b -Author: Keir Mierle -Date: Thu May 8 16:04:20 2014 +0200 - - Fix GetMarker compilation issue - -commit 8dd93e431b6e44439c803bfd26ec2669b656177e -Author: Keir Mierle -Date: Thu May 8 15:50:26 2014 +0200 - - Expose GetMarker() in AutoTrack - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D516 - -commit 4405dff60ea08d454b64da1a7c0595d9328cf8a3 -Author: Keir Mierle -Date: Thu May 8 15:38:14 2014 +0200 - - Add public SetMarkers to AutoTrack - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D515 - -commit c90837f6db276a3b1f610eaad509155f6a43b24f -Author: Keir Mierle -Date: Thu May 8 15:17:48 2014 +0200 - - Make autotrack skeleton compile - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D514 - -commit be01baa2e82e36f63e548f073157e68d2ff870c0 -Author: Keir Mierle -Date: Wed May 7 18:48:55 2014 +0200 - - Add preliminary TrackMarkerToFrame in autotrack - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D509 - -commit 0cab028d591b3d08672ca86eb6c6e4ac1aacf1d0 -Author: Sergey Sharybin -Date: Wed May 7 17:59:11 2014 +0200 - - Remove assert from ArrayND Resize - - That assert broke initialization of arrays which doesn't - own the data since constructor uses Resize to set shape - and strides. - - Strides are still to be fixed, but that's for later. - -commit 64f9c118029a9351e9023e96527c120e1d724d5b -Author: Sergey Sharybin -Date: Wed May 7 17:42:21 2014 +0200 - - Fix ArrayND freeing the data it doesn't own - - Can't really guarantee it works fully correct now, - but at least this check is needed anyway and compilation - works just fine. - - Reviewers: keir - - Reviewed By: keir - - Differential Revision: https://developer.blender.org/D508 - -commit 0618f1c8e88dfc738cdde55784da80b889905e7c -Author: Keir Mierle -Date: Wed May 7 12:03:32 2014 +0200 - - Minor changes - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D505 - -commit 5c34335e1bb90c4ed701ee830c718ed4e20dbffa -Author: Sergey Sharybin -Date: Wed May 7 11:12:23 2014 +0200 - - Fix compilation error in frame accessor - - - int64 is not a standard type, we've got int64_t defined in - std int. We also have an msvc port of this header, so should - not be an issue. - - - Fixed inconsistency in usage of CacheKey and Key, used Key. - - - Some functions weren't marked as virtual. - - Additional change: added self to authors. - - Reviewers: keir - - Reviewed By: keir - - Differential Revision: https://developer.blender.org/D504 - -commit 06bc207614e262cd688e2c3ed820ade7c77bdb66 -Author: Keir Mierle -Date: Tue May 6 22:30:59 2014 +0200 - - Start new Tracks implementation - - This adds the new Tracks implementation, as well as a - trivial test to show it compiles. - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D502 - -commit 25ce061e6da69881460ba7718bb0d660a2380a02 -Author: Keir Mierle -Date: Tue May 6 19:10:51 2014 +0200 - - Add Reconstruction class for new API - - This starts the new Reconstruction class (with support for e.g. planes). This - also starts the new namespace "mv" which will eventually have all the symbols - we wish to export. - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D501 - -commit 0a6af3e29016048978aea607673340500e050339 -Author: Keir Mierle -Date: Tue May 6 17:52:53 2014 +0200 - - Add a new Tracks implementation - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D500 - -commit 887b68d29c2b198f4939f9ab5153881aa2c1806e -Author: Keir Mierle -Date: Tue May 6 17:01:39 2014 +0200 - - Initial commit of unfinished AutoTrack API - - This starts the creating the new AutoTrack API. The new API will - make it possible for libmv to do full autotracking, including - predictive tracking and also support multiple motion models (3D - planes etc). - - The first goal (not in this patch) is to convert Blender to use - the new API without adding any new functionality. - - Note: This does not add any of the API to the build system! - It likely does not compile. - - Reviewers: sergey - - Reviewed By: sergey - - Differential Revision: https://developer.blender.org/D499 - -commit 08cc227d431d257d27f300fbb8e6991e663302da -Author: Sergey Sharybin -Date: Tue May 6 13:09:22 2014 +0200 - - Fix homography test failure - - It was caused by assuming that reconstructed homography matrix - should look exactly the same as the matrix used to generate a - test case. - - It's not actually valid assumption because different-looking - matrices could correspond to the same exact transform. - - In this change we make it so actual "re-projected" vectors - are being checked, not the values in matrix. This makes it - more predictable verification. - - Reviewers: keir - - Reviewed By: keir - - Differential Revision: https://developer.blender.org/D488 - -commit 0b7d83dc9627447dc7df64d7e3a468aefe9ddc13 -Author: Sergey Sharybin -Date: Wed Apr 23 19:14:55 2014 +0600 - - Fix compilation on OSX after previous commit - - EXPECT_EQ wasn't defined in the scope. - -commit d14049e00dabf8fdf49056779f0a3718fbb39e8f -Author: Sergey Sharybin -Date: Wed Apr 23 15:08:16 2014 +0600 - - Move aligned malloc implementation into own file - - It was rather stupid having it in brute region tracker, - now it is in own file in base library (which was also - added in this commit, before this it consist of header - files only). - - Reviewers: keir - - Reviewed By: keir - - Differential Revision: https://developer.blender.org/D479 - -commit 0ddf3851bfcb8de43660b119a25a77a25674200d -Author: Sergey Sharybin -Date: Mon Apr 21 14:14:03 2014 +0600 - - Optimization of PearsonProductMomentCorrelation - - Pass the arrays by reference rather than by value, - should give some percent of speedup. - - Also don't pass the dimensions to the function but - get them from the images themselves. - - Hopefully this will give some %% of tracker speedup. - -commit f68fdbe5896a6c5bd8b500caeec61b876c5e44c6 -Author: Sergey Sharybin -Date: Mon Apr 21 14:10:43 2014 +0600 - - Fix wrong assert in ResizeImage() - - The assert didn't make any sense because ComputeBoundingBox() - is intended to return bounding box in the following way: - (xmin, xmax, ymin, ymax). - -commit 1d386b6775a71c499e9b8e4a288c0785c4937677 -Author: Sergey Sharybin -Date: Thu Apr 17 18:42:43 2014 +0600 - - Add unit tests for buffer (un)distortion - - Currently only uses identity camera intrinsics just to - see whether lookup grids are properly allocated. - - Should prevent accidents like that one happened recently - with crashing Blender after Libmv re-integration. diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh deleted file mode 100755 index 273365bb31a..00000000000 --- a/extern/libmv/bundle.sh +++ /dev/null @@ -1,187 +0,0 @@ -#!/bin/sh - -if [ "x$1" = "x--i-really-know-what-im-doing" ] ; then - echo Proceeding as requested by command line ... -else - echo "*** Please run again with --i-really-know-what-im-doing ..." - exit 1 -fi - -BRANCH="master" - -repo="git://git.blender.org/libmv.git" -tmp=`mktemp -d` - -git clone -b $BRANCH $repo $tmp/libmv - -git --git-dir $tmp/libmv/.git --work-tree $tmp/libmv log -n 50 > ChangeLog - -find libmv -type f -exec rm -rf {} \; -find third_party -type f -exec rm -rf {} \; - -cat "files.txt" | while read f; do - mkdir -p `dirname $f` - cp $tmp/libmv/src/$f $f -done - -rm -rf $tmp - -sources=`find ./libmv -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep -v _test.cc | grep -v test_data_sets | sed -r 's/^\.\//\t\t/' | sort -d` -headers=`find ./libmv -type f -iname '*.h' | grep -v test_data_sets | sed -r 's/^\.\//\t\t/' | sort -d` - -third_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t\t/' | sort -d` -third_headers=`find ./third_party -type f -iname '*.h' | sed -r 's/^\.\//\t\t/' | sort -d` - -tests=`find ./libmv -type f -iname '*_test.cc' | sort -d | awk ' { name=gensub(".*/([A-Za-z_]+)_test.cc", "\\\\1", $1); printf("\t\tBLENDER_SRC_GTEST(\"libmv_%s\" \"%s\" \"libmv_test_dataset;extern_libmv;extern_ceres\")\n", name, $1) } '` - -src_dir=`find ./libmv -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t\t/' | sort -d | uniq` -src_third_dir=`find ./third_party -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t\t/' | sort -d | uniq` -src="" -win_src="" -for x in $src_dir $src_third_dir; do - t="" - - if stat $x/*.cpp > /dev/null 2>&1; then - t=" src += env.Glob('`echo $x'/*.cpp'`')" - fi - - if stat $x/*.c > /dev/null 2>&1; then - if [ -z "$t" ]; then - t=" src += env.Glob('`echo $x'/*.c'`')" - else - t="$t + env.Glob('`echo $x'/*.c'`')" - fi - fi - - if stat $x/*.cc > /dev/null 2>&1; then - if [ -z "$t" ]; then - t=" src += env.Glob('`echo $x'/*.cc'`')" - else - t="$t + env.Glob('`echo $x'/*.cc'`')" - fi - fi - - if test `echo $x | grep -c "windows\|gflags" ` -eq 0; then - if [ -z "$src" ]; then - src=$t - else - src=`echo "$src\n$t"` - fi - else - if [ -z "$win_src" ]; then - win_src=`echo " $t"` - else - win_src=`echo "$win_src\n $t"` - fi - fi -done - -cat > CMakeLists.txt << EOF -# ***** 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) 2011, Blender Foundation -# All rights reserved. -# -# Contributor(s): Blender Foundation, -# Sergey Sharybin -# -# ***** END GPL LICENSE BLOCK ***** - -# NOTE: This file is automatically generated by bundle.sh script -# If you're doing changes in this file, please update template -# in that script too - -set(INC - . -) - -set(INC_SYS -) - -set(SRC - libmv-capi.h -) - -add_definitions(\${GFLAGS_DEFINES}) -add_definitions(\${GLOG_DEFINES}) -add_definitions(\${CERES_DEFINES}) - -if(WITH_LIBMV) - list(APPEND INC - ../gflags/src - ../glog/src - third_party/ceres/include - third_party/ceres/config - ../../intern/guardedalloc - ) - - list(APPEND INC_SYS - \${EIGEN3_INCLUDE_DIRS} - \${PNG_INCLUDE_DIRS} - \${ZLIB_INCLUDE_DIRS} - ) - - add_definitions( - -DWITH_LIBMV_GUARDED_ALLOC - -DLIBMV_NO_FAST_DETECTOR= - ) - - list(APPEND SRC - intern/autotrack.cc - intern/camera_intrinsics.cc - intern/detector.cc - intern/frame_accessor.cc - intern/homography.cc - intern/image.cc - intern/logging.cc - intern/reconstruction.cc - intern/track_region.cc - intern/tracks.cc - intern/tracksN.cc -${sources} -${third_sources} - - intern/autotrack.h - intern/camera_intrinsics.h - intern/detector.h - intern/frame_accessor.h - intern/homography.h - intern/image.h - intern/logging.h - intern/reconstruction.h - intern/track_region.h - intern/tracks.h - intern/tracksN.h -${headers} - -${third_headers} - ) - - - if(WITH_GTESTS) - blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "${INC}" "${INC_SYS}") - -${tests} - endif() -else() - list(APPEND SRC - intern/stub.cc - ) -endif() - -blender_add_lib(extern_libmv "\${SRC}" "\${INC}" "\${INC_SYS}") -EOF diff --git a/extern/libmv/files.txt b/extern/libmv/files.txt deleted file mode 100644 index 223066bb02f..00000000000 --- a/extern/libmv/files.txt +++ /dev/null @@ -1,138 +0,0 @@ -libmv/autotrack/autotrack.cc -libmv/autotrack/autotrack.h -libmv/autotrack/callbacks.h -libmv/autotrack/frame_accessor.h -libmv/autotrack/marker.h -libmv/autotrack/model.h -libmv/autotrack/predict_tracks.cc -libmv/autotrack/predict_tracks.h -libmv/autotrack/predict_tracks_test.cc -libmv/autotrack/quad.h -libmv/autotrack/reconstruction.h -libmv/autotrack/region.h -libmv/autotrack/tracks.cc -libmv/autotrack/tracks.h -libmv/autotrack/tracks_test.cc -libmv/base/aligned_malloc.cc -libmv/base/aligned_malloc.h -libmv/base/id_generator.h -libmv/base/scoped_ptr.h -libmv/base/scoped_ptr_test.cc -libmv/base/vector.h -libmv/base/vector_test.cc -libmv/base/vector_utils.h -libmv/image/array_nd.cc -libmv/image/array_nd.h -libmv/image/array_nd_test.cc -libmv/image/convolve.cc -libmv/image/convolve.h -libmv/image/convolve_test.cc -libmv/image/correlation.h -libmv/image/image_converter.h -libmv/image/image_drawing.h -libmv/image/image.h -libmv/image/image_test.cc -libmv/image/sample.h -libmv/image/sample_test.cc -libmv/image/tuple.h -libmv/image/tuple_test.cc -libmv/logging/logging.h -libmv/multiview/conditioning.cc -libmv/multiview/conditioning.h -libmv/multiview/euclidean_resection.cc -libmv/multiview/euclidean_resection.h -libmv/multiview/euclidean_resection_test.cc -libmv/multiview/fundamental.cc -libmv/multiview/fundamental.h -libmv/multiview/fundamental_test.cc -libmv/multiview/homography.cc -libmv/multiview/homography_error.h -libmv/multiview/homography.h -libmv/multiview/homography_parameterization.h -libmv/multiview/homography_test.cc -libmv/multiview/nviewtriangulation.h -libmv/multiview/nviewtriangulation_test.cc -libmv/multiview/panography.cc -libmv/multiview/panography.h -libmv/multiview/panography_kernel.cc -libmv/multiview/panography_kernel.h -libmv/multiview/panography_test.cc -libmv/multiview/projection.cc -libmv/multiview/projection.h -libmv/multiview/projection_test.cc -libmv/multiview/resection.h -libmv/multiview/resection_test.cc -libmv/multiview/test_data_sets.cc -libmv/multiview/test_data_sets.h -libmv/multiview/triangulation.cc -libmv/multiview/triangulation.h -libmv/multiview/triangulation_test.cc -libmv/multiview/two_view_kernel.h -libmv/numeric/dogleg.h -libmv/numeric/dogleg_test.cc -libmv/numeric/function_derivative.h -libmv/numeric/function_derivative_test.cc -libmv/numeric/levenberg_marquardt.h -libmv/numeric/levenberg_marquardt_test.cc -libmv/numeric/numeric.cc -libmv/numeric/numeric.h -libmv/numeric/numeric_test.cc -libmv/numeric/poly.cc -libmv/numeric/poly.h -libmv/numeric/poly_test.cc -libmv/simple_pipeline/bundle.cc -libmv/simple_pipeline/bundle.h -libmv/simple_pipeline/callbacks.h -libmv/simple_pipeline/camera_intrinsics.cc -libmv/simple_pipeline/camera_intrinsics.h -libmv/simple_pipeline/camera_intrinsics_impl.h -libmv/simple_pipeline/camera_intrinsics_test.cc -libmv/simple_pipeline/detect.cc -libmv/simple_pipeline/detect.h -libmv/simple_pipeline/detect_test.cc -libmv/simple_pipeline/distortion_models.cc -libmv/simple_pipeline/distortion_models.h -libmv/simple_pipeline/initialize_reconstruction.cc -libmv/simple_pipeline/initialize_reconstruction.h -libmv/simple_pipeline/intersect.cc -libmv/simple_pipeline/intersect.h -libmv/simple_pipeline/intersect_test.cc -libmv/simple_pipeline/keyframe_selection.cc -libmv/simple_pipeline/keyframe_selection.h -libmv/simple_pipeline/keyframe_selection_test.cc -libmv/simple_pipeline/modal_solver.cc -libmv/simple_pipeline/modal_solver.h -libmv/simple_pipeline/modal_solver_test.cc -libmv/simple_pipeline/pipeline.cc -libmv/simple_pipeline/pipeline.h -libmv/simple_pipeline/reconstruction.cc -libmv/simple_pipeline/reconstruction.h -libmv/simple_pipeline/reconstruction_scale.cc -libmv/simple_pipeline/reconstruction_scale.h -libmv/simple_pipeline/resect.cc -libmv/simple_pipeline/resect.h -libmv/simple_pipeline/resect_test.cc -libmv/simple_pipeline/tracks.cc -libmv/simple_pipeline/tracks.h -libmv/tracking/brute_region_tracker.cc -libmv/tracking/brute_region_tracker.h -libmv/tracking/brute_region_tracker_test.cc -libmv/tracking/hybrid_region_tracker.cc -libmv/tracking/hybrid_region_tracker.h -libmv/tracking/kalman_filter.h -libmv/tracking/klt_region_tracker.cc -libmv/tracking/klt_region_tracker.h -libmv/tracking/klt_region_tracker_test.cc -libmv/tracking/pyramid_region_tracker.cc -libmv/tracking/pyramid_region_tracker.h -libmv/tracking/pyramid_region_tracker_test.cc -libmv/tracking/region_tracker.h -libmv/tracking/retrack_region_tracker.cc -libmv/tracking/retrack_region_tracker.h -libmv/tracking/track_region.cc -libmv/tracking/track_region.h -libmv/tracking/trklt_region_tracker.cc -libmv/tracking/trklt_region_tracker.h -third_party/msinttypes/inttypes.h -third_party/msinttypes/README.libmv -third_party/msinttypes/stdint.h diff --git a/extern/libmv/intern/autotrack.cc b/extern/libmv/intern/autotrack.cc deleted file mode 100644 index f0cbc68f11e..00000000000 --- a/extern/libmv/intern/autotrack.cc +++ /dev/null @@ -1,99 +0,0 @@ -/* - * ***** 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) 2014 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/autotrack.h" -#include "intern/tracksN.h" -#include "intern/utildefines.h" -#include "libmv/autotrack/autotrack.h" - -using mv::AutoTrack; -using mv::FrameAccessor; -using mv::Marker; -using libmv::TrackRegionOptions; -using libmv::TrackRegionResult; - -libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor *frame_accessor) { - return (libmv_AutoTrack*) LIBMV_OBJECT_NEW(AutoTrack, - (FrameAccessor*) frame_accessor); -} - -void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack) { - LIBMV_OBJECT_DELETE(libmv_autotrack, AutoTrack); -} - -void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack, - const libmv_AutoTrackOptions* options) { - AutoTrack *autotrack = ((AutoTrack*) libmv_autotrack); - libmv_configureTrackRegionOptions(options->track_region, - &autotrack->options.track_region); - - autotrack->options.search_region.min(0) = options->search_region.min[0]; - autotrack->options.search_region.min(1) = options->search_region.min[1]; - autotrack->options.search_region.max(0) = options->search_region.max[0]; - autotrack->options.search_region.max(1) = options->search_region.max[1]; -} - -int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack, - const libmv_TrackRegionOptions* libmv_options, - libmv_Marker *libmv_tracked_marker, - libmv_TrackRegionResult* libmv_result) { - - Marker tracked_marker; - TrackRegionOptions options; - TrackRegionResult result; - libmv_apiMarkerToMarker(*libmv_tracked_marker, &tracked_marker); - libmv_configureTrackRegionOptions(*libmv_options, - &options); - (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker, - &result, - &options)); - libmv_markerToApiMarker(tracked_marker, libmv_tracked_marker); - libmv_regionTrackergetResult(result, libmv_result); - return result.is_usable(); -} - -void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack, - const libmv_Marker* libmv_marker) { - Marker marker; - libmv_apiMarkerToMarker(*libmv_marker, &marker); - ((AutoTrack*) libmv_autotrack)->AddMarker(marker); -} - -int libmv_autoTrackGetMarker(libmv_AutoTrack* libmv_autotrack, - int clip, - int frame, - int track, - libmv_Marker *libmv_marker) { - Marker marker; - int ok = ((AutoTrack*) libmv_autotrack)->GetMarker(clip, - frame, - track, - &marker); - if (ok) { - libmv_markerToApiMarker(marker, libmv_marker); - } - return ok; -} diff --git a/extern/libmv/intern/autotrack.h b/extern/libmv/intern/autotrack.h deleted file mode 100644 index 2a4a8f3c97f..00000000000 --- a/extern/libmv/intern/autotrack.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ***** 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) 2014 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_AUTOTRACK_H_ -#define LIBMV_C_API_AUTOTRACK_H_ - -#include "intern/frame_accessor.h" -#include "intern/tracksN.h" -#include "intern/track_region.h" -#include "intern/region.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct libmv_AutoTrack libmv_AutoTrack; - -typedef struct libmv_AutoTrackOptions { - libmv_TrackRegionOptions track_region; - libmv_Region search_region; -} libmv_AutoTrackOptions; - -libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor *frame_accessor); - -void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack); - -void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack, - const libmv_AutoTrackOptions* options); - -int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack, - const libmv_TrackRegionOptions* libmv_options, - libmv_Marker *libmv_tracker_marker, - libmv_TrackRegionResult* libmv_result); - -void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack, - const libmv_Marker* libmv_marker); - -int libmv_autoTrackGetMarker(libmv_AutoTrack* libmv_autotrack, - int clip, - int frame, - int track, - libmv_Marker *libmv_marker); - -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_C_API_TRACKS_H_ diff --git a/extern/libmv/intern/camera_intrinsics.cc b/extern/libmv/intern/camera_intrinsics.cc deleted file mode 100644 index 0ce757cc93b..00000000000 --- a/extern/libmv/intern/camera_intrinsics.cc +++ /dev/null @@ -1,355 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/camera_intrinsics.h" -#include "intern/utildefines.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" - -using libmv::CameraIntrinsics; -using libmv::DivisionCameraIntrinsics; -using libmv::PolynomialCameraIntrinsics; - -libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) { - CameraIntrinsics *camera_intrinsics = - libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); - return (libmv_CameraIntrinsics *) camera_intrinsics; -} - -libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( - const libmv_CameraIntrinsics* libmv_intrinsics) { - const CameraIntrinsics *orig_intrinsics = - (const CameraIntrinsics *) libmv_intrinsics; - - CameraIntrinsics *new_intrinsics = NULL; - switch (orig_intrinsics->GetDistortionModelType()) { - case libmv::DISTORTION_MODEL_POLYNOMIAL: - { - const PolynomialCameraIntrinsics *polynomial_intrinsics = - static_cast(orig_intrinsics); - new_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics, - *polynomial_intrinsics); - break; - } - case libmv::DISTORTION_MODEL_DIVISION: - { - const DivisionCameraIntrinsics *division_intrinsics = - static_cast(orig_intrinsics); - new_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics, - *division_intrinsics); - break; - } - default: - assert(!"Unknown distortion model"); - } - return (libmv_CameraIntrinsics *) new_intrinsics; -} - -void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics) { - LIBMV_OBJECT_DELETE(libmv_intrinsics, CameraIntrinsics); -} - -void libmv_cameraIntrinsicsUpdate( - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - libmv_CameraIntrinsics* libmv_intrinsics) { - CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; - - double focal_length = libmv_camera_intrinsics_options->focal_length; - double principal_x = libmv_camera_intrinsics_options->principal_point_x; - double principal_y = libmv_camera_intrinsics_options->principal_point_y; - int image_width = libmv_camera_intrinsics_options->image_width; - int image_height = libmv_camera_intrinsics_options->image_height; - - /* Try avoid unnecessary updates, so pre-computed distortion grids - * are not freed. - */ - - if (camera_intrinsics->focal_length() != focal_length) { - camera_intrinsics->SetFocalLength(focal_length, focal_length); - } - - if (camera_intrinsics->principal_point_x() != principal_x || - camera_intrinsics->principal_point_y() != principal_y) { - camera_intrinsics->SetPrincipalPoint(principal_x, principal_y); - } - - if (camera_intrinsics->image_width() != image_width || - camera_intrinsics->image_height() != image_height) { - camera_intrinsics->SetImageSize(image_width, image_height); - } - - switch (libmv_camera_intrinsics_options->distortion_model) { - case LIBMV_DISTORTION_MODEL_POLYNOMIAL: - { - assert(camera_intrinsics->GetDistortionModelType() == - libmv::DISTORTION_MODEL_POLYNOMIAL); - - PolynomialCameraIntrinsics *polynomial_intrinsics = - (PolynomialCameraIntrinsics *) camera_intrinsics; - - double k1 = libmv_camera_intrinsics_options->polynomial_k1; - double k2 = libmv_camera_intrinsics_options->polynomial_k2; - double k3 = libmv_camera_intrinsics_options->polynomial_k3; - - if (polynomial_intrinsics->k1() != k1 || - polynomial_intrinsics->k2() != k2 || - polynomial_intrinsics->k3() != k3) { - polynomial_intrinsics->SetRadialDistortion(k1, k2, k3); - } - break; - } - - case LIBMV_DISTORTION_MODEL_DIVISION: - { - assert(camera_intrinsics->GetDistortionModelType() == - libmv::DISTORTION_MODEL_DIVISION); - - DivisionCameraIntrinsics *division_intrinsics = - (DivisionCameraIntrinsics *) camera_intrinsics; - - double k1 = libmv_camera_intrinsics_options->division_k1; - double k2 = libmv_camera_intrinsics_options->division_k2; - - if (division_intrinsics->k1() != k1 || - division_intrinsics->k2() != k2) { - division_intrinsics->SetDistortion(k1, k2); - } - - break; - } - - default: - assert(!"Unknown distortion model"); - } -} - -void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics, - int threads) { - CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; - camera_intrinsics->SetThreads(threads); -} - -void libmv_cameraIntrinsicsExtractOptions( - const libmv_CameraIntrinsics* libmv_intrinsics, - libmv_CameraIntrinsicsOptions* camera_intrinsics_options) { - const CameraIntrinsics *camera_intrinsics = - (const CameraIntrinsics *) libmv_intrinsics; - - // Fill in options which are common for all distortion models. - camera_intrinsics_options->focal_length = camera_intrinsics->focal_length(); - camera_intrinsics_options->principal_point_x = - camera_intrinsics->principal_point_x(); - camera_intrinsics_options->principal_point_y = - camera_intrinsics->principal_point_y(); - - camera_intrinsics_options->image_width = camera_intrinsics->image_width(); - camera_intrinsics_options->image_height = camera_intrinsics->image_height(); - - switch (camera_intrinsics->GetDistortionModelType()) { - case libmv::DISTORTION_MODEL_POLYNOMIAL: - { - const PolynomialCameraIntrinsics *polynomial_intrinsics = - static_cast(camera_intrinsics); - camera_intrinsics_options->distortion_model = - LIBMV_DISTORTION_MODEL_POLYNOMIAL; - camera_intrinsics_options->polynomial_k1 = polynomial_intrinsics->k1(); - camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2(); - camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3(); - camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1(); - camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p2(); - break; - } - - case libmv::DISTORTION_MODEL_DIVISION: - { - const DivisionCameraIntrinsics *division_intrinsics = - static_cast(camera_intrinsics); - camera_intrinsics_options->distortion_model = - LIBMV_DISTORTION_MODEL_DIVISION; - camera_intrinsics_options->division_k1 = division_intrinsics->k1(); - camera_intrinsics_options->division_k2 = division_intrinsics->k2(); - break; - } - - default: - assert(!"Uknown distortion model"); - } -} - -void libmv_cameraIntrinsicsUndistortByte( - const libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, - int width, - int height, - float overscan, - int channels, - unsigned char* destination_image) { - CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; - camera_intrinsics->UndistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); -} - -void libmv_cameraIntrinsicsUndistortFloat( - const libmv_CameraIntrinsics* libmv_intrinsics, - const float* source_image, - int width, - int height, - float overscan, - int channels, - float* destination_image) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; - intrinsics->UndistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); -} - -void libmv_cameraIntrinsicsDistortByte( - const struct libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, - int width, - int height, - float overscan, - int channels, - unsigned char *destination_image) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; - intrinsics->DistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); -} - -void libmv_cameraIntrinsicsDistortFloat( - const libmv_CameraIntrinsics* libmv_intrinsics, - float* source_image, - int width, - int height, - float overscan, - int channels, - float* destination_image) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; - intrinsics->DistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); -} - -void libmv_cameraIntrinsicsApply( - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - double x, - double y, - double* x1, - double* y1) { - /* Do a lens distortion if focal length is non-zero only. */ - if (libmv_camera_intrinsics_options->focal_length) { - CameraIntrinsics* camera_intrinsics = - libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); - camera_intrinsics->ApplyIntrinsics(x, y, x1, y1); - LIBMV_OBJECT_DELETE(camera_intrinsics, CameraIntrinsics); - } -} - -void libmv_cameraIntrinsicsInvert( - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - double x, - double y, - double* x1, - double* y1) { - /* Do a lens un-distortion if focal length is non-zero only/ */ - if (libmv_camera_intrinsics_options->focal_length) { - CameraIntrinsics *camera_intrinsics = - libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); - camera_intrinsics->InvertIntrinsics(x, y, x1, y1); - LIBMV_OBJECT_DELETE(camera_intrinsics, CameraIntrinsics); - } -} - -static void libmv_cameraIntrinsicsFillFromOptions( - const libmv_CameraIntrinsicsOptions* camera_intrinsics_options, - CameraIntrinsics* camera_intrinsics) { - camera_intrinsics->SetFocalLength(camera_intrinsics_options->focal_length, - camera_intrinsics_options->focal_length); - - camera_intrinsics->SetPrincipalPoint( - camera_intrinsics_options->principal_point_x, - camera_intrinsics_options->principal_point_y); - - camera_intrinsics->SetImageSize(camera_intrinsics_options->image_width, - camera_intrinsics_options->image_height); - - switch (camera_intrinsics_options->distortion_model) { - case LIBMV_DISTORTION_MODEL_POLYNOMIAL: - { - PolynomialCameraIntrinsics *polynomial_intrinsics = - static_cast(camera_intrinsics); - - polynomial_intrinsics->SetRadialDistortion( - camera_intrinsics_options->polynomial_k1, - camera_intrinsics_options->polynomial_k2, - camera_intrinsics_options->polynomial_k3); - - break; - } - - case LIBMV_DISTORTION_MODEL_DIVISION: - { - DivisionCameraIntrinsics *division_intrinsics = - static_cast(camera_intrinsics); - - division_intrinsics->SetDistortion( - camera_intrinsics_options->division_k1, - camera_intrinsics_options->division_k2); - break; - } - - default: - assert(!"Unknown distortion model"); - } -} - -CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( - const libmv_CameraIntrinsicsOptions* camera_intrinsics_options) { - CameraIntrinsics *camera_intrinsics = NULL; - switch (camera_intrinsics_options->distortion_model) { - case LIBMV_DISTORTION_MODEL_POLYNOMIAL: - camera_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics); - break; - case LIBMV_DISTORTION_MODEL_DIVISION: - camera_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics); - break; - default: - assert(!"Unknown distortion model"); - } - libmv_cameraIntrinsicsFillFromOptions(camera_intrinsics_options, - camera_intrinsics); - return camera_intrinsics; -} diff --git a/extern/libmv/intern/camera_intrinsics.h b/extern/libmv/intern/camera_intrinsics.h deleted file mode 100644 index 9910d16a108..00000000000 --- a/extern/libmv/intern/camera_intrinsics.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_CAMERA_INTRINSICS_H_ -#define LIBMV_C_API_CAMERA_INTRINSICS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct libmv_CameraIntrinsics libmv_CameraIntrinsics; - -enum { - LIBMV_DISTORTION_MODEL_POLYNOMIAL = 0, - LIBMV_DISTORTION_MODEL_DIVISION = 1, -}; - -typedef struct libmv_CameraIntrinsicsOptions { - // Common settings of all distortion models. - int distortion_model; - int image_width, image_height; - double focal_length; - double principal_point_x, principal_point_y; - - // Radial distortion model. - double polynomial_k1, polynomial_k2, polynomial_k3; - double polynomial_p1, polynomial_p2; - - // Division distortion model. - double division_k1, division_k2; -} libmv_CameraIntrinsicsOptions; - -libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options); - -libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( - const libmv_CameraIntrinsics* libmv_intrinsics); - -void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics); -void libmv_cameraIntrinsicsUpdate( - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - libmv_CameraIntrinsics* libmv_intrinsics); - -void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics, - int threads); - -void libmv_cameraIntrinsicsExtractOptions( - const libmv_CameraIntrinsics* libmv_intrinsics, - libmv_CameraIntrinsicsOptions* camera_intrinsics_options); - -void libmv_cameraIntrinsicsUndistortByte( - const libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, - int width, - int height, - float overscan, - int channels, - unsigned char* destination_image); - -void libmv_cameraIntrinsicsUndistortFloat( - const libmv_CameraIntrinsics* libmv_intrinsics, - const float* source_image, - int width, - int height, - float overscan, - int channels, - float* destination_image); - -void libmv_cameraIntrinsicsDistortByte( - const struct libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, - int width, - int height, - float overscan, - int channels, - unsigned char *destination_image); - -void libmv_cameraIntrinsicsDistortFloat( - const libmv_CameraIntrinsics* libmv_intrinsics, - float* source_image, - int width, - int height, - float overscan, - int channels, - float* destination_image); - -void libmv_cameraIntrinsicsApply( - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - double x, - double y, - double* x1, - double* y1); - -void libmv_cameraIntrinsicsInvert( - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - double x, - double y, - double* x1, - double* y1); - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus - -namespace libmv { - class CameraIntrinsics; -} - -libmv::CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( - const libmv_CameraIntrinsicsOptions* camera_intrinsics_options); -#endif - -#endif // LIBMV_C_API_CAMERA_INTRINSICS_H_ diff --git a/extern/libmv/intern/detector.cc b/extern/libmv/intern/detector.cc deleted file mode 100644 index 8abc9014115..00000000000 --- a/extern/libmv/intern/detector.cc +++ /dev/null @@ -1,148 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/detector.h" -#include "intern/image.h" -#include "intern/utildefines.h" -#include "libmv/simple_pipeline/detect.h" - -using libmv::Detect; -using libmv::DetectOptions; -using libmv::Feature; -using libmv::FloatImage; - -struct libmv_Features { - int count; - Feature* features; -}; - -namespace { - -libmv_Features *libmv_featuresFromVector( - const libmv::vector& features) { - libmv_Features* libmv_features = LIBMV_STRUCT_NEW(libmv_Features, 1); - int count = features.size(); - if (count) { - libmv_features->features = LIBMV_STRUCT_NEW(Feature, count); - for (int i = 0; i < count; i++) { - libmv_features->features[i] = features.at(i); - } - } else { - libmv_features->features = NULL; - } - libmv_features->count = count; - return libmv_features; -} - -void libmv_convertDetectorOptions(libmv_DetectOptions *options, - DetectOptions *detector_options) { - switch (options->detector) { -#define LIBMV_CONVERT(the_detector) \ - case LIBMV_DETECTOR_ ## the_detector: \ - detector_options->type = DetectOptions::the_detector; \ - break; - LIBMV_CONVERT(FAST) - LIBMV_CONVERT(MORAVEC) - LIBMV_CONVERT(HARRIS) -#undef LIBMV_CONVERT - } - detector_options->margin = options->margin; - detector_options->min_distance = options->min_distance; - detector_options->fast_min_trackness = options->fast_min_trackness; - detector_options->moravec_max_count = options->moravec_max_count; - detector_options->moravec_pattern = options->moravec_pattern; - detector_options->harris_threshold = options->harris_threshold; -} - -} // namespace - -libmv_Features *libmv_detectFeaturesByte(const unsigned char* image_buffer, - int width, - int height, - int channels, - libmv_DetectOptions* options) { - // Prepare the image. - FloatImage image; - libmv_byteBufferToFloatImage(image_buffer, width, height, channels, &image); - - // Configure detector. - DetectOptions detector_options; - libmv_convertDetectorOptions(options, &detector_options); - - // Run the detector. - libmv::vector detected_features; - Detect(image, detector_options, &detected_features); - - // Convert result to C-API. - libmv_Features* result = libmv_featuresFromVector(detected_features); - return result; -} - -libmv_Features* libmv_detectFeaturesFloat(const float* image_buffer, - int width, - int height, - int channels, - libmv_DetectOptions* options) { - // Prepare the image. - FloatImage image; - libmv_floatBufferToFloatImage(image_buffer, width, height, channels, &image); - - // Configure detector. - DetectOptions detector_options; - libmv_convertDetectorOptions(options, &detector_options); - - // Run the detector. - libmv::vector detected_features; - Detect(image, detector_options, &detected_features); - - // Convert result to C-API. - libmv_Features* result = libmv_featuresFromVector(detected_features); - return result; -} - -void libmv_featuresDestroy(libmv_Features* libmv_features) { - if (libmv_features->features) { - LIBMV_STRUCT_DELETE(libmv_features->features); - } - LIBMV_STRUCT_DELETE(libmv_features); -} - -int libmv_countFeatures(const libmv_Features* libmv_features) { - return libmv_features->count; -} - -void libmv_getFeature(const libmv_Features* libmv_features, - int number, - double* x, - double* y, - double* score, - double* size) { - Feature &feature = libmv_features->features[number]; - *x = feature.x; - *y = feature.y; - *score = feature.score; - *size = feature.size; -} diff --git a/extern/libmv/intern/detector.h b/extern/libmv/intern/detector.h deleted file mode 100644 index f72b0dd8d6e..00000000000 --- a/extern/libmv/intern/detector.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_DETECTOR_H_ -#define LIBMV_C_API_DETECTOR_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct libmv_Features libmv_Features; - -enum { - LIBMV_DETECTOR_FAST, - LIBMV_DETECTOR_MORAVEC, - LIBMV_DETECTOR_HARRIS, -}; - -typedef struct libmv_DetectOptions { - int detector; - int margin; - int min_distance; - int fast_min_trackness; - int moravec_max_count; - unsigned char *moravec_pattern; - double harris_threshold; -} libmv_DetectOptions; - -libmv_Features* libmv_detectFeaturesByte(const unsigned char* image_buffer, - int width, - int height, - int channels, - libmv_DetectOptions* options); - -libmv_Features* libmv_detectFeaturesFloat(const float* image_buffer, - int width, - int height, - int channels, - libmv_DetectOptions* options); - -void libmv_featuresDestroy(libmv_Features* libmv_features); -int libmv_countFeatures(const libmv_Features* libmv_features); -void libmv_getFeature(const libmv_Features* libmv_features, - int number, - double* x, - double* y, - double* score, - double* size); - -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_C_API_DETECTOR_H_ diff --git a/extern/libmv/intern/frame_accessor.cc b/extern/libmv/intern/frame_accessor.cc deleted file mode 100644 index 8bf2cab914b..00000000000 --- a/extern/libmv/intern/frame_accessor.cc +++ /dev/null @@ -1,164 +0,0 @@ -/* - * ***** 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) 2014 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/frame_accessor.h" -#include "intern/image.h" -#include "intern/utildefines.h" -#include "libmv/autotrack/frame_accessor.h" -#include "libmv/autotrack/region.h" -#include "libmv/image/image.h" - -namespace { - -using libmv::FloatImage; -using mv::FrameAccessor; -using mv::Region; - -struct LibmvFrameAccessor : public FrameAccessor { - LibmvFrameAccessor(libmv_FrameAccessorUserData* user_data, - libmv_GetImageCallback get_image_callback, - libmv_ReleaseImageCallback release_image_callback) - : user_data_(user_data), - get_image_callback_(get_image_callback), - release_image_callback_(release_image_callback) { } - - libmv_InputMode get_libmv_input_mode(InputMode input_mode) { - switch (input_mode) { -#define CHECK_INPUT_MODE(mode) \ - case mode: \ - return LIBMV_IMAGE_MODE_ ## mode; - CHECK_INPUT_MODE(MONO) - CHECK_INPUT_MODE(RGBA) -#undef CHECK_INPUT_MODE - } - assert(!"unknown input mode passed from Libmv."); - // TODO(sergey): Proper error handling here in the future. - return LIBMV_IMAGE_MODE_MONO; - } - - void get_libmv_region(const Region& region, - libmv_Region* libmv_region) { - libmv_region->min[0] = region.min(0); - libmv_region->min[1] = region.min(1); - libmv_region->max[0] = region.max(0); - libmv_region->max[1] = region.max(1); - } - - Key GetImage(int clip, - int frame, - InputMode input_mode, - int downscale, - const Region* region, - const Transform* transform, - FloatImage* destination) { - float *float_buffer; - int width, height, channels; - libmv_Region libmv_region; - if (region) { - get_libmv_region(*region, &libmv_region); - } - Key cache_key = get_image_callback_(user_data_, - clip, - frame, - get_libmv_input_mode(input_mode), - downscale, - region != NULL ? &libmv_region : NULL, - (libmv_FrameTransform*) transform, - &float_buffer, - &width, - &height, - &channels); - - // TODO(sergey): Dumb code for until we can set data directly. - FloatImage temp_image(float_buffer, - height, - width, - channels); - destination->CopyFrom(temp_image); - - return cache_key; - } - - void ReleaseImage(Key cache_key) { - release_image_callback_(cache_key); - } - - bool GetClipDimensions(int clip, int *width, int *height) { - return false; - } - - int NumClips() { - return 1; - } - - int NumFrames(int clip) { - return 0; - } - - libmv_FrameAccessorUserData* user_data_; - libmv_GetImageCallback get_image_callback_; - libmv_ReleaseImageCallback release_image_callback_; -}; - -} // namespace - -libmv_FrameAccessor* libmv_FrameAccessorNew( - libmv_FrameAccessorUserData* user_data, - libmv_GetImageCallback get_image_callback, - libmv_ReleaseImageCallback release_image_callback) { - return (libmv_FrameAccessor*) LIBMV_OBJECT_NEW(LibmvFrameAccessor, - user_data, - get_image_callback, - release_image_callback); -} - -void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor) { - LIBMV_OBJECT_DELETE(frame_accessor, LibmvFrameAccessor); -} - -int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform) { - return ((FrameAccessor::Transform*) transform)->key(); -} - -void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform, - const libmv_FloatImage *input_image, - libmv_FloatImage *output_image) { - const FloatImage input(input_image->buffer, - input_image->height, - input_image->width, - input_image->channels); - - FloatImage output; - ((FrameAccessor::Transform*) transform)->run(input, - &output); - - int num_pixels = output.Width() *output.Height() * output.Depth(); - output_image->buffer = new float[num_pixels]; - memcpy(output_image->buffer, output.Data(), num_pixels * sizeof(float)); - output_image->width = output.Width(); - output_image->height = output.Height(); - output_image->channels = output.Depth(); -} diff --git a/extern/libmv/intern/frame_accessor.h b/extern/libmv/intern/frame_accessor.h deleted file mode 100644 index 3e813fe7581..00000000000 --- a/extern/libmv/intern/frame_accessor.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * ***** 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) 2014 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_FRAME_ACCESSOR_H_ -#define LIBMV_C_API_FRAME_ACCESSOR_H_ - -#include - -#include "intern/image.h" -#include "intern/region.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct libmv_FrameAccessor libmv_FrameAccessor; -typedef struct libmv_FrameTransform libmv_FrameTransform; -typedef struct libmv_FrameAccessorUserData libmv_FrameAccessorUserData; -typedef void *libmv_CacheKey; - -typedef enum { - LIBMV_IMAGE_MODE_MONO, - LIBMV_IMAGE_MODE_RGBA, -} libmv_InputMode; - -typedef libmv_CacheKey (*libmv_GetImageCallback) ( - libmv_FrameAccessorUserData* user_data, - int clip, - int frame, - libmv_InputMode input_mode, - int downscale, - const libmv_Region* region, - const libmv_FrameTransform* transform, - float** destination, - int* width, - int* height, - int* channels); - -typedef void (*libmv_ReleaseImageCallback) (libmv_CacheKey cache_key); - -libmv_FrameAccessor* libmv_FrameAccessorNew( - libmv_FrameAccessorUserData* user_data, - libmv_GetImageCallback get_image_callback, - libmv_ReleaseImageCallback release_image_callback); -void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor); - -int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform); - -void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform, - const libmv_FloatImage *input_image, - libmv_FloatImage *output_image); -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_C_API_FRAME_ACCESSOR_H_ diff --git a/extern/libmv/intern/homography.cc b/extern/libmv/intern/homography.cc deleted file mode 100644 index 6b61bd9ab42..00000000000 --- a/extern/libmv/intern/homography.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/homography.h" -#include "intern/utildefines.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/homography.h" - -void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*x1)[2], - /* const */ double (*x2)[2], - int num_points, - double H[3][3]) { - libmv::Mat x1_mat, x2_mat; - libmv::Mat3 H_mat; - - x1_mat.resize(2, num_points); - x2_mat.resize(2, num_points); - - for (int i = 0; i < num_points; i++) { - x1_mat.col(i) = libmv::Vec2(x1[i][0], x1[i][1]); - x2_mat.col(i) = libmv::Vec2(x2[i][0], x2[i][1]); - } - - LG << "x1: " << x1_mat; - LG << "x2: " << x2_mat; - - libmv::EstimateHomographyOptions options; - libmv::EstimateHomography2DFromCorrespondences(x1_mat, - x2_mat, - options, - &H_mat); - - LG << "H: " << H_mat; - - memcpy(H, H_mat.data(), 9 * sizeof(double)); -} diff --git a/extern/libmv/intern/homography.h b/extern/libmv/intern/homography.h deleted file mode 100644 index 175108e8171..00000000000 --- a/extern/libmv/intern/homography.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_HOMOGRAPHY_H_ -#define LIBMV_C_API_HOMOGRAPHY_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*x1)[2], - /* const */ double (*x2)[2], - int num_points, - double H[3][3]); - -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_C_API_HOMOGRAPHY_H_ diff --git a/extern/libmv/intern/image.cc b/extern/libmv/intern/image.cc deleted file mode 100644 index 5018caef5b1..00000000000 --- a/extern/libmv/intern/image.cc +++ /dev/null @@ -1,272 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/image.h" -#include "intern/utildefines.h" -#include "libmv/tracking/track_region.h" - -#include -#include - -using libmv::FloatImage; -using libmv::SamplePlanarPatch; - -void libmv_floatImageDestroy(libmv_FloatImage *image) { - delete [] image->buffer; -} - -/* Image <-> buffers conversion */ - -void libmv_byteBufferToFloatImage(const unsigned char* buffer, - int width, - int height, - int channels, - FloatImage* image) { - image->Resize(height, width, channels); - for (int y = 0, a = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - for (int k = 0; k < channels; k++) { - (*image)(y, x, k) = (float)buffer[a++] / 255.0f; - } - } - } -} - -void libmv_floatBufferToFloatImage(const float* buffer, - int width, - int height, - int channels, - FloatImage* image) { - image->Resize(height, width, channels); - for (int y = 0, a = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - for (int k = 0; k < channels; k++) { - (*image)(y, x, k) = buffer[a++]; - } - } - } -} - -void libmv_floatImageToFloatBuffer(const FloatImage &image, - float* buffer) { - for (int y = 0, a = 0; y < image.Height(); y++) { - for (int x = 0; x < image.Width(); x++) { - for (int k = 0; k < image.Depth(); k++) { - buffer[a++] = image(y, x, k); - } - } - } -} - -void libmv_floatImageToByteBuffer(const libmv::FloatImage &image, - unsigned char* buffer) { - for (int y = 0, a= 0; y < image.Height(); y++) { - for (int x = 0; x < image.Width(); x++) { - for (int k = 0; k < image.Depth(); k++) { - buffer[a++] = image(y, x, k) * 255.0f; - } - } - } -} - -static bool savePNGImage(png_bytep* row_pointers, - int width, - int height, - int depth, - int color_type, - const char* file_name) { - png_infop info_ptr; - png_structp png_ptr; - FILE *fp = fopen(file_name, "wb"); - - if (fp == NULL) { - return false; - } - - /* Initialize stuff */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - info_ptr = png_create_info_struct(png_ptr); - - if (setjmp(png_jmpbuf(png_ptr))) { - fclose(fp); - return false; - } - - png_init_io(png_ptr, fp); - - /* Write PNG header. */ - if (setjmp(png_jmpbuf(png_ptr))) { - fclose(fp); - return false; - } - - png_set_IHDR(png_ptr, - info_ptr, - width, - height, - depth, - color_type, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, - PNG_FILTER_TYPE_BASE); - - png_write_info(png_ptr, info_ptr); - - /* Write bytes/ */ - if (setjmp(png_jmpbuf(png_ptr))) { - fclose(fp); - return false; - } - - png_write_image(png_ptr, row_pointers); - - /* End write/ */ - if (setjmp(png_jmpbuf(png_ptr))) { - fclose(fp); - return false; - } - - png_write_end(png_ptr, NULL); - fclose(fp); - - return true; -} - -bool libmv_saveImage(const FloatImage& image, - const char* prefix, - int x0, - int y0) { - int x, y; - png_bytep *row_pointers; - - assert(image.Depth() == 1); - - row_pointers = new png_bytep[image.Height()]; - - for (y = 0; y < image.Height(); y++) { - row_pointers[y] = new png_byte[4 * image.Width()]; - - for (x = 0; x < image.Width(); x++) { - if (x0 == x && image.Height() - y0 - 1 == y) { - row_pointers[y][x * 4 + 0] = 255; - row_pointers[y][x * 4 + 1] = 0; - row_pointers[y][x * 4 + 2] = 0; - row_pointers[y][x * 4 + 3] = 255; - } else { - float pixel = image(image.Height() - y - 1, x, 0); - row_pointers[y][x * 4 + 0] = pixel * 255; - row_pointers[y][x * 4 + 1] = pixel * 255; - row_pointers[y][x * 4 + 2] = pixel * 255; - row_pointers[y][x * 4 + 3] = 255; - } - } - } - - static int image_counter = 0; - char file_name[128]; - snprintf(file_name, sizeof(file_name), - "%s_%02d.png", - prefix, ++image_counter); - bool result = savePNGImage(row_pointers, - image.Width(), - image.Height(), - 8, - PNG_COLOR_TYPE_RGBA, - file_name); - - for (y = 0; y < image.Height(); y++) { - delete [] row_pointers[y]; - } - delete [] row_pointers; - - return result; -} - -void libmv_samplePlanarPatchFloat(const float* image, - int width, - int height, - int channels, - const double* xs, - const double* ys, - int num_samples_x, - int num_samples_y, - const float* mask, - float* patch, - double* warped_position_x, - double* warped_position_y) { - FloatImage libmv_image, libmv_patch, libmv_mask; - FloatImage *libmv_mask_for_sample = NULL; - - libmv_floatBufferToFloatImage(image, width, height, channels, &libmv_image); - - if (mask) { - libmv_floatBufferToFloatImage(mask, width, height, 1, &libmv_mask); - libmv_mask_for_sample = &libmv_mask; - } - - SamplePlanarPatch(libmv_image, - xs, ys, - num_samples_x, num_samples_y, - libmv_mask_for_sample, - &libmv_patch, - warped_position_x, - warped_position_y); - - libmv_floatImageToFloatBuffer(libmv_patch, patch); -} - -void libmv_samplePlanarPatchByte(const unsigned char* image, - int width, - int height, - int channels, - const double* xs, - const double* ys, - int num_samples_x, - int num_samples_y, - const float* mask, - unsigned char* patch, - double* warped_position_x, - double* warped_position_y) { - libmv::FloatImage libmv_image, libmv_patch, libmv_mask; - libmv::FloatImage *libmv_mask_for_sample = NULL; - - libmv_byteBufferToFloatImage(image, width, height, channels, &libmv_image); - - if (mask) { - libmv_floatBufferToFloatImage(mask, width, height, 1, &libmv_mask); - libmv_mask_for_sample = &libmv_mask; - } - - libmv::SamplePlanarPatch(libmv_image, - xs, ys, - num_samples_x, num_samples_y, - libmv_mask_for_sample, - &libmv_patch, - warped_position_x, - warped_position_y); - - libmv_floatImageToByteBuffer(libmv_patch, patch); -} diff --git a/extern/libmv/intern/image.h b/extern/libmv/intern/image.h deleted file mode 100644 index 1213943aac4..00000000000 --- a/extern/libmv/intern/image.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_IMAGE_H_ -#define LIBMV_IMAGE_H_ - -#ifdef __cplusplus -# include "libmv/image/image.h" -void libmv_byteBufferToFloatImage(const unsigned char* buffer, - int width, - int height, - int channels, - libmv::FloatImage* image); - -void libmv_floatBufferToFloatImage(const float* buffer, - int width, - int height, - int channels, - libmv::FloatImage* image); - -void libmv_floatImageToFloatBuffer(const libmv::FloatImage& image, - float *buffer); - -void libmv_floatImageToByteBuffer(const libmv::FloatImage& image, - unsigned char* buffer); - -bool libmv_saveImage(const libmv::FloatImage& image, - const char* prefix, - int x0, - int y0); -#endif // __cplusplus - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct libmv_FloatImage { - float *buffer; - int width; - int height; - int channels; -} libmv_FloatImage; - -void libmv_floatImageDestroy(libmv_FloatImage *image); - -void libmv_samplePlanarPatchFloat(const float* image, - int width, - int height, - int channels, - const double* xs, - const double* ys, - int num_samples_x, - int num_samples_y, - const float* mask, - float* patch, - double* warped_position_x, - double* warped_position_y); - - void libmv_samplePlanarPatchByte(const unsigned char* image, - int width, - int height, - int channels, - const double* xs, - const double* ys, - int num_samples_x, - int num_samples_y, - const float* mask, - unsigned char* patch, - double* warped_position_x, - double* warped_position_y); - -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_IMAGE_H_ diff --git a/extern/libmv/intern/logging.cc b/extern/libmv/intern/logging.cc deleted file mode 100644 index 77b56ef4df3..00000000000 --- a/extern/libmv/intern/logging.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/logging.h" -#include "intern/utildefines.h" -#include "libmv/logging/logging.h" - -void libmv_initLogging(const char* argv0) { - // Make it so FATAL messages are always print into console. - char severity_fatal[32]; - snprintf(severity_fatal, sizeof(severity_fatal), "%d", - google::GLOG_FATAL); - - google::InitGoogleLogging(argv0); - gflags::SetCommandLineOption("logtostderr", "1"); - gflags::SetCommandLineOption("v", "0"); - gflags::SetCommandLineOption("stderrthreshold", severity_fatal); - gflags::SetCommandLineOption("minloglevel", severity_fatal); -} - -void libmv_startDebugLogging(void) { - gflags::SetCommandLineOption("logtostderr", "1"); - gflags::SetCommandLineOption("v", "2"); - gflags::SetCommandLineOption("stderrthreshold", "1"); - gflags::SetCommandLineOption("minloglevel", "0"); -} - -void libmv_setLoggingVerbosity(int verbosity) { - char val[10]; - snprintf(val, sizeof(val), "%d", verbosity); - gflags::SetCommandLineOption("v", val); -} diff --git a/extern/libmv/intern/logging.h b/extern/libmv/intern/logging.h deleted file mode 100644 index 479ed3d6288..00000000000 --- a/extern/libmv/intern/logging.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_LOGGING_H_ -#define LIBMV_C_API_LOGGING_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -// Initialize GLog logging. -void libmv_initLogging(const char* argv0); - -// Switch Glog to debug logging level. -void libmv_startDebugLogging(void); - -// Set GLog logging verbosity level. -void libmv_setLoggingVerbosity(int verbosity); - -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_C_API_LOGGING_H_ diff --git a/extern/libmv/intern/reconstruction.cc b/extern/libmv/intern/reconstruction.cc deleted file mode 100644 index 046671e467f..00000000000 --- a/extern/libmv/intern/reconstruction.cc +++ /dev/null @@ -1,542 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/reconstruction.h" -#include "intern/camera_intrinsics.h" -#include "intern/tracks.h" -#include "intern/utildefines.h" - -#include "libmv/logging/logging.h" -#include "libmv/simple_pipeline/bundle.h" -#include "libmv/simple_pipeline/keyframe_selection.h" -#include "libmv/simple_pipeline/initialize_reconstruction.h" -#include "libmv/simple_pipeline/modal_solver.h" -#include "libmv/simple_pipeline/pipeline.h" -#include "libmv/simple_pipeline/reconstruction_scale.h" -#include "libmv/simple_pipeline/tracks.h" - -using libmv::CameraIntrinsics; -using libmv::EuclideanCamera; -using libmv::EuclideanPoint; -using libmv::EuclideanReconstruction; -using libmv::EuclideanScaleToUnity; -using libmv::Marker; -using libmv::ProgressUpdateCallback; - -using libmv::PolynomialCameraIntrinsics; -using libmv::Tracks; -using libmv::EuclideanBundle; -using libmv::EuclideanCompleteReconstruction; -using libmv::EuclideanReconstructTwoFrames; -using libmv::EuclideanReprojectionError; - -struct libmv_Reconstruction { - EuclideanReconstruction reconstruction; - - /* Used for per-track average error calculation after reconstruction */ - Tracks tracks; - CameraIntrinsics *intrinsics; - - double error; - bool is_valid; -}; - -namespace { - -class ReconstructUpdateCallback : public ProgressUpdateCallback { - public: - ReconstructUpdateCallback( - reconstruct_progress_update_cb progress_update_callback, - void *callback_customdata) { - progress_update_callback_ = progress_update_callback; - callback_customdata_ = callback_customdata; - } - - void invoke(double progress, const char* message) { - if (progress_update_callback_) { - progress_update_callback_(callback_customdata_, progress, message); - } - } - protected: - reconstruct_progress_update_cb progress_update_callback_; - void* callback_customdata_; -}; - -void libmv_solveRefineIntrinsics( - const Tracks &tracks, - const int refine_intrinsics, - const int bundle_constraints, - reconstruct_progress_update_cb progress_update_callback, - void* callback_customdata, - EuclideanReconstruction* reconstruction, - CameraIntrinsics* intrinsics) { - /* only a few combinations are supported but trust the caller/ */ - int bundle_intrinsics = 0; - - if (refine_intrinsics & LIBMV_REFINE_FOCAL_LENGTH) { - bundle_intrinsics |= libmv::BUNDLE_FOCAL_LENGTH; - } - if (refine_intrinsics & LIBMV_REFINE_PRINCIPAL_POINT) { - bundle_intrinsics |= libmv::BUNDLE_PRINCIPAL_POINT; - } - if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K1) { - bundle_intrinsics |= libmv::BUNDLE_RADIAL_K1; - } - if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K2) { - bundle_intrinsics |= libmv::BUNDLE_RADIAL_K2; - } - - progress_update_callback(callback_customdata, 1.0, "Refining solution"); - - EuclideanBundleCommonIntrinsics(tracks, - bundle_intrinsics, - bundle_constraints, - reconstruction, - intrinsics); -} - -void finishReconstruction( - const Tracks &tracks, - const CameraIntrinsics &camera_intrinsics, - libmv_Reconstruction *libmv_reconstruction, - reconstruct_progress_update_cb progress_update_callback, - void *callback_customdata) { - EuclideanReconstruction &reconstruction = - libmv_reconstruction->reconstruction; - - /* Reprojection error calculation. */ - progress_update_callback(callback_customdata, 1.0, "Finishing solution"); - libmv_reconstruction->tracks = tracks; - libmv_reconstruction->error = EuclideanReprojectionError(tracks, - reconstruction, - camera_intrinsics); -} - -bool selectTwoKeyframesBasedOnGRICAndVariance( - Tracks& tracks, - Tracks& normalized_tracks, - CameraIntrinsics& camera_intrinsics, - int& keyframe1, - int& keyframe2) { - libmv::vector keyframes; - - /* Get list of all keyframe candidates first. */ - SelectKeyframesBasedOnGRICAndVariance(normalized_tracks, - camera_intrinsics, - keyframes); - - if (keyframes.size() < 2) { - LG << "Not enough keyframes detected by GRIC"; - return false; - } else if (keyframes.size() == 2) { - keyframe1 = keyframes[0]; - keyframe2 = keyframes[1]; - return true; - } - - /* Now choose two keyframes with minimal reprojection error after initial - * reconstruction choose keyframes with the least reprojection error after - * solving from two candidate keyframes. - * - * In fact, currently libmv returns single pair only, so this code will - * not actually run. But in the future this could change, so let's stay - * prepared. - */ - int previous_keyframe = keyframes[0]; - double best_error = std::numeric_limits::max(); - for (int i = 1; i < keyframes.size(); i++) { - EuclideanReconstruction reconstruction; - int current_keyframe = keyframes[i]; - libmv::vector keyframe_markers = - normalized_tracks.MarkersForTracksInBothImages(previous_keyframe, - current_keyframe); - - Tracks keyframe_tracks(keyframe_markers); - - /* get a solution from two keyframes only */ - EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction); - EuclideanBundle(keyframe_tracks, &reconstruction); - EuclideanCompleteReconstruction(keyframe_tracks, - &reconstruction, - NULL); - - double current_error = EuclideanReprojectionError(tracks, - reconstruction, - camera_intrinsics); - - LG << "Error between " << previous_keyframe - << " and " << current_keyframe - << ": " << current_error; - - if (current_error < best_error) { - best_error = current_error; - keyframe1 = previous_keyframe; - keyframe2 = current_keyframe; - } - - previous_keyframe = current_keyframe; - } - - return true; -} - -Marker libmv_projectMarker(const EuclideanPoint& point, - const EuclideanCamera& camera, - const CameraIntrinsics& intrinsics) { - libmv::Vec3 projected = camera.R * point.X + camera.t; - projected /= projected(2); - - libmv::Marker reprojected_marker; - intrinsics.ApplyIntrinsics(projected(0), projected(1), - &reprojected_marker.x, - &reprojected_marker.y); - - reprojected_marker.image = camera.image; - reprojected_marker.track = point.track; - return reprojected_marker; -} - -void libmv_getNormalizedTracks(const Tracks &tracks, - const CameraIntrinsics &camera_intrinsics, - Tracks *normalized_tracks) { - libmv::vector markers = tracks.AllMarkers(); - for (int i = 0; i < markers.size(); ++i) { - Marker &marker = markers[i]; - camera_intrinsics.InvertIntrinsics(marker.x, marker.y, - &marker.x, &marker.y); - normalized_tracks->Insert(marker.image, - marker.track, - marker.x, marker.y, - marker.weight); - } -} - -} // namespace - -libmv_Reconstruction *libmv_solveReconstruction( - const libmv_Tracks* libmv_tracks, - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - libmv_ReconstructionOptions* libmv_reconstruction_options, - reconstruct_progress_update_cb progress_update_callback, - void* callback_customdata) { - libmv_Reconstruction *libmv_reconstruction = - LIBMV_OBJECT_NEW(libmv_Reconstruction); - - Tracks &tracks = *((Tracks *) libmv_tracks); - EuclideanReconstruction &reconstruction = - libmv_reconstruction->reconstruction; - - ReconstructUpdateCallback update_callback = - ReconstructUpdateCallback(progress_update_callback, - callback_customdata); - - /* Retrieve reconstruction options from C-API to libmv API. */ - CameraIntrinsics *camera_intrinsics; - camera_intrinsics = libmv_reconstruction->intrinsics = - libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); - - /* Invert the camera intrinsics/ */ - Tracks normalized_tracks; - libmv_getNormalizedTracks(tracks, *camera_intrinsics, &normalized_tracks); - - /* keyframe selection. */ - int keyframe1 = libmv_reconstruction_options->keyframe1, - keyframe2 = libmv_reconstruction_options->keyframe2; - - if (libmv_reconstruction_options->select_keyframes) { - LG << "Using automatic keyframe selection"; - - update_callback.invoke(0, "Selecting keyframes"); - - selectTwoKeyframesBasedOnGRICAndVariance(tracks, - normalized_tracks, - *camera_intrinsics, - keyframe1, - keyframe2); - - /* so keyframes in the interface would be updated */ - libmv_reconstruction_options->keyframe1 = keyframe1; - libmv_reconstruction_options->keyframe2 = keyframe2; - } - - /* Actual reconstruction. */ - LG << "frames to init from: " << keyframe1 << " " << keyframe2; - - libmv::vector keyframe_markers = - normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2); - - LG << "number of markers for init: " << keyframe_markers.size(); - - if (keyframe_markers.size() < 8) { - LG << "No enough markers to initialize from"; - libmv_reconstruction->is_valid = false; - return libmv_reconstruction; - } - - update_callback.invoke(0, "Initial reconstruction"); - - EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction); - EuclideanBundle(normalized_tracks, &reconstruction); - EuclideanCompleteReconstruction(normalized_tracks, - &reconstruction, - &update_callback); - - /* Refinement/ */ - if (libmv_reconstruction_options->refine_intrinsics) { - libmv_solveRefineIntrinsics( - tracks, - libmv_reconstruction_options->refine_intrinsics, - libmv::BUNDLE_NO_CONSTRAINTS, - progress_update_callback, - callback_customdata, - &reconstruction, - camera_intrinsics); - } - - /* Set reconstruction scale to unity. */ - EuclideanScaleToUnity(&reconstruction); - - /* Finish reconstruction. */ - finishReconstruction(tracks, - *camera_intrinsics, - libmv_reconstruction, - progress_update_callback, - callback_customdata); - - libmv_reconstruction->is_valid = true; - return (libmv_Reconstruction *) libmv_reconstruction; -} - -libmv_Reconstruction *libmv_solveModal( - const libmv_Tracks *libmv_tracks, - const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, - const libmv_ReconstructionOptions *libmv_reconstruction_options, - reconstruct_progress_update_cb progress_update_callback, - void *callback_customdata) { - libmv_Reconstruction *libmv_reconstruction = - LIBMV_OBJECT_NEW(libmv_Reconstruction); - - Tracks &tracks = *((Tracks *) libmv_tracks); - EuclideanReconstruction &reconstruction = - libmv_reconstruction->reconstruction; - - ReconstructUpdateCallback update_callback = - ReconstructUpdateCallback(progress_update_callback, - callback_customdata); - - /* Retrieve reconstruction options from C-API to libmv API. */ - CameraIntrinsics *camera_intrinsics; - camera_intrinsics = libmv_reconstruction->intrinsics = - libmv_cameraIntrinsicsCreateFromOptions( - libmv_camera_intrinsics_options); - - /* Invert the camera intrinsics. */ - Tracks normalized_tracks; - libmv_getNormalizedTracks(tracks, *camera_intrinsics, &normalized_tracks); - - /* Actual reconstruction. */ - ModalSolver(normalized_tracks, &reconstruction, &update_callback); - - PolynomialCameraIntrinsics empty_intrinsics; - EuclideanBundleCommonIntrinsics(normalized_tracks, - libmv::BUNDLE_NO_INTRINSICS, - libmv::BUNDLE_NO_TRANSLATION, - &reconstruction, - &empty_intrinsics); - - /* Refinement. */ - if (libmv_reconstruction_options->refine_intrinsics) { - libmv_solveRefineIntrinsics( - tracks, - libmv_reconstruction_options->refine_intrinsics, - libmv::BUNDLE_NO_TRANSLATION, - progress_update_callback, callback_customdata, - &reconstruction, - camera_intrinsics); - } - - /* Finish reconstruction. */ - finishReconstruction(tracks, - *camera_intrinsics, - libmv_reconstruction, - progress_update_callback, - callback_customdata); - - libmv_reconstruction->is_valid = true; - return (libmv_Reconstruction *) libmv_reconstruction; -} - -int libmv_reconstructionIsValid(libmv_Reconstruction *libmv_reconstruction) { - return libmv_reconstruction->is_valid; -} - -void libmv_reconstructionDestroy(libmv_Reconstruction *libmv_reconstruction) { - LIBMV_OBJECT_DELETE(libmv_reconstruction->intrinsics, CameraIntrinsics); - LIBMV_OBJECT_DELETE(libmv_reconstruction, libmv_Reconstruction); -} - -int libmv_reprojectionPointForTrack( - const libmv_Reconstruction *libmv_reconstruction, - int track, - double pos[3]) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const EuclideanPoint *point = - reconstruction->PointForTrack(track); - if (point) { - pos[0] = point->X[0]; - pos[1] = point->X[2]; - pos[2] = point->X[1]; - return 1; - } - return 0; -} - -double libmv_reprojectionErrorForTrack( - const libmv_Reconstruction *libmv_reconstruction, - int track) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const CameraIntrinsics *intrinsics = libmv_reconstruction->intrinsics; - libmv::vector markers = - libmv_reconstruction->tracks.MarkersForTrack(track); - - int num_reprojected = 0; - double total_error = 0.0; - - for (int i = 0; i < markers.size(); ++i) { - double weight = markers[i].weight; - const EuclideanCamera *camera = - reconstruction->CameraForImage(markers[i].image); - const EuclideanPoint *point = - reconstruction->PointForTrack(markers[i].track); - - if (!camera || !point || weight == 0.0) { - continue; - } - - num_reprojected++; - - Marker reprojected_marker = - libmv_projectMarker(*point, *camera, *intrinsics); - double ex = (reprojected_marker.x - markers[i].x) * weight; - double ey = (reprojected_marker.y - markers[i].y) * weight; - - total_error += sqrt(ex * ex + ey * ey); - } - - return total_error / num_reprojected; -} - -double libmv_reprojectionErrorForImage( - const libmv_Reconstruction *libmv_reconstruction, - int image) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const CameraIntrinsics *intrinsics = libmv_reconstruction->intrinsics; - libmv::vector markers = - libmv_reconstruction->tracks.MarkersInImage(image); - const EuclideanCamera *camera = reconstruction->CameraForImage(image); - int num_reprojected = 0; - double total_error = 0.0; - - if (!camera) { - return 0.0; - } - - for (int i = 0; i < markers.size(); ++i) { - const EuclideanPoint *point = - reconstruction->PointForTrack(markers[i].track); - - if (!point) { - continue; - } - - num_reprojected++; - - Marker reprojected_marker = - libmv_projectMarker(*point, *camera, *intrinsics); - double ex = (reprojected_marker.x - markers[i].x) * markers[i].weight; - double ey = (reprojected_marker.y - markers[i].y) * markers[i].weight; - - total_error += sqrt(ex * ex + ey * ey); - } - - return total_error / num_reprojected; -} - -int libmv_reprojectionCameraForImage( - const libmv_Reconstruction *libmv_reconstruction, - int image, - double mat[4][4]) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const EuclideanCamera *camera = - reconstruction->CameraForImage(image); - - if (camera) { - for (int j = 0; j < 3; ++j) { - for (int k = 0; k < 3; ++k) { - int l = k; - - if (k == 1) { - l = 2; - } else if (k == 2) { - l = 1; - } - - if (j == 2) { - mat[j][l] = -camera->R(j, k); - } else { - mat[j][l] = camera->R(j, k); - } - } - mat[j][3] = 0.0; - } - - libmv::Vec3 optical_center = -camera->R.transpose() * camera->t; - - mat[3][0] = optical_center(0); - mat[3][1] = optical_center(2); - mat[3][2] = optical_center(1); - - mat[3][3] = 1.0; - - return 1; - } - - return 0; -} - -double libmv_reprojectionError( - const libmv_Reconstruction *libmv_reconstruction) { - return libmv_reconstruction->error; -} - -libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics( - libmv_Reconstruction *libmv_reconstruction) { - return (libmv_CameraIntrinsics *) libmv_reconstruction->intrinsics; -} diff --git a/extern/libmv/intern/reconstruction.h b/extern/libmv/intern/reconstruction.h deleted file mode 100644 index 8b6b34a6142..00000000000 --- a/extern/libmv/intern/reconstruction.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_RECONSTRUCTION_H_ -#define LIBMV_C_API_RECONSTRUCTION_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -struct libmv_Tracks; -struct libmv_CameraIntrinsics; -struct libmv_CameraIntrinsicsOptions; - -typedef struct libmv_Reconstruction libmv_Reconstruction; - -enum { - LIBMV_REFINE_FOCAL_LENGTH = (1 << 0), - LIBMV_REFINE_PRINCIPAL_POINT = (1 << 1), - LIBMV_REFINE_RADIAL_DISTORTION_K1 = (1 << 2), - LIBMV_REFINE_RADIAL_DISTORTION_K2 = (1 << 4), -}; - -typedef struct libmv_ReconstructionOptions { - int select_keyframes; - int keyframe1, keyframe2; - int refine_intrinsics; -} libmv_ReconstructionOptions; - -typedef void (*reconstruct_progress_update_cb) (void* customdata, - double progress, - const char* message); - -libmv_Reconstruction* libmv_solveReconstruction( - const struct libmv_Tracks* libmv_tracks, - const struct libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - libmv_ReconstructionOptions* libmv_reconstruction_options, - reconstruct_progress_update_cb progress_update_callback, - void* callback_customdata); - -libmv_Reconstruction* libmv_solveModal( - const struct libmv_Tracks* libmv_tracks, - const struct libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - const libmv_ReconstructionOptions* libmv_reconstruction_options, - reconstruct_progress_update_cb progress_update_callback, - void* callback_customdata); - -int libmv_reconstructionIsValid(libmv_Reconstruction *libmv_reconstruction); - -void libmv_reconstructionDestroy(libmv_Reconstruction* libmv_reconstruction); - -int libmv_reprojectionPointForTrack( - const libmv_Reconstruction* libmv_reconstruction, - int track, - double pos[3]); - -double libmv_reprojectionErrorForTrack( - const libmv_Reconstruction* libmv_reconstruction, - int track); - -double libmv_reprojectionErrorForImage( - const libmv_Reconstruction* libmv_reconstruction, - int image); - -int libmv_reprojectionCameraForImage( - const libmv_Reconstruction* libmv_reconstruction, - int image, - double mat[4][4]); - -double libmv_reprojectionError(const libmv_Reconstruction* libmv_reconstruction); - -struct libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics( - libmv_Reconstruction *libmv_Reconstruction); - -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_C_API_RECONSTRUCTION_H_ diff --git a/extern/libmv/intern/region.h b/extern/libmv/intern/region.h deleted file mode 100644 index 9f114bbad3b..00000000000 --- a/extern/libmv/intern/region.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * ***** 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) 2014 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_REGION_H_ -#define LIBMV_C_API_REGION_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct libmv_Region { - float min[2]; - float max[2]; -} libmv_Region; - -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_C_API_REGION_H_ diff --git a/extern/libmv/intern/stub.cc b/extern/libmv/intern/stub.cc deleted file mode 100644 index 5d667baa880..00000000000 --- a/extern/libmv/intern/stub.cc +++ /dev/null @@ -1,403 +0,0 @@ -/* - * ***** 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): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "libmv-capi.h" - -#include -#include - -/* ************ Logging ************ */ - -void libmv_initLogging(const char * /*argv0*/) { -} - -void libmv_startDebugLogging(void) { -} - -void libmv_setLoggingVerbosity(int /*verbosity*/) { -} - -/* ************ Planar tracker ************ */ - -/* TrackRegion (new planar tracker) */ -int libmv_trackRegion(const libmv_TrackRegionOptions * /*options*/, - const float * /*image1*/, - int /*image1_width*/, - int /*image1_height*/, - const float * /*image2*/, - int /*image2_width*/, - int /*image2_height*/, - const double *x1, - const double *y1, - libmv_TrackRegionResult *result, - double *x2, - double *y2) { - /* Convert to doubles for the libmv api. The four corners and the center. */ - for (int i = 0; i < 5; ++i) { - x2[i] = x1[i]; - y2[i] = y1[i]; - } - - result->termination = -1; - result->termination_reason = "Built without libmv support"; - result->correlation = 0.0; - - return false; -} - -void libmv_samplePlanarPatchFloat(const float * /*image*/, - int /*width*/, - int /*height*/, - int /*channels*/, - const double * /*xs*/, - const double * /*ys*/, - int /*num_samples_x*/, - int /*num_samples_y*/, - const float * /*mask*/, - float * /*patch*/, - double * /*warped_position_x*/, - double * /*warped_position_y*/) { - /* TODO(sergey): implement */ -} - -void libmv_samplePlanarPatchByte(const unsigned char * /*image*/, - int /*width*/, - int /*height*/, - int /*channels*/, - const double * /*xs*/, - const double * /*ys*/, - int /*num_samples_x*/, int /*num_samples_y*/, - const float * /*mask*/, - unsigned char * /*patch*/, - double * /*warped_position_x*/, - double * /*warped_position_y*/) { - /* TODO(sergey): implement */ -} - -void libmv_floatImageDestroy(libmv_FloatImage* /*image*/) -{ -} - -/* ************ Tracks ************ */ - -libmv_Tracks *libmv_tracksNew(void) { - return NULL; -} - -void libmv_tracksInsert(libmv_Tracks * /*libmv_tracks*/, - int /*image*/, - int /*track*/, - double /*x*/, - double /*y*/, - double /*weight*/) { -} - -void libmv_tracksDestroy(libmv_Tracks * /*libmv_tracks*/) { -} - -/* ************ Reconstruction solver ************ */ - -libmv_Reconstruction *libmv_solveReconstruction( - const libmv_Tracks * /*libmv_tracks*/, - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, - libmv_ReconstructionOptions * /*libmv_reconstruction_options*/, - reconstruct_progress_update_cb /*progress_update_callback*/, - void * /*callback_customdata*/) { - return NULL; -} - -libmv_Reconstruction *libmv_solveModal( - const libmv_Tracks * /*libmv_tracks*/, - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, - const libmv_ReconstructionOptions * /*libmv_reconstruction_options*/, - reconstruct_progress_update_cb /*progress_update_callback*/, - void * /*callback_customdata*/) { - return NULL; -} - -int libmv_reconstructionIsValid(libmv_Reconstruction * /*libmv_reconstruction*/) { - return 0; -} - -int libmv_reprojectionPointForTrack( - const libmv_Reconstruction * /*libmv_reconstruction*/, - int /*track*/, - double /*pos*/[3]) { - return 0; -} - -double libmv_reprojectionErrorForTrack( - const libmv_Reconstruction * /*libmv_reconstruction*/, - int /*track*/) { - return 0.0; -} - -double libmv_reprojectionErrorForImage( - const libmv_Reconstruction * /*libmv_reconstruction*/, - int /*image*/) { - return 0.0; -} - -int libmv_reprojectionCameraForImage( - const libmv_Reconstruction * /*libmv_reconstruction*/, - int /*image*/, - double /*mat*/[4][4]) { - return 0; -} - -double libmv_reprojectionError( - const libmv_Reconstruction * /*libmv_reconstruction*/) { - return 0.0; -} - -void libmv_reconstructionDestroy( - struct libmv_Reconstruction * /*libmv_reconstruction*/) { -} - -/* ************ Feature detector ************ */ - -libmv_Features *libmv_detectFeaturesByte(const unsigned char * /*image_buffer*/, - int /*width*/, - int /*height*/, - int /*channels*/, - libmv_DetectOptions * /*options*/) { - return NULL; -} - -struct libmv_Features *libmv_detectFeaturesFloat( - const float * /*image_buffer*/, - int /*width*/, - int /*height*/, - int /*channels*/, - libmv_DetectOptions * /*options*/) { - return NULL; -} - -int libmv_countFeatures(const libmv_Features * /*libmv_features*/) { - return 0; -} - -void libmv_getFeature(const libmv_Features * /*libmv_features*/, - int /*number*/, - double *x, - double *y, - double *score, - double *size) { - *x = 0.0; - *y = 0.0; - *score = 0.0; - *size = 0.0; -} - -void libmv_featuresDestroy(struct libmv_Features * /*libmv_features*/) { -} - -/* ************ Camera intrinsics ************ */ - -libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics( - libmv_Reconstruction * /*libmv_reconstruction*/) { - return NULL; -} - -libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/) { - return NULL; -} - -libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( - const libmv_CameraIntrinsics * /*libmvIntrinsics*/) { - return NULL; -} - -void libmv_cameraIntrinsicsDestroy( - libmv_CameraIntrinsics * /*libmvIntrinsics*/) { -} - -void libmv_cameraIntrinsicsUpdate( - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, - libmv_CameraIntrinsics * /*libmv_intrinsics*/) { -} - -void libmv_cameraIntrinsicsSetThreads( - libmv_CameraIntrinsics * /*libmv_intrinsics*/, - int /*threads*/) { -} - -void libmv_cameraIntrinsicsExtractOptions( - const libmv_CameraIntrinsics * /*libmv_intrinsics*/, - libmv_CameraIntrinsicsOptions *camera_intrinsics_options) { - memset(camera_intrinsics_options, 0, sizeof(libmv_CameraIntrinsicsOptions)); - camera_intrinsics_options->focal_length = 1.0; -} - -void libmv_cameraIntrinsicsUndistortByte( - const libmv_CameraIntrinsics * /*libmv_intrinsics*/, - const unsigned char *source_image, - int width, int height, - float overscan, int channels, - unsigned char *destination_image) { - memcpy(destination_image, source_image, - channels * width * height * sizeof(unsigned char)); -} - -void libmv_cameraIntrinsicsUndistortFloat( - const libmv_CameraIntrinsics* /*libmv_intrinsics*/, - const float* source_image, - int width, - int height, - float overscan, - int channels, - float* destination_image) { - memcpy(destination_image, source_image, - channels * width * height * sizeof(float)); -} - -void libmv_cameraIntrinsicsDistortByte( - const struct libmv_CameraIntrinsics* /*libmv_intrinsics*/, - const unsigned char *source_image, - int width, - int height, - float overscan, - int channels, - unsigned char *destination_image) { - memcpy(destination_image, source_image, - channels * width * height * sizeof(unsigned char)); -} - -void libmv_cameraIntrinsicsDistortFloat( - const libmv_CameraIntrinsics* /*libmv_intrinsics*/, - float* source_image, - int width, - int height, - float overscan, - int channels, - float* destination_image) { - memcpy(destination_image, source_image, - channels * width * height * sizeof(float)); -} - -/* ************ utils ************ */ - -void libmv_cameraIntrinsicsApply( - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - double x, - double y, - double* x1, - double* y1) { - double focal_length = libmv_camera_intrinsics_options->focal_length; - double principal_x = libmv_camera_intrinsics_options->principal_point_x; - double principal_y = libmv_camera_intrinsics_options->principal_point_y; - *x1 = x * focal_length + principal_x; - *y1 = y * focal_length + principal_y; -} - -void libmv_cameraIntrinsicsInvert( - const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, - double x, - double y, - double* x1, - double* y1) { - double focal_length = libmv_camera_intrinsics_options->focal_length; - double principal_x = libmv_camera_intrinsics_options->principal_point_x; - double principal_y = libmv_camera_intrinsics_options->principal_point_y; - *x1 = (x - principal_x) / focal_length; - *y1 = (y - principal_y) / focal_length; -} - -void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*x1)[2], - /* const */ double (*x2)[2], - int num_points, - double H[3][3]) { - memset(H, 0, sizeof(double[3][3])); - H[0][0] = 1.0f; - H[1][1] = 1.0f; - H[2][2] = 1.0f; -} - -/* ************ autotrack ************ */ - -libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* /*frame_accessor*/) -{ - return NULL; -} - -void libmv_autoTrackDestroy(libmv_AutoTrack* /*libmv_autotrack*/) -{ -} - -void libmv_autoTrackSetOptions(libmv_AutoTrack* /*libmv_autotrack*/, - const libmv_AutoTrackOptions* /*options*/) -{ -} - -int libmv_autoTrackMarker(libmv_AutoTrack* /*libmv_autotrack*/, - const libmv_TrackRegionOptions* /*libmv_options*/, - libmv_Marker * /*libmv_tracker_marker*/, - libmv_TrackRegionResult* /*libmv_result*/) -{ - return 0; -} - -void libmv_autoTrackAddMarker(libmv_AutoTrack* /*libmv_autotrack*/, - const libmv_Marker* /*libmv_marker*/) -{ -} - -int libmv_autoTrackGetMarker(libmv_AutoTrack* /*libmv_autotrack*/, - int /*clip*/, - int /*frame*/, - int /*track*/, - libmv_Marker* /*libmv_marker*/) -{ - return 0; -} - -/* ************ frame accessor ************ */ - -libmv_FrameAccessor* libmv_FrameAccessorNew( - libmv_FrameAccessorUserData* /*user_data**/, - libmv_GetImageCallback /*get_image_callback*/, - libmv_ReleaseImageCallback /*release_image_callback*/) -{ - return NULL; -} - -void libmv_FrameAccessorDestroy(libmv_FrameAccessor* /*frame_accessor*/) -{ -} - -int64_t libmv_frameAccessorgetTransformKey( - const libmv_FrameTransform * /*transform*/) -{ - return 0; -} - -void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* /*transform*/, - const libmv_FloatImage* /*input_image*/, - libmv_FloatImage* /*output_image*/) -{ -} - diff --git a/extern/libmv/intern/track_region.cc b/extern/libmv/intern/track_region.cc deleted file mode 100644 index 24fbc78c1a1..00000000000 --- a/extern/libmv/intern/track_region.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/track_region.h" -#include "intern/image.h" -#include "intern/utildefines.h" -#include "libmv/image/image.h" -#include "libmv/tracking/track_region.h" - -/* define this to generate PNG images with content of search areas - tracking between which failed */ -#undef DUMP_FAILURE - -/* define this to generate PNG images with content of search areas - on every itteration of tracking */ -#undef DUMP_ALWAYS - -using libmv::FloatImage; -using libmv::TrackRegionOptions; -using libmv::TrackRegionResult; -using libmv::TrackRegion; - -void libmv_configureTrackRegionOptions( - const libmv_TrackRegionOptions& options, - TrackRegionOptions* track_region_options) { - switch (options.motion_model) { -#define LIBMV_CONVERT(the_model) \ - case TrackRegionOptions::the_model: \ - track_region_options->mode = TrackRegionOptions::the_model; \ - break; - LIBMV_CONVERT(TRANSLATION) - LIBMV_CONVERT(TRANSLATION_ROTATION) - LIBMV_CONVERT(TRANSLATION_SCALE) - LIBMV_CONVERT(TRANSLATION_ROTATION_SCALE) - LIBMV_CONVERT(AFFINE) - LIBMV_CONVERT(HOMOGRAPHY) -#undef LIBMV_CONVERT - } - - track_region_options->minimum_correlation = options.minimum_correlation; - track_region_options->max_iterations = options.num_iterations; - track_region_options->sigma = options.sigma; - track_region_options->num_extra_points = 1; - track_region_options->image1_mask = NULL; - track_region_options->use_brute_initialization = options.use_brute; - /* TODO(keir): This will make some cases better, but may be a regression until - * the motion model is in. Since this is on trunk, enable it for now. - * - * TODO(sergey): This gives much worse results on mango footage (see 04_2e) - * so disabling for now for until proper prediction model is landed. - * - * The thing is, currently blender sends input coordinates as the guess to - * region tracker and in case of fast motion such an early out ruins the track. - */ - track_region_options->attempt_refine_before_brute = false; - track_region_options->use_normalized_intensities = options.use_normalization; -} - -void libmv_regionTrackergetResult(const TrackRegionResult& track_region_result, - libmv_TrackRegionResult* result) { - result->termination = (int) track_region_result.termination; - result->termination_reason = ""; - result->correlation = track_region_result.correlation; -} - -int libmv_trackRegion(const libmv_TrackRegionOptions* options, - const float* image1, - int image1_width, - int image1_height, - const float* image2, - int image2_width, - int image2_height, - const double* x1, - const double* y1, - libmv_TrackRegionResult* result, - double* x2, - double* y2) { - double xx1[5], yy1[5]; - double xx2[5], yy2[5]; - bool tracking_result = false; - - // Convert to doubles for the libmv api. The four corners and the center. - for (int i = 0; i < 5; ++i) { - xx1[i] = x1[i]; - yy1[i] = y1[i]; - xx2[i] = x2[i]; - yy2[i] = y2[i]; - } - - TrackRegionOptions track_region_options; - FloatImage image1_mask; - - libmv_configureTrackRegionOptions(*options, &track_region_options); - if (options->image1_mask) { - libmv_floatBufferToFloatImage(options->image1_mask, - image1_width, - image1_height, - 1, - &image1_mask); - - track_region_options.image1_mask = &image1_mask; - } - - // Convert from raw float buffers to libmv's FloatImage. - FloatImage old_patch, new_patch; - libmv_floatBufferToFloatImage(image1, - image1_width, - image1_height, - 1, - &old_patch); - libmv_floatBufferToFloatImage(image2, - image2_width, - image2_height, - 1, - &new_patch); - - TrackRegionResult track_region_result; - TrackRegion(old_patch, new_patch, - xx1, yy1, - track_region_options, - xx2, yy2, - &track_region_result); - - // Convert to floats for the blender api. - for (int i = 0; i < 5; ++i) { - x2[i] = xx2[i]; - y2[i] = yy2[i]; - } - - // TODO(keir): Update the termination string with failure details. - if (track_region_result.termination == TrackRegionResult::CONVERGENCE || - track_region_result.termination == TrackRegionResult::NO_CONVERGENCE) { - tracking_result = true; - } - - // Debug dump of patches. -#if defined(DUMP_FAILURE) || defined(DUMP_ALWAYS) - bool need_dump = !tracking_result; - -# ifdef DUMP_ALWAYS - need_dump = true; -# endif - - if (need_dump) { - libmv_saveImage(old_patch, "old_patch", x1[4], y1[4]); - libmv_saveImage(new_patch, "new_patch", x2[4], y2[4]); - if (options->image1_mask) { - libmv_saveImage(image1_mask, "mask", x2[4], y2[4]); - } - } -#endif - - return tracking_result; -} diff --git a/extern/libmv/intern/track_region.h b/extern/libmv/intern/track_region.h deleted file mode 100644 index 7ed3e443e40..00000000000 --- a/extern/libmv/intern/track_region.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_TRACK_REGION_H_ -#define LIBMV_C_API_TRACK_REGION_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct libmv_TrackRegionOptions { - int motion_model; - int num_iterations; - int use_brute; - int use_normalization; - double minimum_correlation; - double sigma; - float *image1_mask; -} libmv_TrackRegionOptions; - -typedef struct libmv_TrackRegionResult { - int termination; - const char* termination_reason; - double correlation; -} libmv_TrackRegionResult; - -#ifdef __cplusplus -namespace libmv { - struct TrackRegionOptions; - struct TrackRegionResult; -} -void libmv_configureTrackRegionOptions( - const libmv_TrackRegionOptions& options, - libmv::TrackRegionOptions* track_region_options); - -void libmv_regionTrackergetResult( - const libmv::TrackRegionResult& track_region_result, - libmv_TrackRegionResult* result); -#endif - -int libmv_trackRegion(const libmv_TrackRegionOptions* options, - const float* image1, - int image1_width, - int image1_height, - const float* image2, - int image2_width, - int image2_height, - const double* x1, - const double* y1, - libmv_TrackRegionResult* result, - double* x2, - double* y2); - -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_C_API_PLANAR_TRACKER_H_ diff --git a/extern/libmv/intern/tracks.cc b/extern/libmv/intern/tracks.cc deleted file mode 100644 index 9b032b0760a..00000000000 --- a/extern/libmv/intern/tracks.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/tracks.h" -#include "intern/utildefines.h" - -#include "libmv/simple_pipeline/tracks.h" - -using libmv::Marker; -using libmv::Tracks; - -libmv_Tracks* libmv_tracksNew(void) { - Tracks* tracks = LIBMV_OBJECT_NEW(Tracks); - - return (libmv_Tracks*) tracks; -} - -void libmv_tracksDestroy(libmv_Tracks* libmv_tracks) { - LIBMV_OBJECT_DELETE(libmv_tracks, Tracks); -} - -void libmv_tracksInsert(libmv_Tracks *libmv_tracks, - int image, - int track, - double x, - double y, - double weight) { - ((Tracks *) libmv_tracks)->Insert(image, track, x, y, weight); -} diff --git a/extern/libmv/intern/tracks.h b/extern/libmv/intern/tracks.h deleted file mode 100644 index 79f6cc99579..00000000000 --- a/extern/libmv/intern/tracks.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_TRACKS_H_ -#define LIBMV_C_API_TRACKS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct libmv_Tracks libmv_Tracks; - -libmv_Tracks* libmv_tracksNew(void); - -void libmv_tracksDestroy(libmv_Tracks* libmv_tracks); - -void libmv_tracksInsert(libmv_Tracks* libmv_tracks, - int image, - int track, - double x, - double y, - double weight); - -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_C_API_TRACKS_H_ diff --git a/extern/libmv/intern/tracksN.cc b/extern/libmv/intern/tracksN.cc deleted file mode 100644 index 9e1da88ef10..00000000000 --- a/extern/libmv/intern/tracksN.cc +++ /dev/null @@ -1,138 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "intern/tracksN.h" -#include "intern/utildefines.h" -#include "libmv/autotrack/marker.h" -#include "libmv/autotrack/tracks.h" - -using mv::Marker; -using mv::Tracks; - -void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, - Marker *marker) { - marker->clip = libmv_marker.clip; - marker->frame = libmv_marker.frame; - marker->track = libmv_marker.track; - marker->center(0) = libmv_marker.center[0]; - marker->center(1) = libmv_marker.center[1]; - for (int i = 0; i < 4; i++) { - marker->patch.coordinates(i, 0) = libmv_marker.patch[i][0]; - marker->patch.coordinates(i, 1) = libmv_marker.patch[i][1]; - } - marker->search_region.min(0) = libmv_marker.search_region_min[0]; - marker->search_region.min(1) = libmv_marker.search_region_min[1]; - marker->search_region.max(0) = libmv_marker.search_region_max[0]; - marker->search_region.max(1) = libmv_marker.search_region_max[1]; - marker->weight = libmv_marker.weight; - marker->source = (Marker::Source) libmv_marker.source; - marker->status = (Marker::Status) libmv_marker.status; - marker->reference_clip = libmv_marker.reference_clip; - marker->reference_frame = libmv_marker.reference_frame; - marker->model_type = (Marker::ModelType) libmv_marker.model_type; - marker->model_id = libmv_marker.model_id; - marker->disabled_channels = libmv_marker.disabled_channels; -} - -void libmv_markerToApiMarker(const Marker& marker, - libmv_Marker *libmv_marker) { - libmv_marker->clip = marker.clip; - libmv_marker->frame = marker.frame; - libmv_marker->track = marker.track; - libmv_marker->center[0] = marker.center(0); - libmv_marker->center[1] = marker.center(1); - for (int i = 0; i < 4; i++) { - libmv_marker->patch[i][0] = marker.patch.coordinates(i, 0); - libmv_marker->patch[i][1] = marker.patch.coordinates(i, 1); - } - libmv_marker->search_region_min[0] = marker.search_region.min(0); - libmv_marker->search_region_min[1] = marker.search_region.min(1); - libmv_marker->search_region_max[0] = marker.search_region.max(0); - libmv_marker->search_region_max[1] = marker.search_region.max(1); - libmv_marker->weight = marker.weight; - libmv_marker->source = (libmv_MarkerSource) marker.source; - libmv_marker->status = (libmv_MarkerStatus) marker.status; - libmv_marker->reference_clip = marker.reference_clip; - libmv_marker->reference_frame = marker.reference_frame; - libmv_marker->model_type = (libmv_MarkerModelType) marker.model_type; - libmv_marker->model_id = marker.model_id; - libmv_marker->disabled_channels = marker.disabled_channels; -} - -libmv_TracksN* libmv_tracksNewN(void) { - Tracks* tracks = LIBMV_OBJECT_NEW(Tracks); - - return (libmv_TracksN*) tracks; -} - -void libmv_tracksDestroyN(libmv_TracksN* libmv_tracks) { - LIBMV_OBJECT_DELETE(libmv_tracks, Tracks); -} - -void libmv_tracksAddMarkerN(libmv_TracksN* libmv_tracks, - const libmv_Marker* libmv_marker) { - Marker marker; - libmv_apiMarkerToMarker(*libmv_marker, &marker); - ((Tracks*) libmv_tracks)->AddMarker(marker); -} - -void libmv_tracksGetMarkerN(libmv_TracksN* libmv_tracks, - int clip, - int frame, - int track, - libmv_Marker* libmv_marker) { - Marker marker; - ((Tracks*) libmv_tracks)->GetMarker(clip, frame, track, &marker); - libmv_markerToApiMarker(marker, libmv_marker); -} - -void libmv_tracksRemoveMarkerN(libmv_TracksN* libmv_tracks, - int clip, - int frame, - int track) { - ((Tracks *) libmv_tracks)->RemoveMarker(clip, frame, track); -} - -void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, - int track) { - ((Tracks *) libmv_tracks)->RemoveMarkersForTrack(track); -} - -int libmv_tracksMaxClipN(libmv_TracksN* libmv_tracks) { - return ((Tracks*) libmv_tracks)->MaxClip(); -} - -int libmv_tracksMaxFrameN(libmv_TracksN* libmv_tracks, int clip) { - return ((Tracks*) libmv_tracks)->MaxFrame(clip); -} - -int libmv_tracksMaxTrackN(libmv_TracksN* libmv_tracks) { - return ((Tracks*) libmv_tracks)->MaxTrack(); -} - -int libmv_tracksNumMarkersN(libmv_TracksN* libmv_tracks) { - return ((Tracks*) libmv_tracks)->NumMarkers(); -} diff --git a/extern/libmv/intern/tracksN.h b/extern/libmv/intern/tracksN.h deleted file mode 100644 index d0cb54e40bc..00000000000 --- a/extern/libmv/intern/tracksN.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -// TODO(serrgey): For the time being we're converting simple pipeline -// to an autotrack pipeline we call it tracks. -// Once we've done with porting we remove N. - -#ifndef LIBMV_C_API_TRACKSN_H_ -#define LIBMV_C_API_TRACKSN_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct libmv_TracksN libmv_TracksN; - -// Keep order in this enums exactly the same as in mv::Marker. -// Otherwise API wouldn't convert the values properly. -typedef enum libmv_MarkerSource { - LIBMV_MARKER_SOURCE_MANUAL, - LIBMV_MARKER_SOURCE_DETECTED, - LIBMV_MARKER_SOURCE_TRACKED, - LIBMV_MARKER_SOURCE_MATCHED, - LIBMV_MARKER_SOURCE_PREDICTED, -} libmv_MarkerSource; - -typedef enum libmv_MarkerStatus { - LIBMV_MARKER_STATUS_UNKNOWN, - LIBMV_MARKER_STATUS_INLIER, - LIBMV_MARKER_STATUS_OUTLIER, -} libmv_MarkerStatus; - -typedef enum libmv_MarkerModelType { - LIBMV_MARKER_MODEL_TYPE_POINT, - LIBMV_MARKER_MODEL_TYPE_PLANE, - LIBMV_MARKER_MODEL_TYPE_LINE, - LIBMV_MARKER_MODEL_TYPE_CUBE, -} libmv_MarkerModelType; - -enum libmv_MarkerChannel { - LIBMV_MARKER_CHANNEL_R = (1 << 0), - LIBMV_MARKER_CHANNEL_G = (1 << 1), - LIBMV_MARKER_CHANNEL_B = (1 << 2), -}; - -typedef struct libmv_Marker { - int clip; - int frame; - int track; - float center[2]; - float patch[4][2]; - float search_region_min[2]; - float search_region_max[2]; - float weight; - libmv_MarkerSource source; - libmv_MarkerStatus status; - int reference_clip; - int reference_frame; - libmv_MarkerModelType model_type; - int model_id; - int disabled_channels; -} libmv_Marker; - -#ifdef __cplusplus -namespace mv { - struct Marker; -} -void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, - mv::Marker *marker); - -void libmv_markerToApiMarker(const mv::Marker& marker, - libmv_Marker *libmv_marker); -#endif - -libmv_TracksN* libmv_tracksNewN(void); - -void libmv_tracksDestroyN(libmv_TracksN* libmv_tracks); - - -void libmv_tracksAddMarkerN(libmv_TracksN* libmv_tracks, - const libmv_Marker* libmv_marker); - -void libmv_tracksGetMarkerN(libmv_TracksN* libmv_tracks, - int clip, - int frame, - int track, - libmv_Marker* libmv_marker); - -void libmv_tracksRemoveMarkerN(libmv_TracksN* libmv_tracks, - int clip, - int frame, - int track); - -void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, - int track); - -int libmv_tracksMaxClipN(libmv_TracksN* libmv_tracks); -int libmv_tracksMaxFrameN(libmv_TracksN* libmv_tracks, int clip); -int libmv_tracksMaxTrackN(libmv_TracksN* libmv_tracks); -int libmv_tracksNumMarkersN(libmv_TracksN* libmv_tracks); - -#ifdef __cplusplus -} -#endif - -#endif // LIBMV_C_API_TRACKS_H_ diff --git a/extern/libmv/intern/utildefines.h b/extern/libmv/intern/utildefines.h deleted file mode 100644 index b1f11d6091e..00000000000 --- a/extern/libmv/intern/utildefines.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ***** 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_UTILDEFINES_H_ -#define LIBMV_C_API_UTILDEFINES_H_ - -#if defined(_MSC_VER) && _MSC_VER < 1900 -# 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_UTILDEFINES_H_ diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h deleted file mode 100644 index 92e206a19b2..00000000000 --- a/extern/libmv/libmv-capi.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * ***** 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) 2011 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation, - * Sergey Sharybin - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef LIBMV_C_API_H -#define LIBMV_C_API_H - -#include "intern/autotrack.h" -#include "intern/camera_intrinsics.h" -#include "intern/detector.h" -#include "intern/frame_accessor.h" -#include "intern/homography.h" -#include "intern/image.h" -#include "intern/logging.h" -#include "intern/reconstruction.h" -#include "intern/track_region.h" -#include "intern/tracks.h" -#include "intern/tracksN.h" - -#endif // LIBMV_C_API_H diff --git a/extern/libmv/libmv/autotrack/autotrack.cc b/extern/libmv/libmv/autotrack/autotrack.cc deleted file mode 100644 index 4c7bdf1fde8..00000000000 --- a/extern/libmv/libmv/autotrack/autotrack.cc +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#include "libmv/autotrack/autotrack.h" -#include "libmv/autotrack/quad.h" -#include "libmv/autotrack/frame_accessor.h" -#include "libmv/autotrack/predict_tracks.h" -#include "libmv/base/scoped_ptr.h" -#include "libmv/logging/logging.h" -#include "libmv/numeric/numeric.h" - -namespace mv { - -namespace { - -class DisableChannelsTransform : public FrameAccessor::Transform { - public: - DisableChannelsTransform(int disabled_channels) - : disabled_channels_(disabled_channels) { } - - int64_t key() const { - return disabled_channels_; - } - - void run(const FloatImage& input, FloatImage* output) const { - bool disable_red = (disabled_channels_ & Marker::CHANNEL_R) != 0, - disable_green = (disabled_channels_ & Marker::CHANNEL_G) != 0, - disable_blue = (disabled_channels_ & Marker::CHANNEL_B) != 0; - - LG << "Disabling channels: " - << (disable_red ? "R " : "") - << (disable_green ? "G " : "") - << (disable_blue ? "B" : ""); - - // It's important to rescale the resultappropriately so that e.g. if only - // blue is selected, it's not zeroed out. - float scale = (disable_red ? 0.0f : 0.2126f) + - (disable_green ? 0.0f : 0.7152f) + - (disable_blue ? 0.0f : 0.0722f); - - output->Resize(input.Height(), input.Width(), 1); - for (int y = 0; y < input.Height(); y++) { - for (int x = 0; x < input.Width(); x++) { - float r = disable_red ? 0.0f : input(y, x, 0); - float g = disable_green ? 0.0f : input(y, x, 1); - float b = disable_blue ? 0.0f : input(y, x, 2); - (*output)(y, x, 0) = (0.2126f * r + 0.7152f * g + 0.0722f * b) / scale; - } - } - } - - private: - // Bitfield representing visible channels, bits are from Marker::Channel. - int disabled_channels_; -}; - -template -void QuadToArrays(const QuadT& quad, ArrayT* x, ArrayT* y) { - for (int i = 0; i < 4; ++i) { - x[i] = quad.coordinates(i, 0); - y[i] = quad.coordinates(i, 1); - } -} - -void MarkerToArrays(const Marker& marker, double* x, double* y) { - Quad2Df offset_quad = marker.patch; - Vec2f origin = marker.search_region.Rounded().min; - offset_quad.coordinates.rowwise() -= origin.transpose(); - QuadToArrays(offset_quad, x, y); - x[4] = marker.center.x() - origin(0); - y[4] = marker.center.y() - origin(1); -} - -FrameAccessor::Key GetImageForMarker(const Marker& marker, - FrameAccessor* frame_accessor, - FloatImage* image) { - // TODO(sergey): Currently we pass float region to the accessor, - // but we don't want the accessor to decide the rounding, so we - // do rounding here. - // Ideally we would need to pass IntRegion to the frame accessor. - Region region = marker.search_region.Rounded(); - libmv::scoped_ptr transform = NULL; - if (marker.disabled_channels != 0) { - transform.reset(new DisableChannelsTransform(marker.disabled_channels)); - } - return frame_accessor->GetImage(marker.clip, - marker.frame, - FrameAccessor::MONO, - 0, // No downscale for now. - ®ion, - transform.get(), - image); -} - -} // namespace - -bool AutoTrack::TrackMarker(Marker* tracked_marker, - TrackRegionResult* result, - const TrackRegionOptions* track_options) { - // Try to predict the location of the second marker. - bool predicted_position = false; - if (PredictMarkerPosition(tracks_, tracked_marker)) { - LG << "Succesfully predicted!"; - predicted_position = true; - } else { - LG << "Prediction failed; trying to track anyway."; - } - - Marker reference_marker; - tracks_.GetMarker(tracked_marker->reference_clip, - tracked_marker->reference_frame, - tracked_marker->track, - &reference_marker); - - // Convert markers into the format expected by TrackRegion. - double x1[5], y1[5]; - MarkerToArrays(reference_marker, x1, y1); - - double x2[5], y2[5]; - MarkerToArrays(*tracked_marker, x2, y2); - - // TODO(keir): Technically this could take a smaller slice from the source - // image instead of taking one the size of the search window. - FloatImage reference_image; - FrameAccessor::Key reference_key = GetImageForMarker(reference_marker, - frame_accessor_, - &reference_image); - if (!reference_key) { - LG << "Couldn't get frame for reference marker: " << reference_marker; - return false; - } - - FloatImage tracked_image; - FrameAccessor::Key tracked_key = GetImageForMarker(*tracked_marker, - frame_accessor_, - &tracked_image); - if (!tracked_key) { - frame_accessor_->ReleaseImage(reference_key); - LG << "Couldn't get frame for tracked marker: " << tracked_marker; - return false; - } - - // Store original position befoer tracking, so we can claculate offset later. - Vec2f original_center = tracked_marker->center; - - // Do the tracking! - TrackRegionOptions local_track_region_options; - if (track_options) { - local_track_region_options = *track_options; - } - local_track_region_options.num_extra_points = 1; // For center point. - local_track_region_options.attempt_refine_before_brute = predicted_position; - TrackRegion(reference_image, - tracked_image, - x1, y1, - local_track_region_options, - x2, y2, - result); - - // Copy results over the tracked marker. - Vec2f tracked_origin = tracked_marker->search_region.Rounded().min; - for (int i = 0; i < 4; ++i) { - tracked_marker->patch.coordinates(i, 0) = x2[i] + tracked_origin[0]; - tracked_marker->patch.coordinates(i, 1) = y2[i] + tracked_origin[1]; - } - tracked_marker->center(0) = x2[4] + tracked_origin[0]; - tracked_marker->center(1) = y2[4] + tracked_origin[1]; - Vec2f delta = tracked_marker->center - original_center; - tracked_marker->search_region.Offset(delta); - tracked_marker->source = Marker::TRACKED; - tracked_marker->status = Marker::UNKNOWN; - tracked_marker->reference_clip = reference_marker.clip; - tracked_marker->reference_frame = reference_marker.frame; - - // Release the images from the accessor cache. - frame_accessor_->ReleaseImage(reference_key); - frame_accessor_->ReleaseImage(tracked_key); - - // TODO(keir): Possibly the return here should get removed since the results - // are part of TrackResult. However, eventually the autotrack stuff will have - // extra status (e.g. prediction fail, etc) that should get included. - return true; -} - -void AutoTrack::AddMarker(const Marker& marker) { - tracks_.AddMarker(marker); -} - -void AutoTrack::SetMarkers(vector* markers) { - tracks_.SetMarkers(markers); -} - -bool AutoTrack::GetMarker(int clip, int frame, int track, - Marker* markers) const { - return tracks_.GetMarker(clip, frame, track, markers); -} - -void AutoTrack::DetectAndTrack(const DetectAndTrackOptions& options) { - int num_clips = frame_accessor_->NumClips(); - for (int clip = 0; clip < num_clips; ++clip) { - int num_frames = frame_accessor_->NumFrames(clip); - vector previous_frame_markers; - // Q: How to decide track #s when detecting? - // Q: How to match markers from previous frame? set of prev frame tracks? - // Q: How to decide what markers should get tracked and which ones should not? - for (int frame = 0; frame < num_frames; ++frame) { - if (Cancelled()) { - LG << "Got cancel message while detecting and tracking..."; - return; - } - // First, get or detect markers for this frame. - vector this_frame_markers; - tracks_.GetMarkersInFrame(clip, frame, &this_frame_markers); - LG << "Clip " << clip << ", frame " << frame << " have " - << this_frame_markers.size(); - if (this_frame_markers.size() < options.min_num_features) { - DetectFeaturesInFrame(clip, frame); - this_frame_markers.clear(); - tracks_.GetMarkersInFrame(clip, frame, &this_frame_markers); - LG << "... detected " << this_frame_markers.size() << " features."; - } - if (previous_frame_markers.empty()) { - LG << "First frame; skipping tracking stage."; - previous_frame_markers.swap(this_frame_markers); - continue; - } - // Second, find tracks that should get tracked forward into this frame. - // To avoid tracking markers that are already tracked to this frame, make - // a sorted set of the tracks that exist in the last frame. - vector tracks_in_this_frame; - for (int i = 0; i < this_frame_markers.size(); ++i) { - tracks_in_this_frame.push_back(this_frame_markers[i].track); - } - std::sort(tracks_in_this_frame.begin(), - tracks_in_this_frame.end()); - - // Find tracks in the previous frame that are not in this one. - vector previous_frame_markers_to_track; - int num_skipped = 0; - for (int i = 0; i < previous_frame_markers.size(); ++i) { - if (std::binary_search(tracks_in_this_frame.begin(), - tracks_in_this_frame.end(), - previous_frame_markers[i].track)) { - num_skipped++; - } else { - previous_frame_markers_to_track.push_back(&previous_frame_markers[i]); - } - } - - // Finally track the markers from the last frame into this one. - // TODO(keir): Use OMP. - for (int i = 0; i < previous_frame_markers_to_track.size(); ++i) { - Marker this_frame_marker = *previous_frame_markers_to_track[i]; - this_frame_marker.frame = frame; - LG << "Tracking: " << this_frame_marker; - TrackRegionResult result; - TrackMarker(&this_frame_marker, &result); - if (result.is_usable()) { - LG << "Success: " << this_frame_marker; - AddMarker(this_frame_marker); - this_frame_markers.push_back(this_frame_marker); - } else { - LG << "Failed to track: " << this_frame_marker; - } - } - // Put the markers from this frame - previous_frame_markers.swap(this_frame_markers); - } - } -} - -} // namespace mv diff --git a/extern/libmv/libmv/autotrack/autotrack.h b/extern/libmv/libmv/autotrack/autotrack.h deleted file mode 100644 index 1d7422f54e7..00000000000 --- a/extern/libmv/libmv/autotrack/autotrack.h +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#ifndef LIBMV_AUTOTRACK_AUTOTRACK_H_ -#define LIBMV_AUTOTRACK_AUTOTRACK_H_ - -#include "libmv/autotrack/tracks.h" -#include "libmv/autotrack/region.h" -#include "libmv/tracking/track_region.h" - -namespace libmv { -class CameraIntrinsics; -}; - -namespace mv { - -using libmv::CameraIntrinsics; -using libmv::TrackRegionOptions; -using libmv::TrackRegionResult; - -struct FrameAccessor; -class OperationListener; - -// The coordinator of all tracking operations; keeps track of all state -// relating to tracking and reconstruction; for example, 2D tracks and motion -// models, reconstructed cameras, points, and planes; tracking settings; etc. -// -// Typical usage for full autotrack: -// -// AutoTrack auto_track(image_accessor); -// auto_track.SetNumFramesInClip(0, 10); -// auto_track.SetNumFramesInClip(1, 54); -// auto_track.AutoTrack() -// -// It is also possible to specify options to control the reconstruction. -// Furthermore, the individual methods of reconstruction are exposed to make it -// possible to interact with the pipeline as it runs. For example, to track one -// marker across frames, -// -// AutoTrack auto_track(image_accessor); -// auto_track.SetNumFramesInClip(0, 10); -// auto_track.SetNumFramesInClip(1, 54); -// auto_track.AddMarker(...); -// auto_track.TrackMarkerToFrame(int clip1, int frame1, -// int clip2, int frame2, -// options?) -// -class AutoTrack { - public: - struct Options { - // Default configuration for 2D tracking when calling TrackMarkerToFrame(). - TrackRegionOptions track_region; - - // Default search window for region tracking, in absolute frame pixels. - Region search_region; - }; - - AutoTrack(FrameAccessor* frame_accessor) - : frame_accessor_(frame_accessor) {} - - // Marker manipulation. - // Clip manipulation. - - // Set the number of clips. These clips will get accessed from the frame - // accessor, matches between frames found, and a reconstruction created. - //void SetNumFrames(int clip, int num_frames); - - // Tracking & Matching - - // Find the marker for the track in the frame indicated by the marker. - // Caller maintains ownership of *result and *tracked_marker. - bool TrackMarker(Marker* tracked_marker, - TrackRegionResult* result, - const TrackRegionOptions* track_options=NULL); - - // Wrapper around Tracks API; however these may add additional processing. - void AddMarker(const Marker& tracked_marker); - void SetMarkers(vector* markers); - bool GetMarker(int clip, int frame, int track, Marker* marker) const; - - // TODO(keir): Implement frame matching! This could be very cool for loop - // closing and connecting across clips. - //void MatchFrames(int clip1, int frame1, int clip2, int frame2) {} - - // Wrapper around the Reconstruction API. - // Returns the new ID. - int AddCameraIntrinsics(CameraIntrinsics* intrinsics) { - (void) intrinsics; - return 0; - } // XXX - int SetClipIntrinsics(int clip, int intrinsics) { - (void) clip; - (void) intrinsics; - return 0; - } // XXX - - enum Motion { - GENERAL_CAMERA_MOTION, - TRIPOD_CAMERA_MOTION, - }; - int SetClipMotion(int clip, Motion motion) { - (void) clip; - (void) motion; - return 0; - } // XXX - - // Decide what to refine for the given intrinsics. bundle_options is from - // bundle.h (e.g. BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL_K1). - void SetIntrinsicsRefine(int intrinsics, int bundle_options) { - (void) intrinsics; - (void) bundle_options; - } // XXX - - // Keyframe read/write. - struct ClipFrame { - int clip; - int frame; - }; - const vector& keyframes() { return keyframes_; } - void ClearKeyframes() { keyframes_.clear(); } - void SetKeyframes(const vector& keyframes) { - keyframes_ = keyframes; - } - - // What about reporting what happened? -- callbacks; maybe result struct. - void Reconstruct(); - - // Detect and track in 2D. - struct DetectAndTrackOptions { - int min_num_features; - }; - void DetectAndTrack(const DetectAndTrackOptions& options); - - struct DetectFeaturesInFrameOptions { - }; - void DetectFeaturesInFrame(int clip, int frame, - const DetectFeaturesInFrameOptions* options=NULL) { - (void) clip; - (void) frame; - (void) options; - } // XXX - - // Does not take ownership of the given listener, but keeps a reference to it. - void AddListener(OperationListener* listener) {(void) listener;} // XXX - - // Create the initial reconstruction, - //void FindInitialReconstruction(); - - // State machine - // - // Question: Have explicit state? Or determine state from existing data? - // Conclusion: Determine state from existing data. - // - // Preliminary state thoughts - // - // No tracks or markers - // - Tracks empty. - // - // Initial tracks found - // - All images have at least 5 tracks - // - // Ran RANSAC on tracks to mark inliers / outliers. - // - All images have at least 8 "inlier" tracks - // - // Detector matching run to close loops and match across clips - // - At least 5 matching tracks between clips - // - // Initial reconstruction found (2 frames)? - // - There exists two cameras with intrinsics / extrinsics - // - // Preliminary reconstruction finished - // - Poses for all frames in all clips estimated. - // - // Final reconstruction finished - // - Final reconstruction bundle adjusted. - - // For now, expose options directly. In the future this may change. - Options options; - - private: - bool Log(); - bool Progress(); - bool Cancelled() { return false; } - - Tracks tracks_; // May be normalized camera coordinates or raw pixels. - //Reconstruction reconstruction_; - - // TODO(keir): Add the motion models here. - //vector motion_models_; - - // TODO(keir): Should num_clips and num_frames get moved to FrameAccessor? - // TODO(keir): What about masking for clips and frames to prevent various - // things like reconstruction or tracking from happening on certain frames? - FrameAccessor* frame_accessor_; - //int num_clips_; - //vector num_frames_; // Indexed by clip. - - // The intrinsics for each clip, assuming each clip has fixed intrinsics. - // TODO(keir): Decide what the semantics should be for varying focal length. - vector clip_intrinsics_; - - vector keyframes_; -}; - -} // namespace mv - -#endif // LIBMV_AUTOTRACK_AUTOTRACK_H_ diff --git a/extern/libmv/libmv/autotrack/callbacks.h b/extern/libmv/libmv/autotrack/callbacks.h deleted file mode 100644 index e65841de3ce..00000000000 --- a/extern/libmv/libmv/autotrack/callbacks.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#ifndef LIBMV_AUTOTRACK_LISTENER_H_ -#define LIBMV_AUTOTRACK_LISTENER_H_ - -namespace mv { - -struct OperationListener { - // All hooks return true to continue or false to indicate the operation - // should abort. Hooks should be thread safe (reentrant). - virtual bool Log(const string& message) = 0; - virtual bool Progress(double fraction) = 0; - virtual bool Cancelled() = 0; -}; - -} // namespace mv - -#endif // LIBMV_AUTOTRACK_LISTENER_H_ diff --git a/extern/libmv/libmv/autotrack/frame_accessor.h b/extern/libmv/libmv/autotrack/frame_accessor.h deleted file mode 100644 index 8de5d865cd7..00000000000 --- a/extern/libmv/libmv/autotrack/frame_accessor.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#ifndef LIBMV_AUTOTRACK_FRAME_ACCESSOR_H_ -#define LIBMV_AUTOTRACK_FRAME_ACCESSOR_H_ - -#include - -#include "libmv/image/image.h" - -namespace mv { - -struct Region; - -using libmv::FloatImage; - -// This is the abstraction to different sources of images that will be part of -// a reconstruction. These may come from disk or they may come from Blender. In -// most cases it's expected that the implementation provides some caching -// otherwise performance will be terrible. Sometimes the images need to get -// filtered, and this interface provides for that as well (and permits -// implementations to cache filtered image pieces). -struct FrameAccessor { - struct Transform { - virtual ~Transform() { } - // The key should depend on the transform arguments. Must be non-zero. - virtual int64_t key() const = 0; - - // Apply the expected transform. Output is sized correctly already. - // TODO(keir): What about blurs that need to access pixels outside the ROI? - virtual void run(const FloatImage& input, FloatImage* output) const = 0; - }; - - enum InputMode { - MONO, - RGBA - }; - - typedef void* Key; - - // Get a possibly-filtered version of a frame of a video. Downscale will - // cause the input image to get downscaled by 2^downscale for pyramid access. - // Region is always in original-image coordinates, and describes the - // requested area. The transform describes an (optional) transform to apply - // to the image before it is returned. - // - // When done with an image, you must call ReleaseImage with the returned key. - virtual Key GetImage(int clip, - int frame, - InputMode input_mode, - int downscale, // Downscale by 2^downscale. - const Region* region, // Get full image if NULL. - const Transform* transform, // May be NULL. - FloatImage* destination) = 0; - - // Releases an image from the frame accessor. Non-caching implementations may - // free the image immediately; others may hold onto the image. - virtual void ReleaseImage(Key) = 0; - - virtual bool GetClipDimensions(int clip, int* width, int* height) = 0; - virtual int NumClips() = 0; - virtual int NumFrames(int clip) = 0; -}; - -} // namespace libmv - -#endif // LIBMV_AUTOTRACK_FRAME_ACCESSOR_H_ diff --git a/extern/libmv/libmv/autotrack/marker.h b/extern/libmv/libmv/autotrack/marker.h deleted file mode 100644 index bb803313af8..00000000000 --- a/extern/libmv/libmv/autotrack/marker.h +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#ifndef LIBMV_AUTOTRACK_MARKER_H_ -#define LIBMV_AUTOTRACK_MARKER_H_ - -#include - -#include "libmv/autotrack/quad.h" -#include "libmv/autotrack/region.h" -#include "libmv/numeric/numeric.h" - -namespace mv { - -using libmv::Vec2f; - -// A marker is the 2D location of a tracked region (quad) in an image. -// Note that some of this information could be normalized by having a -// collection of inter-connected structs. Instead the "fat Marker" design below -// trades memory for data structure simplicity. -struct Marker { - int clip; // The clip this marker is from. - int frame; // The frame within the clip this marker is from. - int track; // The track this marker is from. - - // The center of the marker in frame coordinates. This is typically, but not - // always, the same as the center of the patch. - Vec2f center; - - // A frame-realtive quad defining the part of the image the marker covers. - // For reference markers, the pixels in the patch are the tracking pattern. - Quad2Df patch; - - // Some markers are less certain than others; the weight determines the - // amount this marker contributes to the error. 1.0 indicates normal - // contribution; 0.0 indicates a zero-weight track (and will be omitted from - // bundle adjustment). - float weight; - - enum Source { - MANUAL, // The user placed this marker manually. - DETECTED, // A keypoint detector found this point. - TRACKED, // The tracking algorithm placed this marker. - MATCHED, // A matching algorithm (e.g. SIFT or SURF or ORB) found this. - PREDICTED, // A motion model predicted this marker. This is needed for - // handling occlusions in some cases where an imaginary marker - // is placed to keep camera motion smooth. - }; - Source source; - - // Markers may be inliers or outliers if the tracking fails; this allows - // visualizing the markers in the image. - enum Status { - UNKNOWN, - INLIER, - OUTLIER - }; - Status status; - - // When doing correlation tracking, where to search in the current frame for - // the pattern from the reference frame, in absolute frame coordinates. - Region search_region; - - // For tracked and matched markers, indicates what the reference was. - int reference_clip; - int reference_frame; - - // Model related information for non-point tracks. - // - // Some tracks are on a larger object, such as a plane or a line or perhaps - // another primitive (a rectangular prisim). This captures the information - // needed to say that for example a collection of markers belongs to model #2 - // (and model #2 is a plane). - enum ModelType { - POINT, - PLANE, - LINE, - CUBE - }; - ModelType model_type; - - // The model ID this track (e.g. the second model, which is a plane). - int model_id; - - // TODO(keir): Add a "int model_argument" to capture that e.g. a marker is on - // the 3rd face of a cube. - - enum Channel { - CHANNEL_R = (1 << 0), - CHANNEL_G = (1 << 1), - CHANNEL_B = (1 << 2), - }; - - // Channels from the original frame which this marker is unable to see. - int disabled_channels; - - // Offset everything (center, patch, search) by the given delta. - template - void Offset(const T& offset) { - center += offset.template cast(); - patch.coordinates.rowwise() += offset.template cast(); - search_region.Offset(offset); - } - - // Shift the center to the given new position (and patch, search). - template - void SetPosition(const T& new_center) { - Offset(new_center - center); - } -}; - -inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { - out << "{" - << marker.clip << ", " - << marker.frame << ", " - << marker.track << ", (" - << marker.center.x() << ", " - << marker.center.y() << ")" - << "}"; - return out; -} - -} // namespace mv - -#endif // LIBMV_AUTOTRACK_MARKER_H_ diff --git a/extern/libmv/libmv/autotrack/model.h b/extern/libmv/libmv/autotrack/model.h deleted file mode 100644 index 1165281cdac..00000000000 --- a/extern/libmv/libmv/autotrack/model.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#ifndef LIBMV_AUTOTRACK_MODEL_H_ -#define LIBMV_AUTOTRACK_MODEL_H_ - -#include "libmv/numeric/numeric.h" -#include "libmv/autotrack/quad.h" - -namespace mv { - -struct Model { - enum ModelType { - POINT, - PLANE, - LINE, - CUBE - }; - - // ??? -}; - -} // namespace mv - -#endif // LIBMV_AUTOTRACK_MODEL_H_ diff --git a/extern/libmv/libmv/autotrack/predict_tracks.cc b/extern/libmv/libmv/autotrack/predict_tracks.cc deleted file mode 100644 index adc986a0033..00000000000 --- a/extern/libmv/libmv/autotrack/predict_tracks.cc +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#include "libmv/autotrack/marker.h" -#include "libmv/autotrack/predict_tracks.h" -#include "libmv/autotrack/tracks.h" -#include "libmv/base/vector.h" -#include "libmv/logging/logging.h" -#include "libmv/tracking/kalman_filter.h" - -namespace mv { - -namespace { - -using libmv::vector; -using libmv::Vec2; - -// Implied time delta between steps. Set empirically by tweaking and seeing -// what numbers did best at prediction. -const double dt = 3.8; - -// State transition matrix. - -// The states for predicting a track are as follows: -// -// 0 - X position -// 1 - X velocity -// 2 - X acceleration -// 3 - Y position -// 4 - Y velocity -// 5 - Y acceleration -// -// Note that in the velocity-only state transition matrix, the acceleration -// component is ignored; so technically the system could be modelled with only -// 4 states instead of 6. For ease of implementation, this keeps order 6. - -// Choose one or the other model from below (velocity or acceleration). - -// For a typical system having constant velocity. This gives smooth-appearing -// predictions, but they are not always as accurate. -const double velocity_state_transition_data[] = { - 1, dt, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 1, dt, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 1 -}; - -// This 3rd-order system also models acceleration. This makes for "jerky" -// predictions, but that tend to be more accurate. -const double acceleration_state_transition_data[] = { - 1, dt, dt*dt/2, 0, 0, 0, - 0, 1, dt, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 1, dt, dt*dt/2, - 0, 0, 0, 0, 1, dt, - 0, 0, 0, 0, 0, 1 -}; - -// This system (attempts) to add an angular velocity component. However, it's -// total junk. -const double angular_state_transition_data[] = { - 1, dt, -dt, 0, 0, 0, // Position x - 0, 1, 0, 0, 0, 0, // Velocity x - 0, 0, 1, 0, 0, 0, // Angular momentum - 0, 0, dt, 1, dt, 0, // Position y - 0, 0, 0, 0, 1, 0, // Velocity y - 0, 0, 0, 0, 0, 1 // Ignored -}; - -const double* state_transition_data = velocity_state_transition_data; - -// Observation matrix. -const double observation_data[] = { - 1., 0., 0., 0., 0., 0., - 0., 0., 0., 1., 0., 0. -}; - -// Process covariance. -const double process_covariance_data[] = { - 35, 0, 0, 0, 0, 0, - 0, 5, 0, 0, 0, 0, - 0, 0, 5, 0, 0, 0, - 0, 0, 0, 35, 0, 0, - 0, 0, 0, 0, 5, 0, - 0, 0, 0, 0, 0, 5 -}; - -// Process covariance. -const double measurement_covariance_data[] = { - 0.01, 0.00, - 0.00, 0.01, -}; - -// Initial covariance. -const double initial_covariance_data[] = { - 10, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 10, 0, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 1 -}; - -typedef mv::KalmanFilter TrackerKalman; - -TrackerKalman filter(state_transition_data, - observation_data, - process_covariance_data, - measurement_covariance_data); - -bool OrderByFrameLessThan(const Marker* a, const Marker* b) { - if (a->frame == b->frame) { - if (a->clip == b->clip) { - return a->track < b->track; - } - return a->clip < b->clip; - } - return a->frame < b-> frame; -} - -// Predicted must be after the previous markers (in the frame numbering sense). -void RunPrediction(const vector previous_markers, - Marker* predicted_marker) { - TrackerKalman::State state; - state.mean << previous_markers[0]->center.x(), 0, 0, - previous_markers[0]->center.y(), 0, 0; - state.covariance = Eigen::Matrix( - initial_covariance_data); - - int current_frame = previous_markers[0]->frame; - int target_frame = predicted_marker->frame; - - bool predict_forward = current_frame < target_frame; - int frame_delta = predict_forward ? 1 : -1; - - for (int i = 1; i < previous_markers.size(); ++i) { - // Step forward predicting the state until it is on the current marker. - int predictions = 0; - for (; - current_frame != previous_markers[i]->frame; - current_frame += frame_delta) { - filter.Step(&state); - predictions++; - LG << "Predicted point (frame " << current_frame << "): " - << state.mean(0) << ", " << state.mean(3); - } - // Log the error -- not actually used, but interesting. - Vec2 error = previous_markers[i]->center.cast() - - Vec2(state.mean(0), state.mean(3)); - LG << "Prediction error for " << predictions << " steps: (" - << error.x() << ", " << error.y() << "); norm: " << error.norm(); - // Now that the state is predicted in the current frame, update the state - // based on the measurement from the current frame. - filter.Update(previous_markers[i]->center.cast(), - Eigen::Matrix( - measurement_covariance_data), - &state); - LG << "Updated point: " << state.mean(0) << ", " << state.mean(3); - } - // At this point as all the prediction that's possible is done. Finally - // predict until the target frame. - for (; current_frame != target_frame; current_frame += frame_delta) { - filter.Step(&state); - LG << "Final predicted point (frame " << current_frame << "): " - << state.mean(0) << ", " << state.mean(3); - } - - // The x and y positions are at 0 and 3; ignore acceleration and velocity. - predicted_marker->center.x() = state.mean(0); - predicted_marker->center.y() = state.mean(3); - - // Take the patch from the last marker then shift it to match the prediction. - const Marker& last_marker = *previous_markers[previous_markers.size() - 1]; - predicted_marker->patch = last_marker.patch; - Vec2f delta = predicted_marker->center - last_marker.center; - for (int i = 0; i < 4; ++i) { - predicted_marker->patch.coordinates.row(i) += delta; - } - - // Alter the search area as well so it always corresponds to the center. - predicted_marker->search_region = last_marker.search_region; - predicted_marker->search_region.Offset(delta); -} - -} // namespace - -bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) { - // Get all markers for this clip and track. - vector markers; - tracks.GetMarkersForTrackInClip(marker->clip, marker->track, &markers); - - if (markers.empty()) { - LG << "No markers to predict from for " << *marker; - return false; - } - - // Order the markers by frame within the clip. - vector boxed_markers(markers.size()); - for (int i = 0; i < markers.size(); ++i) { - boxed_markers[i] = &markers[i]; - } - std::sort(boxed_markers.begin(), boxed_markers.end(), OrderByFrameLessThan); - - // Find the insertion point for this marker among the returned ones. - int insert_at = -1; // If we find the exact frame - int insert_before = -1; // Otherwise... - for (int i = 0; i < boxed_markers.size(); ++i) { - if (boxed_markers[i]->frame == marker->frame) { - insert_at = i; - break; - } - if (boxed_markers[i]->frame > marker->frame) { - insert_before = i; - break; - } - } - - // Forward starts at the marker or insertion point, and goes forward. - int forward_scan_begin, forward_scan_end; - - // Backward scan starts at the marker or insertion point, and goes backward. - int backward_scan_begin, backward_scan_end; - - // Determine the scanning ranges. - if (insert_at == -1 && insert_before == -1) { - // Didn't find an insertion point except the end. - forward_scan_begin = forward_scan_end = 0; - backward_scan_begin = markers.size() - 1; - backward_scan_end = 0; - } else if (insert_at != -1) { - // Found existing marker; scan before and after it. - forward_scan_begin = insert_at + 1; - forward_scan_end = markers.size() - 1;; - backward_scan_begin = insert_at - 1; - backward_scan_end = 0; - } else { - // Didn't find existing marker but found an insertion point. - forward_scan_begin = insert_before; - forward_scan_end = markers.size() - 1;; - backward_scan_begin = insert_before - 1; - backward_scan_end = 0; - } - - const int num_consecutive_needed = 2; - - if (forward_scan_begin <= forward_scan_end && - forward_scan_end - forward_scan_begin > num_consecutive_needed) { - // TODO(keir): Finish this. - } - - bool predict_forward = false; - if (backward_scan_end <= backward_scan_begin) { - // TODO(keir): Add smarter handling and detecting of consecutive frames! - predict_forward = true; - } - - const int max_frames_to_predict_from = 20; - if (predict_forward) { - if (backward_scan_begin - backward_scan_end < num_consecutive_needed) { - // Not enough information to do a prediction. - LG << "Predicting forward impossible, not enough information"; - return false; - } - LG << "Predicting forward"; - int predict_begin = - std::max(backward_scan_begin - max_frames_to_predict_from, 0); - int predict_end = backward_scan_begin; - vector previous_markers; - for (int i = predict_begin; i <= predict_end; ++i) { - previous_markers.push_back(boxed_markers[i]); - } - RunPrediction(previous_markers, marker); - return true; - } else { - if (forward_scan_end - forward_scan_begin < num_consecutive_needed) { - // Not enough information to do a prediction. - LG << "Predicting backward impossible, not enough information"; - return false; - } - LG << "Predicting backward"; - int predict_begin = - std::min(forward_scan_begin + max_frames_to_predict_from, - forward_scan_end); - int predict_end = forward_scan_begin; - vector previous_markers; - for (int i = predict_begin; i >= predict_end; --i) { - previous_markers.push_back(boxed_markers[i]); - } - RunPrediction(previous_markers, marker); - return false; - } - -} - -} // namespace mv diff --git a/extern/libmv/libmv/autotrack/predict_tracks.h b/extern/libmv/libmv/autotrack/predict_tracks.h deleted file mode 100644 index 0a176d08378..00000000000 --- a/extern/libmv/libmv/autotrack/predict_tracks.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#ifndef LIBMV_AUTOTRACK_PREDICT_TRACKS_H_ -#define LIBMV_AUTOTRACK_PREDICT_TRACKS_H_ - -namespace mv { - -class Tracks; -struct Marker; - -// Predict the position of the given marker, and update it accordingly. The -// existing position will be overwritten. -bool PredictMarkerPosition(const Tracks& tracks, Marker* marker); - -} // namespace mv - -#endif // LIBMV_AUTOTRACK_PREDICT_TRACKS_H_ diff --git a/extern/libmv/libmv/autotrack/predict_tracks_test.cc b/extern/libmv/libmv/autotrack/predict_tracks_test.cc deleted file mode 100644 index fc90e260d94..00000000000 --- a/extern/libmv/libmv/autotrack/predict_tracks_test.cc +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#include "libmv/autotrack/predict_tracks.h" - -#include "libmv/autotrack/marker.h" -#include "libmv/autotrack/tracks.h" -#include "libmv/logging/logging.h" -#include "testing/testing.h" - -namespace mv { - -void AddMarker(int frame, float x, float y, Tracks* tracks) { - Marker marker; - marker.clip = marker.track = 0; - marker.frame = frame; - marker.center.x() = x; - marker.center.y() = y; - marker.patch.coordinates << x - 1, y - 1, - x + 1, y - 1, - x + 1, y + 1, - x - 1, y + 1; - tracks->AddMarker(marker); -} - -TEST(PredictMarkerPosition, EasyLinearMotion) { - Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); - AddMarker(2, 3.0, 10.0, &tracks); - AddMarker(3, 4.0, 15.0, &tracks); - AddMarker(4, 5.0, 20.0, &tracks); - AddMarker(5, 6.0, 25.0, &tracks); - AddMarker(6, 7.0, 30.0, &tracks); - AddMarker(7, 8.0, 35.0, &tracks); - - Marker predicted; - predicted.clip = 0; - predicted.track = 0; - predicted.frame = 8; - - PredictMarkerPosition(tracks, &predicted); - double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm(); - LG << "Got error: " << error; - EXPECT_LT(error, 0.1); - - // Check the patch coordinates as well. - double x = 9, y = 40.0; - Quad2Df expected_patch; - expected_patch.coordinates << x - 1, y - 1, - x + 1, y - 1, - x + 1, y + 1, - x - 1, y + 1; - - error = (expected_patch.coordinates - predicted.patch.coordinates).norm(); - LG << "Patch error: " << error; - EXPECT_LT(error, 0.1); -} - -TEST(PredictMarkerPosition, EasyBackwardLinearMotion) { - Tracks tracks; - AddMarker(8, 1.0, 0.0, &tracks); - AddMarker(7, 2.0, 5.0, &tracks); - AddMarker(6, 3.0, 10.0, &tracks); - AddMarker(5, 4.0, 15.0, &tracks); - AddMarker(4, 5.0, 20.0, &tracks); - AddMarker(3, 6.0, 25.0, &tracks); - AddMarker(2, 7.0, 30.0, &tracks); - AddMarker(1, 8.0, 35.0, &tracks); - - Marker predicted; - predicted.clip = 0; - predicted.track = 0; - predicted.frame = 0; - - PredictMarkerPosition(tracks, &predicted); - LG << predicted; - double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm(); - LG << "Got error: " << error; - EXPECT_LT(error, 0.1); - - // Check the patch coordinates as well. - double x = 9.0, y = 40.0; - Quad2Df expected_patch; - expected_patch.coordinates << x - 1, y - 1, - x + 1, y - 1, - x + 1, y + 1, - x - 1, y + 1; - - error = (expected_patch.coordinates - predicted.patch.coordinates).norm(); - LG << "Patch error: " << error; - EXPECT_LT(error, 0.1); -} - -TEST(PredictMarkerPosition, TwoFrameGap) { - Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); - AddMarker(2, 3.0, 10.0, &tracks); - AddMarker(3, 4.0, 15.0, &tracks); - AddMarker(4, 5.0, 20.0, &tracks); - AddMarker(5, 6.0, 25.0, &tracks); - AddMarker(6, 7.0, 30.0, &tracks); - // Missing frame 7! - - Marker predicted; - predicted.clip = 0; - predicted.track = 0; - predicted.frame = 8; - - PredictMarkerPosition(tracks, &predicted); - double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm(); - LG << "Got error: " << error; - EXPECT_LT(error, 0.1); -} - -TEST(PredictMarkerPosition, FourFrameGap) { - Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); - AddMarker(2, 3.0, 10.0, &tracks); - AddMarker(3, 4.0, 15.0, &tracks); - // Missing frames 4, 5, 6, 7. - - Marker predicted; - predicted.clip = 0; - predicted.track = 0; - predicted.frame = 8; - - PredictMarkerPosition(tracks, &predicted); - double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm(); - LG << "Got error: " << error; - EXPECT_LT(error, 2.0); // Generous error due to larger prediction window. -} - -TEST(PredictMarkerPosition, MultipleGaps) { - Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); - AddMarker(2, 3.0, 10.0, &tracks); - // AddMarker(3, 4.0, 15.0, &tracks); // Note the 3-frame gap. - // AddMarker(4, 5.0, 20.0, &tracks); - // AddMarker(5, 6.0, 25.0, &tracks); - AddMarker(6, 7.0, 30.0, &tracks); // Intermediate measurement. - // AddMarker(7, 8.0, 35.0, &tracks); - - Marker predicted; - predicted.clip = 0; - predicted.track = 0; - predicted.frame = 8; - - PredictMarkerPosition(tracks, &predicted); - double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm(); - LG << "Got error: " << error; - EXPECT_LT(error, 1.0); // Generous error due to larger prediction window. -} - -TEST(PredictMarkerPosition, MarkersInRandomOrder) { - Tracks tracks; - - // This is the same as the easy, except that the tracks are randomly ordered. - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(2, 3.0, 10.0, &tracks); - AddMarker(7, 8.0, 35.0, &tracks); - AddMarker(5, 6.0, 25.0, &tracks); - AddMarker(4, 5.0, 20.0, &tracks); - AddMarker(3, 4.0, 15.0, &tracks); - AddMarker(6, 7.0, 30.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); - - Marker predicted; - predicted.clip = 0; - predicted.track = 0; - predicted.frame = 8; - - PredictMarkerPosition(tracks, &predicted); - double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm(); - LG << "Got error: " << error; - EXPECT_LT(error, 0.1); -} - -} // namespace mv diff --git a/extern/libmv/libmv/autotrack/quad.h b/extern/libmv/libmv/autotrack/quad.h deleted file mode 100644 index 0c70f9882da..00000000000 --- a/extern/libmv/libmv/autotrack/quad.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#ifndef LIBMV_AUTOTRACK_QUAD_H_ -#define LIBMV_AUTOTRACK_QUAD_H_ - -#include - -namespace mv { - -template -struct Quad { - // A quad is 4 points; generally in 2D or 3D. - // - // +----------> x - // |\. - // | \. - // | z (z goes into screen) - // | - // | r0----->r1 - // | ^ | - // | | . | - // | | V - // | r3<-----r2 - // | \. - // | \. - // v normal goes away (right handed). - // y - // - // Each row is one of the corners coordinates; either (x, y) or (x, y, z). - Eigen::Matrix coordinates; -}; - -typedef Quad Quad2Df; - -} // namespace mv - -#endif // LIBMV_AUTOTRACK_QUAD_H_ diff --git a/extern/libmv/libmv/autotrack/reconstruction.h b/extern/libmv/libmv/autotrack/reconstruction.h deleted file mode 100644 index e1d4e882cbd..00000000000 --- a/extern/libmv/libmv/autotrack/reconstruction.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#ifndef LIBMV_AUTOTRACK_RECONSTRUCTION_H_ -#define LIBMV_AUTOTRACK_RECONSTRUCTION_H_ - -#include "libmv/base/vector.h" -#include "libmv/numeric/numeric.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" - -namespace mv { - -using libmv::CameraIntrinsics; -using libmv::vector; - -class Model; - -class CameraPose { - int clip; - int frame; - int intrinsics; - Mat3 R; - Vec3 t; -}; - -class Point { - int track; - - // The coordinates of the point. Note that not all coordinates are always - // used; for example points on a plane only use the first two coordinates. - Vec3 X; -}; - -// A reconstruction for a set of tracks. The indexing for clip, frame, and -// track should match that of a Tracs object, stored elsewhere. -class Reconstruction { - public: - // All methods copy their input reference or take ownership of the pointer. - void AddCameraPose(const CameraPose& pose); - int AddCameraIntrinsics(CameraIntrinsics* intrinsics); - int AddPoint(const Point& point); - int AddModel(Model* model); - - // Returns the corresponding pose or point or NULL if missing. - CameraPose* CameraPoseForFrame(int clip, int frame); - const CameraPose* CameraPoseForFrame(int clip, int frame) const; - Point* PointForTrack(int track); - const Point* PointForTrack(int track) const; - - const vector >& camera_poses() const { - return camera_poses_; - } - - private: - // Indexed by CameraPose::intrinsics. Owns the intrinsics objects. - vector camera_intrinsics_; - - // Indexed by Marker::clip then by Marker::frame. - vector > camera_poses_; - - // Indexed by Marker::track. - vector points_; - - // Indexed by Marker::model_id. Owns model objects. - vector models_; -}; - -} // namespace mv - -#endif // LIBMV_AUTOTRACK_RECONSTRUCTION_H_ diff --git a/extern/libmv/libmv/autotrack/region.h b/extern/libmv/libmv/autotrack/region.h deleted file mode 100644 index b35d99eb60d..00000000000 --- a/extern/libmv/libmv/autotrack/region.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#ifndef LIBMV_AUTOTRACK_REGION_H_ -#define LIBMV_AUTOTRACK_REGION_H_ - -#include "libmv/numeric/numeric.h" - -namespace mv { - -using libmv::Vec2f; - -// A region is a bounding box within an image. -// -// +----------> x -// | -// | (min.x, min.y) (max.x, min.y) -// | +-------------------------+ -// | | | -// | | | -// | | | -// | +-------------------------+ -// v (min.x, max.y) (max.x, max.y) -// y -// -struct Region { - Vec2f min; - Vec2f max; - - template - void Offset(const T& offset) { - min += offset.template cast(); - max += offset.template cast(); - } - - Region Rounded() const { - Region result; - result.min(0) = ceil(this->min(0)); - result.min(1) = ceil(this->min(1)); - result.max(0) = ceil(this->max(0)); - result.max(1) = ceil(this->max(1)); - return result; - } -}; - -} // namespace mv - -#endif // LIBMV_AUTOTRACK_REGION_H_ diff --git a/extern/libmv/libmv/autotrack/tracks.cc b/extern/libmv/libmv/autotrack/tracks.cc deleted file mode 100644 index 174f264f3f2..00000000000 --- a/extern/libmv/libmv/autotrack/tracks.cc +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#include "libmv/autotrack/tracks.h" - -#include -#include -#include - -#include "libmv/numeric/numeric.h" - -namespace mv { - -Tracks::Tracks(const Tracks& other) { - markers_ = other.markers_; -} - -Tracks::Tracks(const vector& markers) : markers_(markers) {} - -bool Tracks::GetMarker(int clip, int frame, int track, Marker* marker) const { - for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == clip && - markers_[i].frame == frame && - markers_[i].track == track) { - *marker = markers_[i]; - return true; - } - } - return false; -} - -void Tracks::GetMarkersForTrack(int track, vector* markers) const { - for (int i = 0; i < markers_.size(); ++i) { - if (track == markers_[i].track) { - markers->push_back(markers_[i]); - } - } -} - -void Tracks::GetMarkersForTrackInClip(int clip, - int track, - vector* markers) const { - for (int i = 0; i < markers_.size(); ++i) { - if (clip == markers_[i].clip && - track == markers_[i].track) { - markers->push_back(markers_[i]); - } - } -} - -void Tracks::GetMarkersInFrame(int clip, - int frame, - vector* markers) const { - for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == clip && - markers_[i].frame == frame) { - markers->push_back(markers_[i]); - } - } -} - -void Tracks::GetMarkersForTracksInBothImages(int clip1, int frame1, - int clip2, int frame2, - vector* markers) const { - std::vector image1_tracks; - std::vector image2_tracks; - - // Collect the tracks in each of the two images. - for (int i = 0; i < markers_.size(); ++i) { - int clip = markers_[i].clip; - int frame = markers_[i].frame; - if (clip == clip1 && frame == frame1) { - image1_tracks.push_back(markers_[i].track); - } else if (clip == clip2 && frame == frame2) { - image2_tracks.push_back(markers_[i].track); - } - } - - // Intersect the two sets to find the tracks of interest. - std::sort(image1_tracks.begin(), image1_tracks.end()); - std::sort(image2_tracks.begin(), image2_tracks.end()); - std::vector intersection; - std::set_intersection(image1_tracks.begin(), image1_tracks.end(), - image2_tracks.begin(), image2_tracks.end(), - std::back_inserter(intersection)); - - // Scan through and get the relevant tracks from the two images. - for (int i = 0; i < markers_.size(); ++i) { - // Save markers that are in either frame and are in our candidate set. - if (((markers_[i].clip == clip1 && - markers_[i].frame == frame1) || - (markers_[i].clip == clip2 && - markers_[i].frame == frame2)) && - std::binary_search(intersection.begin(), - intersection.end(), - markers_[i].track)) { - markers->push_back(markers_[i]); - } - } -} - -void Tracks::AddMarker(const Marker& marker) { - // TODO(keir): This is quadratic for repeated insertions. Fix this by adding - // a smarter data structure like a set<>. - for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == marker.clip && - markers_[i].frame == marker.frame && - markers_[i].track == marker.track) { - markers_[i] = marker; - return; - } - } - markers_.push_back(marker); -} - -void Tracks::SetMarkers(vector* markers) { - std::swap(markers_, *markers); -} - -bool Tracks::RemoveMarker(int clip, int frame, int track) { - int size = markers_.size(); - for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == clip && - markers_[i].frame == frame && - markers_[i].track == track) { - markers_[i] = markers_[size - 1]; - markers_.resize(size - 1); - return true; - } - } - return false; -} - -void Tracks::RemoveMarkersForTrack(int track) { - int size = 0; - for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].track != track) { - markers_[size++] = markers_[i]; - } - } - markers_.resize(size); -} - -int Tracks::MaxClip() const { - int max_clip = 0; - for (int i = 0; i < markers_.size(); ++i) { - max_clip = std::max(markers_[i].clip, max_clip); - } - return max_clip; -} - -int Tracks::MaxFrame(int clip) const { - int max_frame = 0; - for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == clip) { - max_frame = std::max(markers_[i].frame, max_frame); - } - } - return max_frame; -} - -int Tracks::MaxTrack() const { - int max_track = 0; - for (int i = 0; i < markers_.size(); ++i) { - max_track = std::max(markers_[i].track, max_track); - } - return max_track; -} - -int Tracks::NumMarkers() const { - return markers_.size(); -} - -} // namespace mv diff --git a/extern/libmv/libmv/autotrack/tracks.h b/extern/libmv/libmv/autotrack/tracks.h deleted file mode 100644 index 0b7de91d211..00000000000 --- a/extern/libmv/libmv/autotrack/tracks.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#ifndef LIBMV_AUTOTRACK_TRACKS_H_ -#define LIBMV_AUTOTRACK_TRACKS_H_ - -#include "libmv/base/vector.h" -#include "libmv/autotrack/marker.h" - -namespace mv { - -using libmv::vector; - -// The Tracks container stores correspondences between frames. -class Tracks { - public: - Tracks() { } - Tracks(const Tracks &other); - - // Create a tracks object with markers already initialized. Copies markers. - explicit Tracks(const vector& markers); - - // All getters append to the output argument vector. - bool GetMarker(int clip, int frame, int track, Marker* marker) const; - void GetMarkersForTrack(int track, vector* markers) const; - void GetMarkersForTrackInClip(int clip, - int track, - vector* markers) const; - void GetMarkersInFrame(int clip, int frame, vector* markers) const; - - // Get the markers in frame1 and frame2 which have a common track. - // - // This is not the same as the union of the markers in frame1 and - // frame2; each marker is for a track that appears in both images. - void GetMarkersForTracksInBothImages(int clip1, int frame1, - int clip2, int frame2, - vector* markers) const; - - void AddMarker(const Marker& marker); - - // Moves the contents of *markers over top of the existing markers. This - // destroys *markers in the process (but avoids copies). - void SetMarkers(vector* markers); - bool RemoveMarker(int clip, int frame, int track); - void RemoveMarkersForTrack(int track); - - int MaxClip() const; - int MaxFrame(int clip) const; - int MaxTrack() const; - int NumMarkers() const; - - const vector& markers() const { return markers_; } - - private: - vector markers_; - - // TODO(keir): Consider adding access-map data structures to avoid all the - // linear lookup penalties for the accessors. -}; - -} // namespace mv - -#endif // LIBMV_AUTOTRACK_TRACKS_H_ diff --git a/extern/libmv/libmv/autotrack/tracks_test.cc b/extern/libmv/libmv/autotrack/tracks_test.cc deleted file mode 100644 index 028b4a10913..00000000000 --- a/extern/libmv/libmv/autotrack/tracks_test.cc +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) - -#include "libmv/autotrack/tracks.h" - -#include "testing/testing.h" -#include "libmv/logging/logging.h" - -namespace mv { - -TEST(Tracks, MaxFrame) { - Marker marker; - Tracks tracks; - - // Add some markers to clip 0. - marker.clip = 0; - marker.frame = 1; - tracks.AddMarker(marker); - - // Add some markers to clip 1. - marker.clip = 1; - marker.frame = 1; - tracks.AddMarker(marker); - - marker.clip = 1; - marker.frame = 12; - tracks.AddMarker(marker); - - EXPECT_EQ(1, tracks.MaxFrame(0)); - EXPECT_EQ(12, tracks.MaxFrame(1)); -} - -} // namespace mv diff --git a/extern/libmv/libmv/base/aligned_malloc.cc b/extern/libmv/libmv/base/aligned_malloc.cc deleted file mode 100644 index 9141186f196..00000000000 --- a/extern/libmv/libmv/base/aligned_malloc.cc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/base/aligned_malloc.h" -#include "libmv/logging/logging.h" - -#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) -// Needed for memalign on Linux and _aligned_alloc on Windows. -# ifdef FREE_WINDOWS -/* make sure _aligned_malloc is included */ -# ifdef __MSVCRT_VERSION__ -# undef __MSVCRT_VERSION__ -# endif - -# define __MSVCRT_VERSION__ 0x0700 -# endif // FREE_WINDOWS - -# include -#else -// Apple's malloc is 16-byte aligned, and does not have malloc.h, so include -// stdilb instead. -# include -#endif - -namespace libmv { - -void *aligned_malloc(int size, int alignment) { -#ifdef _WIN32 - return _aligned_malloc(size, alignment); -#elif __APPLE__ - // On Mac OS X, both the heap and the stack are guaranteed 16-byte aligned so - // they work natively with SSE types with no further work. - CHECK_EQ(alignment, 16); - return malloc(size); -#elif defined(__FreeBSD__) || defined(__NetBSD__) - void *result; - - if (posix_memalign(&result, alignment, size)) { - // non-zero means allocation error - // either no allocation or bad alignment value - return NULL; - } - return result; -#else // This is for Linux. - return memalign(alignment, size); -#endif -} - -void aligned_free(void *ptr) { -#ifdef _WIN32 - _aligned_free(ptr); -#else - free(ptr); -#endif -} - -} // namespace libmv diff --git a/extern/libmv/libmv/base/aligned_malloc.h b/extern/libmv/libmv/base/aligned_malloc.h deleted file mode 100644 index 096ff6e2d7c..00000000000 --- a/extern/libmv/libmv/base/aligned_malloc.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_BASE_ALIGNED_MALLOC_H_ -#define LIBMV_BASE_ALIGNED_MALLOC_H_ - -namespace libmv { - -// Allocate block of size bytes at least aligned to a given value. -void *aligned_malloc(int size, int alignment); - -// Free memory allocated by aligned_malloc. -void aligned_free(void *ptr); - -} // namespace libmv - -#endif // LIBMV_BASE_ALIGNED_MALLOC_H_ diff --git a/extern/libmv/libmv/base/id_generator.h b/extern/libmv/libmv/base/id_generator.h deleted file mode 100644 index bf1eafd218e..00000000000 --- a/extern/libmv/libmv/base/id_generator.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_ID_GENERATOR_H -#define LIBMV_ID_GENERATOR_H - -namespace libmv { - -template -class IdGenerator { - public: - IdGenerator() : next_(0) {} - ID Generate() { return next_++; } - private: - ID next_; -}; - -} // namespace libmv - -#endif // LIBMV_ID_GENERATOR_H diff --git a/extern/libmv/libmv/base/scoped_ptr.h b/extern/libmv/libmv/base/scoped_ptr.h deleted file mode 100644 index b9cd4854213..00000000000 --- a/extern/libmv/libmv/base/scoped_ptr.h +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_BASE_SCOPED_PTR_H -#define LIBMV_BASE_SCOPED_PTR_H - -#include -#include - -namespace libmv { - -/** - * A handle for a heap-allocated resource that should be freed when it goes out - * of scope. This looks similar to the one found in TR1. - */ -template -class scoped_ptr { - public: - scoped_ptr(T *resource) : resource_(resource) {} - ~scoped_ptr() { reset(0); } - - T *get() const { return resource_; } - T *operator->() const { return resource_; } - T &operator*() const { return *resource_; } - - void reset(T *new_resource) { - if (sizeof(T)) { - delete resource_; - } - resource_ = new_resource; - } - - T *release() { - T *released_resource = resource_; - resource_ = 0; - return released_resource; - } - - private: - // No copying allowed. - T *resource_; -}; - -// Same as scoped_ptr but caller must allocate the data -// with new[] and the destructor will free the memory -// using delete[]. -template -class scoped_array { - public: - scoped_array(T *array) : array_(array) {} - ~scoped_array() { reset(NULL); } - - T *get() const { return array_; } - - T& operator[](std::ptrdiff_t i) const { - assert(i >= 0); - assert(array_ != NULL); - return array_[i]; - } - - void reset(T *new_array) { - if (sizeof(T)) { - delete array_; - } - array_ = new_array; - } - - T *release() { - T *released_array = array_; - array_ = NULL; - return released_array; - } - - private: - T *array_; - - // Forbid comparison of different scoped_array types. - template bool operator==(scoped_array const& p2) const; - template bool operator!=(scoped_array const& p2) const; - - // Disallow evil constructors - scoped_array(const scoped_array&); - void operator=(const scoped_array&); -}; - -} // namespace libmv - -#endif // LIBMV_BASE_SCOPED_PTR_H diff --git a/extern/libmv/libmv/base/scoped_ptr_test.cc b/extern/libmv/libmv/base/scoped_ptr_test.cc deleted file mode 100644 index ce1d56b500a..00000000000 --- a/extern/libmv/libmv/base/scoped_ptr_test.cc +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/base/scoped_ptr.h" -#include "testing/testing.h" - -namespace libmv { -namespace { - -struct FreeMe { - FreeMe(int *freed) : freed(freed) {} - ~FreeMe() { (*freed)++; } - int *freed; -}; - -TEST(ScopedPtr, NullDoesNothing) { - scoped_ptr x(NULL); - // Does nothing. -} - -TEST(ScopedPtr, FreesWhenOutOfScope) { - int frees = 0; - { - scoped_ptr scoped(new FreeMe(&frees)); - EXPECT_EQ(0, frees); - } - EXPECT_EQ(1, frees); -} - -TEST(ScopedPtr, Operators) { - int tag = 123; - scoped_ptr scoped(new FreeMe(&tag)); - EXPECT_EQ(123, *(scoped->freed)); - EXPECT_EQ(123, *((*scoped).freed)); -} - -TEST(ScopedPtr, Reset) { - int frees = 0; - scoped_ptr scoped(new FreeMe(&frees)); - EXPECT_EQ(0, frees); - scoped.reset(new FreeMe(&frees)); - EXPECT_EQ(1, frees); -} - -TEST(ScopedPtr, ReleaseAndGet) { - int frees = 0; - FreeMe *allocated = new FreeMe(&frees); - FreeMe *released = NULL; - { - scoped_ptr scoped(allocated); - EXPECT_EQ(0, frees); - EXPECT_EQ(allocated, scoped.get()); - released = scoped.release(); - EXPECT_EQ(0, frees); - EXPECT_EQ(released, allocated); - } - EXPECT_EQ(0, frees); - delete released; -} - -} // namespace -} // namespace libmv diff --git a/extern/libmv/libmv/base/vector.h b/extern/libmv/libmv/base/vector.h deleted file mode 100644 index 1931fb0b1f9..00000000000 --- a/extern/libmv/libmv/base/vector.h +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Get an aligned vector implementation. Must be included before . The -// Eigen guys went through some trouble to make a portable override for the -// fixed size vector types. - -#ifndef LIBMV_BASE_VECTOR_H -#define LIBMV_BASE_VECTOR_H - -#include -#include - -#include - -namespace libmv { - -// A simple container class, which guarantees 16 byte alignment needed for most -// vectorization. Don't use this container for classes that cannot be copied -// via memcpy. -// FIXME: this class has some issues: -// - doesn't support iterators. -// - impede compatibility with code using STL. -// - the STL already provide support for custom allocators -// it could be replaced with a simple -// template class vector : std::vector {} declaration -// provided it doesn't break code relying on libmv::vector specific behavior -template > -class vector { - public: - ~vector() { clear(); } - - vector() { init(); } - vector(int size) { init(); resize(size); } - vector(int size, const T & val) { - init(); - resize(size); - std::fill(data_, data_+size_, val); } - - // Copy constructor and assignment. - vector(const vector &rhs) { - init(); - copy(rhs); - } - vector &operator=(const vector &rhs) { - if (&rhs != this) { - copy(rhs); - } - return *this; - } - - /// Swaps the contents of two vectors in constant time. - void swap(vector &other) { - std::swap(allocator_, other.allocator_); - std::swap(size_, other.size_); - std::swap(capacity_, other.capacity_); - std::swap(data_, other.data_); - } - - T *data() const { return data_; } - int size() const { return size_; } - int capacity() const { return capacity_; } - const T& back() const { return data_[size_ - 1]; } - T& back() { return data_[size_ - 1]; } - const T& front() const { return data_[0]; } - T& front() { return data_[0]; } - const T& operator[](int n) const { return data_[n]; } - T& operator[](int n) { return data_[n]; } - const T& at(int n) const { return data_[n]; } - T& at(int n) { return data_[n]; } - const T * begin() const { return data_; } - const T * end() const { return data_+size_; } - T * begin() { return data_; } - T * end() { return data_+size_; } - - void resize(size_t size) { - reserve(size); - if (size > size_) { - construct(size_, size); - } else if (size < size_) { - destruct(size, size_); - } - size_ = size; - } - - void push_back(const T &value) { - if (size_ == capacity_) { - reserve(size_ ? 2 * size_ : 1); - } - new (&data_[size_++]) T(value); - } - - void pop_back() { - resize(size_ - 1); - } - - void clear() { - destruct(0, size_); - deallocate(); - init(); - } - - void reserve(unsigned int size) { - if (size > size_) { - T *data = static_cast(allocate(size)); - memcpy(data, data_, sizeof(*data)*size_); - allocator_.deallocate(data_, capacity_); - data_ = data; - capacity_ = size; - } - } - - bool empty() { - return size_ == 0; - } - - private: - void construct(int start, int end) { - for (int i = start; i < end; ++i) { - new (&data_[i]) T; - } - } - void destruct(int start, int end) { - for (int i = start; i < end; ++i) { - data_[i].~T(); - } - } - void init() { - size_ = 0; - data_ = 0; - capacity_ = 0; - } - - void *allocate(int size) { - return size ? allocator_.allocate(size) : 0; - } - - void deallocate() { - allocator_.deallocate(data_, size_); - data_ = 0; - } - - void copy(const vector &rhs) { - resize(rhs.size()); - for (int i = 0; i < rhs.size(); ++i) { - (*this)[i] = rhs[i]; - } - } - - Allocator allocator_; - size_t size_; - size_t capacity_; - T *data_; -}; - -} // namespace libmv - -#endif // LIBMV_BASE_VECTOR_H diff --git a/extern/libmv/libmv/base/vector_test.cc b/extern/libmv/libmv/base/vector_test.cc deleted file mode 100644 index f17718c3926..00000000000 --- a/extern/libmv/libmv/base/vector_test.cc +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/base/vector.h" -#include "libmv/numeric/numeric.h" -#include "testing/testing.h" -#include - -namespace { -using namespace libmv; - -// This uses a Vec2d which is a fixed-size vectorizable Eigen type. It is -// necessary to test vectorizable types to ensure that the alignment asserts -// trigger if the alignment is not correct. -TEST(VectorAlignmentTest, PushBack) { - Vec2 x1, x2; - x1 << 1, 2; - x2 << 3, 4; - - vector vs; - vs.push_back(x1); - EXPECT_EQ(1, vs.size()); - EXPECT_EQ(1, vs.capacity()); - - vs.push_back(x2); - EXPECT_EQ(2, vs.size()); - EXPECT_EQ(2, vs.capacity()); - - // The following is necessary because of some bug in gtest; the expected - // parameter can't be a fixed size vectorizable type with alignment - // requirements. - Vec x1r = x1; - Vec x2r = x2; - EXPECT_EQ(x1r, vs[0]); - EXPECT_EQ(x2r, vs[1]); - - vs.push_back(x2); - vs.push_back(x2); - vs.push_back(x2); - EXPECT_EQ(5, vs.size()); - EXPECT_EQ(8, vs.capacity()); -} - -// Count the number of destruct calls to test that the destructor gets called. -int foo_construct_calls = 0; -int foo_destruct_calls = 0; - -struct Foo { - public: - Foo() : value(5) { foo_construct_calls++; } - ~Foo() { foo_destruct_calls++; } - int value; -}; - -struct VectorTest : public testing::Test { - VectorTest() { - foo_construct_calls = 0; - foo_destruct_calls = 0; - } -}; - -TEST_F(VectorTest, EmptyVectorDoesNotConstruct) { - { - vector v; - EXPECT_EQ(0, v.size()); - EXPECT_EQ(0, v.capacity()); - } - EXPECT_EQ(0, foo_construct_calls); - EXPECT_EQ(0, foo_destruct_calls); -} - -TEST_F(VectorTest, DestructorGetsCalled) { - { - vector v; - v.resize(5); - } - EXPECT_EQ(5, foo_construct_calls); - EXPECT_EQ(5, foo_destruct_calls); -} - -TEST_F(VectorTest, ReserveDoesNotCallConstructorsOrDestructors) { - vector v; - EXPECT_EQ(0, v.size()); - EXPECT_EQ(0, v.capacity()); - EXPECT_EQ(0, foo_construct_calls); - EXPECT_EQ(0, foo_destruct_calls); - - v.reserve(5); - EXPECT_EQ(0, v.size()); - EXPECT_EQ(5, v.capacity()); - EXPECT_EQ(0, foo_construct_calls); - EXPECT_EQ(0, foo_destruct_calls); -} - -TEST_F(VectorTest, ResizeConstructsAndDestructsAsExpected) { - vector v; - - // Create one object. - v.resize(1); - EXPECT_EQ(1, v.size()); - EXPECT_EQ(1, v.capacity()); - EXPECT_EQ(1, foo_construct_calls); - EXPECT_EQ(0, foo_destruct_calls); - EXPECT_EQ(5, v[0].value); - - // Create two more. - v.resize(3); - EXPECT_EQ(3, v.size()); - EXPECT_EQ(3, v.capacity()); - EXPECT_EQ(3, foo_construct_calls); - EXPECT_EQ(0, foo_destruct_calls); - - // Delete the last one. - v.resize(2); - EXPECT_EQ(2, v.size()); - EXPECT_EQ(3, v.capacity()); - EXPECT_EQ(3, foo_construct_calls); - EXPECT_EQ(1, foo_destruct_calls); - - // Delete the remaining two. - v.resize(0); - EXPECT_EQ(0, v.size()); - EXPECT_EQ(3, v.capacity()); - EXPECT_EQ(3, foo_construct_calls); - EXPECT_EQ(3, foo_destruct_calls); -} - -TEST_F(VectorTest, PushPopBack) { - vector v; - - Foo foo; - foo.value = 10; - v.push_back(foo); - EXPECT_EQ(1, v.size()); - EXPECT_EQ(10, v.back().value); - - v.pop_back(); - EXPECT_EQ(0, v.size()); - EXPECT_EQ(1, foo_construct_calls); - EXPECT_EQ(1, foo_destruct_calls); -} - -TEST_F(VectorTest, CopyConstructor) { - vector a; - a.push_back(1); - a.push_back(5); - a.push_back(3); - - vector b(a); - EXPECT_EQ(a.size(), b.size()); - //EXPECT_EQ(a.capacity(), b.capacity()); - for (int i = 0; i < a.size(); ++i) { - EXPECT_EQ(a[i], b[i]); - } -} - -TEST_F(VectorTest, OperatorEquals) { - vector a, b; - a.push_back(1); - a.push_back(5); - a.push_back(3); - - b = a; - - EXPECT_EQ(a.size(), b.size()); - //EXPECT_EQ(a.capacity(), b.capacity()); - for (int i = 0; i < a.size(); ++i) { - EXPECT_EQ(a[i], b[i]); - } -} - -TEST_F(VectorTest, STLFind) { - vector a; - a.push_back(1); - a.push_back(5); - a.push_back(3); - - // Find return an int * - EXPECT_EQ(std::find(&a[0], &a[2], 1) == &a[0], true); - EXPECT_EQ(std::find(&a[0], &a[2], 5) == &a[1], true); - EXPECT_EQ(std::find(&a[0], &a[2], 3) == &a[2], true); - - // Find return a const int * - EXPECT_EQ(std::find(a.begin(), a.end(), 1) == &a[0], true); - EXPECT_EQ(std::find(a.begin(), a.end(), 5) == &a[1], true); - EXPECT_EQ(std::find(a.begin(), a.end(), 3) == &a[2], true); - - // Search value that are not in the vector - EXPECT_EQ(std::find(a.begin(), a.end(), 0) == a.end(), true); - EXPECT_EQ(std::find(a.begin(), a.end(), 52) == a.end(), true); -} - -TEST(Vector, swap) { - vector a, b; - a.push_back(1); - a.push_back(2); - b.push_back(3); - a.swap(b); - EXPECT_EQ(1, a.size()); - EXPECT_EQ(3, a[0]); - EXPECT_EQ(2, b.size()); - EXPECT_EQ(1, b[0]); - EXPECT_EQ(2, b[1]); -} - -} // namespace diff --git a/extern/libmv/libmv/base/vector_utils.h b/extern/libmv/libmv/base/vector_utils.h deleted file mode 100644 index c71e1bea951..00000000000 --- a/extern/libmv/libmv/base/vector_utils.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - - -#ifndef LIBMV_BASE_VECTOR_UTILS_H_ -#define LIBMV_BASE_VECTOR_UTILS_H_ - -/// Delete the contents of a container. -template -void DeleteElements(Array *array) { - for (int i = 0; i < array->size(); ++i) { - delete (*array)[i]; - } - array->clear(); -} - -#endif // LIBMV_BASE_VECTOR_UTILS_H_ diff --git a/extern/libmv/libmv/image/array_nd.cc b/extern/libmv/libmv/image/array_nd.cc deleted file mode 100644 index 469a19aabf1..00000000000 --- a/extern/libmv/libmv/image/array_nd.cc +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/image/image.h" -#include -#include - -namespace libmv { - -void FloatArrayToScaledByteArray(const Array3Df &float_array, - Array3Du *byte_array, - bool automatic_range_detection - ) { - byte_array->ResizeLike(float_array); - float minval = HUGE_VAL; - float maxval = -HUGE_VAL; - if (automatic_range_detection) { - for (int i = 0; i < float_array.Height(); ++i) { - for (int j = 0; j < float_array.Width(); ++j) { - for (int k = 0; k < float_array.Depth(); ++k) { - minval = std::min(minval, float_array(i, j, k)); - maxval = std::max(maxval, float_array(i, j, k)); - } - } - } - } else { - minval = 0; - maxval = 1; - } - for (int i = 0; i < float_array.Height(); ++i) { - for (int j = 0; j < float_array.Width(); ++j) { - for (int k = 0; k < float_array.Depth(); ++k) { - float unscaled = (float_array(i, j, k) - minval) / (maxval - minval); - (*byte_array)(i, j, k) = (unsigned char)(255 * unscaled); - } - } - } -} - -void ByteArrayToScaledFloatArray(const Array3Du &byte_array, - Array3Df *float_array) { - float_array->ResizeLike(byte_array); - for (int i = 0; i < byte_array.Height(); ++i) { - for (int j = 0; j < byte_array.Width(); ++j) { - for (int k = 0; k < byte_array.Depth(); ++k) { - (*float_array)(i, j, k) = float(byte_array(i, j, k)) / 255.0f; - } - } - } -} - -void SplitChannels(const Array3Df &input, - Array3Df *channel0, - Array3Df *channel1, - Array3Df *channel2) { - assert(input.Depth() >= 3); - channel0->Resize(input.Height(), input.Width()); - channel1->Resize(input.Height(), input.Width()); - channel2->Resize(input.Height(), input.Width()); - for (int row = 0; row < input.Height(); ++row) { - for (int column = 0; column < input.Width(); ++column) { - (*channel0)(row, column) = input(row, column, 0); - (*channel1)(row, column) = input(row, column, 1); - (*channel2)(row, column) = input(row, column, 2); - } - } -} - -void PrintArray(const Array3Df &array) { - using namespace std; - - printf("[\n"); - for (int r = 0; r < array.Height(); ++r) { - printf("["); - for (int c = 0; c < array.Width(); ++c) { - if (array.Depth() == 1) { - printf("%11f, ", array(r, c)); - } else { - printf("["); - for (int k = 0; k < array.Depth(); ++k) { - printf("%11f, ", array(r, c, k)); - } - printf("],"); - } - } - printf("],\n"); - } - printf("]\n"); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/image/array_nd.h b/extern/libmv/libmv/image/array_nd.h deleted file mode 100644 index e95e66aa2b3..00000000000 --- a/extern/libmv/libmv/image/array_nd.h +++ /dev/null @@ -1,497 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_IMAGE_ARRAY_ND_H -#define LIBMV_IMAGE_ARRAY_ND_H - -#include -#include -#include - -#include "libmv/image/tuple.h" - -namespace libmv { - -class BaseArray {}; - -/// A multidimensional array class. -template -class ArrayND : public BaseArray { - public: - typedef T Scalar; - - /// Type for the multidimensional indices. - typedef Tuple Index; - - /// Create an empty array. - ArrayND() : data_(NULL), own_data_(true) { Resize(Index(0)); } - - /// Create an array with the specified shape. - ArrayND(const Index &shape) : data_(NULL), own_data_(true) { Resize(shape); } - - /// Create an array with the specified shape. - ArrayND(int *shape) : data_(NULL), own_data_(true) { Resize(shape); } - - /// Copy constructor. - ArrayND(const ArrayND &b) : data_(NULL), own_data_(true) { - ResizeLike(b); - std::memcpy(Data(), b.Data(), sizeof(T) * Size()); - } - - ArrayND(int s0) : data_(NULL), own_data_(true) { Resize(s0); } - ArrayND(int s0, int s1) : data_(NULL), own_data_(true) { Resize(s0, s1); } - ArrayND(int s0, int s1, int s2) : data_(NULL), own_data_(true) { - Resize(s0, s1, s2); - } - - ArrayND(T* data, int s0, int s1, int s2) - : shape_(0), strides_(0), data_(data), own_data_(false) { - Resize(s0, s1, s2); - } - - /// Destructor deletes pixel data. - ~ArrayND() { - if (own_data_) { - delete [] data_; - } - } - - /// Assignation copies pixel data. - ArrayND &operator=(const ArrayND &b) { - assert(this != &b); - ResizeLike(b); - std::memcpy(Data(), b.Data(), sizeof(T) * Size()); - return *this; - } - - const Index &Shapes() const { - return shape_; - } - - const Index &Strides() const { - return strides_; - } - - /// Create an array of shape s. - void Resize(const Index &new_shape) { - if (data_ != NULL && shape_ == new_shape) { - // Don't bother realloacting if the shapes match. - return; - } - shape_.Reset(new_shape); - strides_(N - 1) = 1; - for (int i = N - 1; i > 0; --i) { - strides_(i - 1) = strides_(i) * shape_(i); - } - if (own_data_) { - delete [] data_; - data_ = NULL; - if (Size() > 0) { - data_ = new T[Size()]; - } - } - } - - template - void ResizeLike(const ArrayND &other) { - Resize(other.Shape()); - } - - /// Resizes the array to shape s. All data is lost. - void Resize(const int *new_shape_array) { - Resize(Index(new_shape_array)); - } - - /// Resize a 1D array to length s0. - void Resize(int s0) { - assert(N == 1); - int shape[] = {s0}; - Resize(shape); - } - - /// Resize a 2D array to shape (s0,s1). - void Resize(int s0, int s1) { - int shape[N] = {s0, s1}; - for (int i = 2; i < N; ++i) { - shape[i] = 1; - } - Resize(shape); - } - - // Match Eigen2's API. - void resize(int rows, int cols) { - Resize(rows, cols); - } - - /// Resize a 3D array to shape (s0,s1,s2). - void Resize(int s0, int s1, int s2) { - assert(N == 3); - int shape[] = {s0, s1, s2}; - Resize(shape); - } - - template - void CopyFrom(const ArrayND &other) { - ResizeLike(other); - T *data = Data(); - const D *other_data = other.Data(); - for (int i = 0; i < Size(); ++i) { - data[i] = T(other_data[i]); - } - } - - void Fill(T value) { - for (int i = 0; i < Size(); ++i) { - Data()[i] = value; - } - } - - // Match Eigen's API. - void fill(T value) { - for (int i = 0; i < Size(); ++i) { - Data()[i] = value; - } - } - - /// Return a tuple containing the length of each axis. - const Index &Shape() const { - return shape_; - } - - /// Return the length of an axis. - int Shape(int axis) const { - return shape_(axis); - } - - /// Return the distance between neighboring elements along axis. - int Stride(int axis) const { - return strides_(axis); - } - - /// Return the number of elements of the array. - int Size() const { - int size = 1; - for (int i = 0; i < N; ++i) - size *= Shape(i); - return size; - } - - /// Return the total amount of memory used by the array. - int MemorySizeInBytes() const { - return sizeof(*this) + Size() * sizeof(T); - } - - /// Pointer to the first element of the array. - T *Data() { return data_; } - - /// Constant pointer to the first element of the array. - const T *Data() const { return data_; } - - /// Distance between the first element and the element at position index. - int Offset(const Index &index) const { - int offset = 0; - for (int i = 0; i < N; ++i) - offset += index(i) * Stride(i); - return offset; - } - - /// 1D specialization. - int Offset(int i0) const { - assert(N == 1); - return i0 * Stride(0); - } - - /// 2D specialization. - int Offset(int i0, int i1) const { - assert(N == 2); - return i0 * Stride(0) + i1 * Stride(1); - } - - /// 3D specialization. - int Offset(int i0, int i1, int i2) const { - assert(N == 3); - return i0 * Stride(0) + i1 * Stride(1) + i2 * Stride(2); - } - - /// Return a reference to the element at position index. - T &operator()(const Index &index) { - // TODO(pau) Boundary checking in debug mode. - return *( Data() + Offset(index) ); - } - - /// 1D specialization. - T &operator()(int i0) { - return *( Data() + Offset(i0) ); - } - - /// 2D specialization. - T &operator()(int i0, int i1) { - assert(0 <= i0 && i0 < Shape(0)); - assert(0 <= i1 && i1 < Shape(1)); - return *(Data() + Offset(i0, i1)); - } - - /// 3D specialization. - T &operator()(int i0, int i1, int i2) { - assert(0 <= i0 && i0 < Shape(0)); - assert(0 <= i1 && i1 < Shape(1)); - assert(0 <= i2 && i2 < Shape(2)); - return *(Data() + Offset(i0, i1, i2)); - } - - /// Return a constant reference to the element at position index. - const T &operator()(const Index &index) const { - return *(Data() + Offset(index)); - } - - /// 1D specialization. - const T &operator()(int i0) const { - return *(Data() + Offset(i0)); - } - - /// 2D specialization. - const T &operator()(int i0, int i1) const { - assert(0 <= i0 && i0 < Shape(0)); - assert(0 <= i1 && i1 < Shape(1)); - return *(Data() + Offset(i0, i1)); - } - - /// 3D specialization. - const T &operator()(int i0, int i1, int i2) const { - return *(Data() + Offset(i0, i1, i2)); - } - - /// True if index is inside array. - bool Contains(const Index &index) const { - for (int i = 0; i < N; ++i) - if (index(i) < 0 || index(i) >= Shape(i)) - return false; - return true; - } - - /// 1D specialization. - bool Contains(int i0) const { - return 0 <= i0 && i0 < Shape(0); - } - - /// 2D specialization. - bool Contains(int i0, int i1) const { - return 0 <= i0 && i0 < Shape(0) - && 0 <= i1 && i1 < Shape(1); - } - - /// 3D specialization. - bool Contains(int i0, int i1, int i2) const { - return 0 <= i0 && i0 < Shape(0) - && 0 <= i1 && i1 < Shape(1) - && 0 <= i2 && i2 < Shape(2); - } - - bool operator==(const ArrayND &other) const { - if (shape_ != other.shape_) return false; - if (strides_ != other.strides_) return false; - for (int i = 0; i < Size(); ++i) { - if (this->Data()[i] != other.Data()[i]) - return false; - } - return true; - } - - bool operator!=(const ArrayND &other) const { - return !(*this == other); - } - - ArrayND operator*(const ArrayND &other) const { - assert(Shape() = other.Shape()); - ArrayND res; - res.ResizeLike(*this); - for (int i = 0; i < res.Size(); ++i) { - res.Data()[i] = Data()[i] * other.Data()[i]; - } - return res; - } - - protected: - /// The number of element in each dimension. - Index shape_; - - /// How to jump to neighbors in each dimension. - Index strides_; - - /// Pointer to the first element of the array. - T *data_; - - /// Flag if this Array either own or reference the data - bool own_data_; -}; - -/// 3D array (row, column, channel). -template -class Array3D : public ArrayND { - typedef ArrayND Base; - public: - Array3D() - : Base() { - } - Array3D(int height, int width, int depth = 1) - : Base(height, width, depth) { - } - Array3D(T* data, int height, int width, int depth = 1) - : Base(data, height, width, depth) { - } - - void Resize(int height, int width, int depth = 1) { - Base::Resize(height, width, depth); - } - - int Height() const { - return Base::Shape(0); - } - int Width() const { - return Base::Shape(1); - } - int Depth() const { - return Base::Shape(2); - } - - // Match Eigen2's API so that Array3D's and Mat*'s can work together via - // template magic. - int rows() const { return Height(); } - int cols() const { return Width(); } - int depth() const { return Depth(); } - - int Get_Step() const { return Width()*Depth(); } - - /// Enable accessing with 2 indices for grayscale images. - T &operator()(int i0, int i1, int i2 = 0) { - assert(0 <= i0 && i0 < Height()); - assert(0 <= i1 && i1 < Width()); - return Base::operator()(i0, i1, i2); - } - const T &operator()(int i0, int i1, int i2 = 0) const { - assert(0 <= i0 && i0 < Height()); - assert(0 <= i1 && i1 < Width()); - return Base::operator()(i0, i1, i2); - } -}; - -typedef Array3D Array3Du; -typedef Array3D Array3Dui; -typedef Array3D Array3Di; -typedef Array3D Array3Df; -typedef Array3D Array3Ds; - -void SplitChannels(const Array3Df &input, - Array3Df *channel0, - Array3Df *channel1, - Array3Df *channel2); - -void PrintArray(const Array3Df &array); - -/** Convert a float array into a byte array by scaling values by 255* (max-min). - * where max and min are automatically detected - * (if automatic_range_detection = true) - * \note and TODO this automatic detection only works when the image contains - * at least one pixel of both bounds. - **/ -void FloatArrayToScaledByteArray(const Array3Df &float_array, - Array3Du *byte_array, - bool automatic_range_detection = false); - -//! Convert a byte array into a float array by dividing values by 255. -void ByteArrayToScaledFloatArray(const Array3Du &byte_array, - Array3Df *float_array); - -template -void MultiplyElements(const AArrayType &a, - const BArrayType &b, - CArrayType *c) { - // This function does an element-wise multiply between - // the two Arrays A and B, and stores the result in C. - // A and B must have the same dimensions. - assert(a.Shape() == b.Shape()); - c->ResizeLike(a); - - // To perform the multiplcation, a "current" index into the N-dimensions of - // the A and B matrix specifies which elements are being multiplied. - typename CArrayType::Index index; - - // The index starts at the maximum value for each dimension - const typename CArrayType::Index& cShape = c->Shape(); - for ( int i = 0; i < CArrayType::Index::SIZE; ++i ) - index(i) = cShape(i) - 1; - - // After each multiplication, the highest-dimensional index is reduced. - // if this reduces it less than zero, it resets to its maximum value - // and decrements the index of the next lower dimension. - // This ripple-action continues until the entire new array has been - // calculated, indicated by dimension zero having a negative index. - while ( index(0) >= 0 ) { - (*c)(index) = a(index) * b(index); - - int dimension = CArrayType::Index::SIZE - 1; - index(dimension) = index(dimension) - 1; - while ( dimension > 0 && index(dimension) < 0 ) { - index(dimension) = cShape(dimension) - 1; - index(dimension - 1) = index(dimension - 1) - 1; - --dimension; - } - } -} - -template -void MultiplyElements(const ArrayND &a, - const ArrayND &b, - ArrayND *c) { - // Specialization for N==3 - c->ResizeLike(a); - assert(a.Shape(0) == b.Shape(0)); - assert(a.Shape(1) == b.Shape(1)); - assert(a.Shape(2) == b.Shape(2)); - for (int i = 0; i < a.Shape(0); ++i) { - for (int j = 0; j < a.Shape(1); ++j) { - for (int k = 0; k < a.Shape(2); ++k) { - (*c)(i, j, k) = TC(a(i, j, k) * b(i, j, k)); - } - } - } -} - -template -void MultiplyElements(const Array3D &a, - const Array3D &b, - Array3D *c) { - // Specialization for N==3 - c->ResizeLike(a); - assert(a.Shape(0) == b.Shape(0)); - assert(a.Shape(1) == b.Shape(1)); - assert(a.Shape(2) == b.Shape(2)); - for (int i = 0; i < a.Shape(0); ++i) { - for (int j = 0; j < a.Shape(1); ++j) { - for (int k = 0; k < a.Shape(2); ++k) { - (*c)(i, j, k) = TC(a(i, j, k) * b(i, j, k)); - } - } - } -} - -} // namespace libmv - -#endif // LIBMV_IMAGE_ARRAY_ND_H diff --git a/extern/libmv/libmv/image/array_nd_test.cc b/extern/libmv/libmv/image/array_nd_test.cc deleted file mode 100644 index 313f21b60e9..00000000000 --- a/extern/libmv/libmv/image/array_nd_test.cc +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/image/array_nd.h" -#include "testing/testing.h" - -using libmv::ArrayND; -using libmv::Array3D; -using libmv::Array3Df; - -namespace { - -TEST(ArrayND, EmptyConstructor) { - ArrayND a; - - EXPECT_EQ(0, a.Shape(0)); - EXPECT_EQ(0, a.Shape(1)); -} - -TEST(ArrayND, IndexConstructor) { - int s[] = {1, 2, 3}; - ArrayND::Index shape(s); - ArrayND a(shape); - - EXPECT_EQ(1, a.Shape(0)); - EXPECT_EQ(2, a.Shape(1)); - EXPECT_EQ(3, a.Shape(2)); -} - -TEST(ArrayND, PointerConstructor) { - int s[] = {1, 2, 3}; - ArrayND a(s); - - EXPECT_EQ(1, a.Shape(0)); - EXPECT_EQ(2, a.Shape(1)); - EXPECT_EQ(3, a.Shape(2)); -} - -TEST(ArrayND, CopyConstructor) { - int s[] = {1, 2, 3}; - ArrayND a(s); - a(0, 1, 1) = 3; - a(0, 1, 2) = 3; - ArrayND b(a); - EXPECT_EQ(1, b.Shape(0)); - EXPECT_EQ(2, b.Shape(1)); - EXPECT_EQ(3, b.Shape(2)); - EXPECT_EQ(3, b(0, 1, 1)); - b(0, 1, 2) = 2; - EXPECT_EQ(3, a(0, 1, 2)); -} - -TEST(ArrayND, Assignation) { - int s[] = {1, 2, 3}; - ArrayND a(s); - a(0, 1, 1) = 3; - a(0, 1, 2) = 3; - ArrayND b; - b = a; - EXPECT_EQ(1, b.Shape(0)); - EXPECT_EQ(2, b.Shape(1)); - EXPECT_EQ(3, b.Shape(2)); - EXPECT_EQ(3, b(0, 1, 1)); - b(0, 1, 2) = 2; - EXPECT_EQ(3, a(0, 1, 2)); -} - -TEST(ArrayND, Fill) { - int s[] = {2, 2}; - ArrayND a(s); - a.Fill(42); - EXPECT_EQ(42, a(0, 0)); - EXPECT_EQ(42, a(0, 1)); - EXPECT_EQ(42, a(1, 0)); - EXPECT_EQ(42, a(1, 1)); -} - -TEST(ArrayND, Size) { - int s[] = {1, 2, 3}; - ArrayND::Index shape(s); - ArrayND a(shape); - - int l[] = {0, 1, 2}; - ArrayND::Index last(l); - - EXPECT_EQ(a.Size(), a.Offset(last)+1); - EXPECT_TRUE(a.Contains(last)); - EXPECT_FALSE(a.Contains(shape)); -} - -TEST(ArrayND, MemorySizeInBytes) { - int s[] = {2, 3}; - ArrayND::Index shape(s); - ArrayND a(shape); - - int size = 24 + sizeof(a); - EXPECT_EQ(size, a.MemorySizeInBytes()); -} - -TEST(ArrayND, Parenthesis) { - typedef ArrayND::Index Index; - - int s[] = {3, 3}; - ArrayND a(s); - - *(a.Data()+0) = 0; - *(a.Data()+5) = 5; - - int i1[] = {0, 0}; - EXPECT_EQ(0, a(Index(i1))); - int i2[] = {1, 2}; - EXPECT_EQ(5, a(Index(i2))); -} - -TEST(ArrayND, 1DConstructor) { - ArrayND a(3); - - EXPECT_EQ(3, a.Shape(0)); -} - -TEST(ArrayND, 2DConstructor) { - ArrayND a(1, 2); - - EXPECT_EQ(1, a.Shape(0)); - EXPECT_EQ(2, a.Shape(1)); -} - -TEST(ArrayND, 3DConstructor) { - ArrayND a(1, 2, 3); - - EXPECT_EQ(1, a.Shape(0)); - EXPECT_EQ(2, a.Shape(1)); - EXPECT_EQ(3, a.Shape(2)); -} - -TEST(ArrayND, 1DAccessor) { - ArrayND a(3); - a(0) = 1; - a(1) = 2; - - EXPECT_EQ(1, a(0)); - EXPECT_EQ(2, a(1)); - EXPECT_EQ(1, *(a.Data())); - EXPECT_EQ(2, *(a.Data() + a.Stride(0))); -} - -TEST(ArrayND, 2DAccessor) { - ArrayND a(3, 3); - a(0, 0) = 1; - a(1, 1) = 2; - - EXPECT_EQ(1, a(0, 0)); - EXPECT_EQ(2, a(1, 1)); - EXPECT_EQ(1, *(a.Data())); - EXPECT_EQ(2, *(a.Data() + a.Stride(0) + a.Stride(1))); -} - -TEST(ArrayND, 3DAccessor) { - ArrayND a(3, 3, 3); - a(0, 0, 0) = 1; - a(1, 1, 1) = 2; - - EXPECT_EQ(1, a(0, 0, 0)); - EXPECT_EQ(2, a(1, 1, 1)); - EXPECT_EQ(1, *(a.Data())); - EXPECT_EQ(2, *(a.Data() + a.Stride(0) + a.Stride(1) + a.Stride(2))); -} - -TEST(ArrayND, CopyFrom) { - ArrayND a(2, 2, 1); - a(0, 0, 0) = 1; - a(0, 1, 0) = 2; - a(1, 0, 0) = 3; - a(1, 1, 0) = 4; - ArrayND b; - b.CopyFrom(a); - EXPECT_FLOAT_EQ(1.f, b(0, 0, 0)); - EXPECT_FLOAT_EQ(2.f, b(0, 1, 0)); - EXPECT_FLOAT_EQ(3.f, b(1, 0, 0)); - EXPECT_FLOAT_EQ(4.f, b(1, 1, 0)); -} - -TEST(ArrayND, MultiplyElements) { - ArrayND a(2, 2, 1); - a(0, 0, 0) = 1; - a(0, 1, 0) = 2; - a(1, 0, 0) = 3; - a(1, 1, 0) = 4; - ArrayND b(2, 2, 1); - b(0, 0, 0) = 6; - b(0, 1, 0) = 5; - b(1, 0, 0) = 4; - b(1, 1, 0) = 3; - ArrayND c; - MultiplyElements(a, b, &c); - EXPECT_FLOAT_EQ(6, c(0, 0, 0)); - EXPECT_FLOAT_EQ(10, c(0, 1, 0)); - EXPECT_FLOAT_EQ(12, c(1, 0, 0)); - EXPECT_FLOAT_EQ(12, c(1, 1, 0)); -} - -TEST(ArrayND, IsEqualOperator) { - ArrayND a(2, 2, 1); - a(0, 0, 0) = 1; - a(0, 1, 0) = 2; - a(1, 0, 0) = 3; - a(1, 1, 0) = 4; - ArrayND b(2, 2, 1); - b(0, 0, 0) = 1; - b(0, 1, 0) = 2; - b(1, 0, 0) = 3; - b(1, 1, 0) = 4; - EXPECT_TRUE(a == b); - EXPECT_FALSE(a != b); - b(1, 1, 0) = 5; - EXPECT_TRUE(a != b); - EXPECT_FALSE(a == b); -} - -TEST(Array3D, Sizes) { - Array3D array; - EXPECT_EQ(array.Height(), 0); - EXPECT_EQ(array.Width(), 0); - EXPECT_EQ(array.Depth(), 0); - EXPECT_EQ(array.Shape(0), 0); -} - -TEST(Array3D, CopyConstructor) { - Array3D array(10, 10); - array(0, 0) = 1; - array(0, 1) = 1; - Array3D copy(array); - EXPECT_EQ(copy.Height(), 10); - EXPECT_EQ(copy.Width(), 10); - EXPECT_EQ(copy.Depth(), 1); - EXPECT_EQ(copy(0, 0), 1); - copy(0, 1) = 2; - EXPECT_EQ(array(0, 1), 1); -} - -TEST(Array3D, Assignation) { - Array3D array(10, 10); - array(0, 0) = 1; - array(0, 1) = 1; - Array3D copy; - copy = array; - EXPECT_EQ(copy.Height(), 10); - EXPECT_EQ(copy.Width(), 10); - EXPECT_EQ(copy.Depth(), 1); - EXPECT_EQ(copy(0, 0), 1); - copy(0, 1) = 2; - EXPECT_EQ(array(0, 1), 1); -} - -TEST(Array3D, Parenthesis) { - Array3D array(1, 2, 3); - array(0, 1, 0) = 3; - EXPECT_EQ(array(0, 1), 3); -} - -TEST(Array3Df, SplitChannels) { - Array3Df array(1, 2, 3); - array(0, 0, 0) = 1; - array(0, 1, 0) = 1; - array(0, 0, 1) = 2; - array(0, 1, 1) = 2; - array(0, 0, 2) = 3; - array(0, 1, 2) = 3; - Array3Df c0, c1, c2; - SplitChannels(array, &c0, &c1, &c2); - for (int row = 0; row < 1; ++row) { - for (int column = 0; column < 2; ++column) { - EXPECT_EQ(array(row, column, 0), c0(row, column)); - EXPECT_EQ(array(row, column, 1), c1(row, column)); - EXPECT_EQ(array(row, column, 2), c2(row, column)); - } - } -} - -TEST(ArrayND, MultiplyElementsGeneric) { - ArrayND A; - ArrayND B; - ArrayND C; - int shape[] = {1, 3, 5, 7, 1}; - A.Resize(shape); - B.Resize(shape); - - A.Fill(1.1); - B.Fill(2); - MultiplyElements(A, B, &C); - - ArrayND::Index cIndex; - for (int d0 = 0; d0 < shape[0]; ++d0) - for (int d1 = 0; d1 < shape[1]; ++d1) - for (int d2 = 0; d2 < shape[2]; ++d2) - for (int d3 = 0; d3 < shape[3]; ++d3) - for (int d4 = 0; d4 < shape[4]; ++d4) { - cIndex(0) = d0; - cIndex(1) = d1; - cIndex(2) = d2; - cIndex(3) = d3; - cIndex(4) = d4; - EXPECT_EQ(2.2, C(cIndex)); - } -} - -} // namespace diff --git a/extern/libmv/libmv/image/convolve.cc b/extern/libmv/libmv/image/convolve.cc deleted file mode 100644 index 464043581d2..00000000000 --- a/extern/libmv/libmv/image/convolve.cc +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/image/convolve.h" - -#include - -#include "libmv/image/image.h" - -namespace libmv { - -// Compute a Gaussian kernel and derivative, such that you can take the -// derivative of an image by convolving with the kernel horizontally then the -// derivative vertically to get (eg) the y derivative. -void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) { - assert(sigma >= 0.0); - - // 0.004 implies a 3 pixel kernel with 1 pixel sigma. - const float truncation_factor = 0.004f; - - // Calculate the kernel size based on sigma such that it is odd. - float precisehalfwidth = GaussianInversePositive(truncation_factor, sigma); - int width = lround(2*precisehalfwidth); - if (width % 2 == 0) { - width++; - } - // Calculate the gaussian kernel and its derivative. - kernel->resize(width); - derivative->resize(width); - kernel->setZero(); - derivative->setZero(); - int halfwidth = width / 2; - for (int i = -halfwidth; i <= halfwidth; ++i) { - (*kernel)(i + halfwidth) = Gaussian(i, sigma); - (*derivative)(i + halfwidth) = GaussianDerivative(i, sigma); - } - // Since images should not get brighter or darker, normalize. - NormalizeL1(kernel); - - // Normalize the derivative differently. See - // www.cs.duke.edu/courses/spring03/cps296.1/handouts/Image%20Processing.pdf - double factor = 0.; - for (int i = -halfwidth; i <= halfwidth; ++i) { - factor -= i*(*derivative)(i+halfwidth); - } - *derivative /= factor; -} - -template -void FastConvolve(const Vec &kernel, int width, int height, - const float* src, int src_stride, int src_line_stride, - float* dst, int dst_stride) { - double coefficients[2 * size + 1]; - for (int k = 0; k < 2 * size + 1; ++k) { - coefficients[k] = kernel(2 * size - k); - } - // Fast path: if the kernel has a certain size, use the constant sized loops. - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - double sum = 0; - for (int k = -size; k <= size; ++k) { - if (vertical) { - if (y + k >= 0 && y + k < height) { - sum += src[k * src_line_stride] * coefficients[k + size]; - } - } else { - if (x + k >= 0 && x + k < width) { - sum += src[k * src_stride] * coefficients[k + size]; - } - } - } - dst[0] = static_cast(sum); - src += src_stride; - dst += dst_stride; - } - } -} - -template -void Convolve(const Array3Df &in, - const Vec &kernel, - Array3Df *out_pointer, - int plane) { - int width = in.Width(); - int height = in.Height(); - Array3Df &out = *out_pointer; - if (plane == -1) { - out.ResizeLike(in); - plane = 0; - } - - assert(kernel.size() % 2 == 1); - assert(&in != out_pointer); - - int src_line_stride = in.Stride(0); - int src_stride = in.Stride(1); - int dst_stride = out.Stride(1); - const float* src = in.Data(); - float* dst = out.Data() + plane; - - // Use a dispatch table to make most convolutions used in practice use the - // fast path. - int half_width = kernel.size() / 2; - switch (half_width) { -#define static_convolution(size) case size: \ - FastConvolve(kernel, width, height, src, src_stride, \ - src_line_stride, dst, dst_stride); break; - static_convolution(1) - static_convolution(2) - static_convolution(3) - static_convolution(4) - static_convolution(5) - static_convolution(6) - static_convolution(7) -#undef static_convolution - default: - int dynamic_size = kernel.size() / 2; - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - double sum = 0; - // Slow path: this loop cannot be unrolled. - for (int k = -dynamic_size; k <= dynamic_size; ++k) { - if (vertical) { - if (y + k >= 0 && y + k < height) { - sum += src[k * src_line_stride] * - kernel(2 * dynamic_size - (k + dynamic_size)); - } - } else { - if (x + k >= 0 && x + k < width) { - sum += src[k * src_stride] * - kernel(2 * dynamic_size - (k + dynamic_size)); - } - } - } - dst[0] = static_cast(sum); - src += src_stride; - dst += dst_stride; - } - } - } -} - -void ConvolveHorizontal(const Array3Df &in, - const Vec &kernel, - Array3Df *out_pointer, - int plane) { - Convolve(in, kernel, out_pointer, plane); -} - -void ConvolveVertical(const Array3Df &in, - const Vec &kernel, - Array3Df *out_pointer, - int plane) { - Convolve(in, kernel, out_pointer, plane); -} - -void ConvolveGaussian(const Array3Df &in, - double sigma, - Array3Df *out_pointer) { - Vec kernel, derivative; - ComputeGaussianKernel(sigma, &kernel, &derivative); - - Array3Df tmp; - ConvolveVertical(in, kernel, &tmp); - ConvolveHorizontal(tmp, kernel, out_pointer); -} - -void ImageDerivatives(const Array3Df &in, - double sigma, - Array3Df *gradient_x, - Array3Df *gradient_y) { - Vec kernel, derivative; - ComputeGaussianKernel(sigma, &kernel, &derivative); - Array3Df tmp; - - // Compute first derivative in x. - ConvolveVertical(in, kernel, &tmp); - ConvolveHorizontal(tmp, derivative, gradient_x); - - // Compute first derivative in y. - ConvolveHorizontal(in, kernel, &tmp); - ConvolveVertical(tmp, derivative, gradient_y); -} - -void BlurredImageAndDerivatives(const Array3Df &in, - double sigma, - Array3Df *blurred_image, - Array3Df *gradient_x, - Array3Df *gradient_y) { - Vec kernel, derivative; - ComputeGaussianKernel(sigma, &kernel, &derivative); - Array3Df tmp; - - // Compute convolved image. - ConvolveVertical(in, kernel, &tmp); - ConvolveHorizontal(tmp, kernel, blurred_image); - - // Compute first derivative in x (reusing vertical convolution above). - ConvolveHorizontal(tmp, derivative, gradient_x); - - // Compute first derivative in y. - ConvolveHorizontal(in, kernel, &tmp); - ConvolveVertical(tmp, derivative, gradient_y); -} - -// Compute the gaussian blur of an image and the derivatives of the blurred -// image, and store the results in three channels. Since the blurred value and -// gradients are closer in memory, this leads to better performance if all -// three values are needed at the same time. -void BlurredImageAndDerivativesChannels(const Array3Df &in, - double sigma, - Array3Df *blurred_and_gradxy) { - assert(in.Depth() == 1); - - Vec kernel, derivative; - ComputeGaussianKernel(sigma, &kernel, &derivative); - - // Compute convolved image. - Array3Df tmp; - ConvolveVertical(in, kernel, &tmp); - blurred_and_gradxy->Resize(in.Height(), in.Width(), 3); - ConvolveHorizontal(tmp, kernel, blurred_and_gradxy, 0); - - // Compute first derivative in x. - ConvolveHorizontal(tmp, derivative, blurred_and_gradxy, 1); - - // Compute first derivative in y. - ConvolveHorizontal(in, kernel, &tmp); - ConvolveVertical(tmp, derivative, blurred_and_gradxy, 2); -} - -void BoxFilterHorizontal(const Array3Df &in, - int window_size, - Array3Df *out_pointer) { - Array3Df &out = *out_pointer; - out.ResizeLike(in); - int half_width = (window_size - 1) / 2; - - for (int k = 0; k < in.Depth(); ++k) { - for (int i = 0; i < in.Height(); ++i) { - float sum = 0; - // Init sum. - for (int j = 0; j < half_width; ++j) { - sum += in(i, j, k); - } - // Fill left border. - for (int j = 0; j < half_width + 1; ++j) { - sum += in(i, j + half_width, k); - out(i, j, k) = sum; - } - // Fill interior. - for (int j = half_width + 1; j < in.Width()-half_width; ++j) { - sum -= in(i, j - half_width - 1, k); - sum += in(i, j + half_width, k); - out(i, j, k) = sum; - } - // Fill right border. - for (int j = in.Width() - half_width; j < in.Width(); ++j) { - sum -= in(i, j - half_width - 1, k); - out(i, j, k) = sum; - } - } - } -} - -void BoxFilterVertical(const Array3Df &in, - int window_size, - Array3Df *out_pointer) { - Array3Df &out = *out_pointer; - out.ResizeLike(in); - int half_width = (window_size - 1) / 2; - - for (int k = 0; k < in.Depth(); ++k) { - for (int j = 0; j < in.Width(); ++j) { - float sum = 0; - // Init sum. - for (int i = 0; i < half_width; ++i) { - sum += in(i, j, k); - } - // Fill left border. - for (int i = 0; i < half_width + 1; ++i) { - sum += in(i + half_width, j, k); - out(i, j, k) = sum; - } - // Fill interior. - for (int i = half_width + 1; i < in.Height()-half_width; ++i) { - sum -= in(i - half_width - 1, j, k); - sum += in(i + half_width, j, k); - out(i, j, k) = sum; - } - // Fill right border. - for (int i = in.Height() - half_width; i < in.Height(); ++i) { - sum -= in(i - half_width - 1, j, k); - out(i, j, k) = sum; - } - } - } -} - -void BoxFilter(const Array3Df &in, - int box_width, - Array3Df *out) { - Array3Df tmp; - BoxFilterHorizontal(in, box_width, &tmp); - BoxFilterVertical(tmp, box_width, out); -} - -void LaplaceFilter(unsigned char* src, - unsigned char* dst, - int width, - int height, - int strength) { - for (int y = 1; y < height-1; y++) - for (int x = 1; x < width-1; x++) { - const unsigned char* s = &src[y*width+x]; - int l = 128 + - s[-width-1] + s[-width] + s[-width+1] + - s[1] - 8*s[0] + s[1] + - s[ width-1] + s[ width] + s[ width+1]; - int d = ((256-strength)*s[0] + strength*l) / 256; - if (d < 0) d=0; - if (d > 255) d=255; - dst[y*width+x] = d; - } -} - -} // namespace libmv diff --git a/extern/libmv/libmv/image/convolve.h b/extern/libmv/libmv/image/convolve.h deleted file mode 100644 index d3b6da9794b..00000000000 --- a/extern/libmv/libmv/image/convolve.h +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2007, 2008, 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_IMAGE_CONVOLVE_H_ -#define LIBMV_IMAGE_CONVOLVE_H_ - -#include "libmv/image/image.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { - -// TODO(keir): Find a better place for these functions. gaussian.h in numeric? - -// Zero mean Gaussian. -inline double Gaussian(double x, double sigma) { - return 1/sqrt(2*M_PI*sigma*sigma) * exp(-(x*x/2/sigma/sigma)); -} -// 2D gaussian (zero mean) -// (9) in http://mathworld.wolfram.com/GaussianFunction.html -inline double Gaussian2D(double x, double y, double sigma) { - return 1.0/(2.0*M_PI*sigma*sigma) * exp( -(x*x+y*y)/(2.0*sigma*sigma)); -} -inline double GaussianDerivative(double x, double sigma) { - return -x / sigma / sigma * Gaussian(x, sigma); -} -// Solve the inverse of the Gaussian for positive x. -inline double GaussianInversePositive(double y, double sigma) { - return sqrt(-2 * sigma * sigma * log(y * sigma * sqrt(2*M_PI))); -} - -void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative); -void ConvolveHorizontal(const FloatImage &in, - const Vec &kernel, - FloatImage *out_pointer, - int plane = -1); -void ConvolveVertical(const FloatImage &in, - const Vec &kernel, - FloatImage *out_pointer, - int plane = -1); -void ConvolveGaussian(const FloatImage &in, - double sigma, - FloatImage *out_pointer); - -void ImageDerivatives(const FloatImage &in, - double sigma, - FloatImage *gradient_x, - FloatImage *gradient_y); - -void BlurredImageAndDerivatives(const FloatImage &in, - double sigma, - FloatImage *blurred_image, - FloatImage *gradient_x, - FloatImage *gradient_y); - -// Blur and take the gradients of an image, storing the results inside the -// three channels of blurred_and_gradxy. -void BlurredImageAndDerivativesChannels(const FloatImage &in, - double sigma, - FloatImage *blurred_and_gradxy); - -void BoxFilterHorizontal(const FloatImage &in, - int window_size, - FloatImage *out_pointer); - -void BoxFilterVertical(const FloatImage &in, - int window_size, - FloatImage *out_pointer); - -void BoxFilter(const FloatImage &in, - int box_width, - FloatImage *out); - -/*! - Convolve \a src into \a dst with the discrete laplacian operator. - - \a src and \a dst should be \a width x \a height images. - \a strength is an interpolation coefficient (0-256) between original image and the laplacian. - - \note Make sure the search region is filtered with the same strength as the pattern. -*/ -void LaplaceFilter(unsigned char* src, - unsigned char* dst, - int width, - int height, - int strength); - -} // namespace libmv - -#endif // LIBMV_IMAGE_CONVOLVE_H_ - diff --git a/extern/libmv/libmv/image/convolve_test.cc b/extern/libmv/libmv/image/convolve_test.cc deleted file mode 100644 index 0cdef8e1e72..00000000000 --- a/extern/libmv/libmv/image/convolve_test.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include - -#include "libmv/image/convolve.h" -#include "libmv/image/image.h" -#include "libmv/numeric/numeric.h" -#include "testing/testing.h" - -using namespace libmv; - -namespace { - -TEST(Convolve, ComputeGaussianKernel) { - Vec kernel, derivative; - ComputeGaussianKernel(1, &kernel, &derivative); - EXPECT_EQ(7, kernel.size()); - // TODO(keir): Put in a more thorough test here! -} - -TEST(Convolve, ConvolveGaussian) { - FloatImage im(10, 10); - im.Fill(1); - FloatImage blured; - ConvolveGaussian(im, 3, &blured); - EXPECT_NEAR(im(5, 5), 1, 1e-7); -} - -TEST(Convolve, BoxFilterHorizontal) { - FloatImage im(10, 10), convolved, filtered; - im.Fill(1); - BoxFilterHorizontal(im, 3, &filtered); - Vec kernel(3); - kernel.setConstant(1.); - ConvolveHorizontal(im, kernel, &convolved); - EXPECT_EQ(filtered(5, 5), 3); - EXPECT_TRUE(filtered == convolved); -} - -TEST(Convolve, BoxFilter) { - FloatImage image(5, 5), filtered; - // A single 1.0 inside a 5x5 image should expand to a 3x3 square. - image.Fill(0); - image(2, 2) = 1.0; - BoxFilter(image, 3, &filtered); - for (int j = 0; j < 5; j++) { - for (int i = 0; i < 5; i++) { - if (i == 0 || i == 4 || j == 0 || j == 4) { - EXPECT_EQ(0.0, filtered(j, i)); - } else { - EXPECT_EQ(1.0, filtered(j, i)); - } - } - } -} - -TEST(Convolve, BlurredImageAndDerivativesChannelsFlat) { - FloatImage im(10, 10), blurred_and_derivatives; - im.Fill(1); - BlurredImageAndDerivativesChannels(im, 1.0, &blurred_and_derivatives); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 1.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 0.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 0.0, 1e-7); -} - -TEST(Convolve, BlurredImageAndDerivativesChannelsHorizontalSlope) { - FloatImage image(10, 10), blurred_and_derivatives; - for (int j = 0; j < 10; ++j) { - for (int i = 0; i < 10; ++i) { - image(j, i) = 2*i; - } - } - BlurredImageAndDerivativesChannels(image, 0.9, &blurred_and_derivatives); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 10.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 2.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 0.0, 1e-7); -} - -TEST(Convolve, BlurredImageAndDerivativesChannelsVerticalSlope) { - FloatImage image(10, 10), blurred_and_derivatives; - for (int j = 0; j < 10; ++j) { - for (int i = 0; i < 10; ++i) { - image(j, i) = 2*j; - } - } - BlurredImageAndDerivativesChannels(image, 0.9, &blurred_and_derivatives); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 10.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 0.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 2.0, 1e-7); -} - -} // namespace diff --git a/extern/libmv/libmv/image/correlation.h b/extern/libmv/libmv/image/correlation.h deleted file mode 100644 index c354f7e891e..00000000000 --- a/extern/libmv/libmv/image/correlation.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2012 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_IMAGE_CORRELATION_H -#define LIBMV_IMAGE_CORRELATION_H - -#include "libmv/logging/logging.h" -#include "libmv/image/image.h" - -namespace libmv { - -inline double PearsonProductMomentCorrelation( - const FloatImage &image_and_gradient1_sampled, - const FloatImage &image_and_gradient2_sampled) { - assert(image_and_gradient1_sampled.Width() == - image_and_gradient2_sampled.Width()); - assert(image_and_gradient1_sampled.Height() == - image_and_gradient2_sampled.Height()); - - const int width = image_and_gradient1_sampled.Width(), - height = image_and_gradient1_sampled.Height(); - double sX = 0, sY = 0, sXX = 0, sYY = 0, sXY = 0; - - for (int r = 0; r < height; ++r) { - for (int c = 0; c < width; ++c) { - double x = image_and_gradient1_sampled(r, c, 0); - double y = image_and_gradient2_sampled(r, c, 0); - sX += x; - sY += y; - sXX += x * x; - sYY += y * y; - sXY += x * y; - } - } - - // Normalize. - double N = width * height; - sX /= N; - sY /= N; - sXX /= N; - sYY /= N; - sXY /= N; - - double var_x = sXX - sX * sX; - double var_y = sYY - sY * sY; - double covariance_xy = sXY - sX * sY; - - double correlation = covariance_xy / sqrt(var_x * var_y); - LG << "Covariance xy: " << covariance_xy - << ", var 1: " << var_x << ", var 2: " << var_y - << ", correlation: " << correlation; - return correlation; -} - -} // namespace libmv - -#endif // LIBMV_IMAGE_IMAGE_CORRELATION_H diff --git a/extern/libmv/libmv/image/image.h b/extern/libmv/libmv/image/image.h deleted file mode 100644 index e0f200a4c93..00000000000 --- a/extern/libmv/libmv/image/image.h +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_IMAGE_IMAGE_H -#define LIBMV_IMAGE_IMAGE_H - -#include - -#include "libmv/image/array_nd.h" - -namespace libmv { - -typedef Array3Du ByteImage; // For backwards compatibility. -typedef Array3Df FloatImage; - -// Type added only to manage special 2D array for feature detection -typedef Array3Di IntImage; -typedef Array3Ds ShortImage; - -// An image class that is a thin wrapper around Array3D's of various types. -// TODO(keir): Decide if we should add reference counting semantics... Maybe it -// is the best solution after all. -class Image { - public: - - // Create an image from an array. The image takes ownership of the array. - Image(Array3Du *array) : array_type_(BYTE), array_(array) {} - Image(Array3Df *array) : array_type_(FLOAT), array_(array) {} - - Image(const Image &img): array_type_(NONE), array_(NULL) { - *this = img; - } - - // Underlying data type. - enum DataType { - NONE, - BYTE, - FLOAT, - INT, - SHORT, - }; - - // Size in bytes that the image takes in memory. - int MemorySizeInBytes() { - int size; - switch (array_type_) { - case BYTE: - size = reinterpret_cast(array_)->MemorySizeInBytes(); - break; - case FLOAT: - size = reinterpret_cast(array_)->MemorySizeInBytes(); - break; - case INT: - size = reinterpret_cast(array_)->MemorySizeInBytes(); - break; - case SHORT: - size = reinterpret_cast(array_)->MemorySizeInBytes(); - break; - default : - size = 0; - assert(0); - } - size += sizeof(*this); - return size; - } - - ~Image() { - switch (array_type_) { - case BYTE: - delete reinterpret_cast(array_); - - break; - case FLOAT: - delete reinterpret_cast(array_); - - break; - case INT: - delete reinterpret_cast(array_); - - break; - case SHORT: - delete reinterpret_cast(array_); - - break; - default: - assert(0); - } - } - - Image& operator= (const Image& f) { - if (this != &f) { - array_type_ = f.array_type_; - switch (array_type_) { - case BYTE: - delete reinterpret_cast(array_); - array_ = new Array3Du(*(Array3Du *)f.array_); - break; - case FLOAT: - delete reinterpret_cast(array_); - array_ = new Array3Df(*(Array3Df *)f.array_); - break; - case INT: - delete reinterpret_cast(array_); - array_ = new Array3Di(*(Array3Di *)f.array_); - break; - case SHORT: - delete reinterpret_cast(array_); - array_ = new Array3Ds(*(Array3Ds *)f.array_); - break; - default: - assert(0); - } - } - return *this; - } - - Array3Du *AsArray3Du() const { - if (array_type_ == BYTE) { - return reinterpret_cast(array_); - } - return NULL; - } - - Array3Df *AsArray3Df() const { - if (array_type_ == FLOAT) { - return reinterpret_cast(array_); - } - return NULL; - } - - private: - DataType array_type_; - BaseArray *array_; -}; - -} // namespace libmv - -#endif // LIBMV_IMAGE_IMAGE_IMAGE_H diff --git a/extern/libmv/libmv/image/image_converter.h b/extern/libmv/libmv/image/image_converter.h deleted file mode 100644 index b3a3fa2bf8c..00000000000 --- a/extern/libmv/libmv/image/image_converter.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_IMAGE_IMAGE_CONVERTER_H -#define LIBMV_IMAGE_IMAGE_CONVERTER_H - -#include "libmv/image/array_nd.h" - -namespace libmv { - -// The factor comes from http://www.easyrgb.com/ -// RGB to XYZ : Y is the luminance channel -// var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722 -template -inline T RGB2GRAY(const T r, const T g, const T b) { - return static_cast(r * 0.2126 + g * 0.7152 + b * 0.0722); -} - -/* -// Specialization for the uchar type. (that do not want to work...) -template<> -inline unsigned char RGB2GRAY(const unsigned char r, - const unsigned char g, - const unsigned char b) { - return (unsigned char)(r * 0.2126 + g * 0.7152 + b * 0.0722 +0.5); -}*/ - -template -void Rgb2Gray(const ImageIn &imaIn, ImageOut *imaOut) { - // It is all fine to cnvert RGBA image here as well, - // all the additional channels will be nicely ignored. - assert(imaIn.Depth() >= 3); - - imaOut->Resize(imaIn.Height(), imaIn.Width(), 1); - // Convert each RGB pixel into Gray value (luminance) - - for (int j = 0; j < imaIn.Height(); ++j) { - for (int i = 0; i < imaIn.Width(); ++i) { - (*imaOut)(j, i) = RGB2GRAY(imaIn(j, i, 0) , imaIn(j, i, 1), imaIn(j, i, 2)); - } - } -} - -// Convert given float image to an unsigned char array of pixels. -template -unsigned char *FloatImageToUCharArray(const Image &image) { - unsigned char *buffer = - new unsigned char[image.Width() * image.Height() * image.Depth()]; - - for (int y = 0; y < image.Height(); y++) { - for (int x = 0; x < image.Width(); x++) { - for (int d = 0; d < image.Depth(); d++) { - int index = (y * image.Width() + x) * image.Depth() + d; - buffer[index] = 255.0 * image(y, x, d); - } - } - } - - return buffer; -} - -} // namespace libmv - -#endif // LIBMV_IMAGE_IMAGE_CONVERTER_H diff --git a/extern/libmv/libmv/image/image_drawing.h b/extern/libmv/libmv/image/image_drawing.h deleted file mode 100644 index f50e48b75a3..00000000000 --- a/extern/libmv/libmv/image/image_drawing.h +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -// Generic Image Processing Algorithm (GIPA) -// Use an ImageModel class that must implement the following : -// -// ::Contains(int y, int x) <= Tell if a point is inside or not the image -// ::operator(int y,int x) <= Modification accessor over the pixel (y,x) -// ::Width() -// ::Height() - -#ifndef LIBMV_IMAGE_IMAGE_DRAWING_H -#define LIBMV_IMAGE_IMAGE_DRAWING_H - -namespace libmv { - -/// Put the pixel in the image to the given color only if the point (xc,yc) -/// is inside the image. -template -inline void safePutPixel(int yc, int xc, const Color & col, Image *pim) { - if (!pim) - return; - if (pim->Contains(yc, xc)) { - (*pim)(yc, xc) = col; - } -} -/// Put the pixel in the image to the given color only if the point (xc,yc) -/// is inside the image. This function support multi-channel color -/// \note The color pointer col must have size as the image depth -template -inline void safePutPixel(int yc, int xc, const Color *col, Image *pim) { - if (!pim) - return; - if (pim->Contains(yc, xc)) { - for (int i = 0; i < pim->Depth(); ++i) - (*pim)(yc, xc, i) = *(col + i); - } -} - -// Bresenham approach to draw ellipse. -// http://raphaello.univ-fcomte.fr/ig/algorithme/ExemplesGLUt/BresenhamEllipse.htm -// Add the rotation of the ellipse. -// As the algo. use symmetry we must use 4 rotations. -template -void DrawEllipse(int xc, int yc, int radiusA, int radiusB, - const Color &col, Image *pim, double angle = 0.0) { - int a = radiusA; - int b = radiusB; - - // Counter Clockwise rotation matrix. - double matXY[4] = { cos(angle), sin(angle), - -sin(angle), cos(angle)}; - int x, y; - double d1, d2; - x = 0; - y = b; - d1 = b*b - a*a*b + a*a/4; - - float rotX = (matXY[0] * x + matXY[1] * y); - float rotY = (matXY[2] * x + matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - rotX = (matXY[0] * x - matXY[1] * y); - rotY = (matXY[2] * x - matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - rotX = (-matXY[0] * x - matXY[1] * y); - rotY = (-matXY[2] * x - matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - rotX = (-matXY[0] * x + matXY[1] * y); - rotY = (-matXY[2] * x + matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - - while (a*a*(y-.5) > b*b*(x+1)) { - if (d1 < 0) { - d1 += b*b*(2*x+3); - ++x; - } else { - d1 += b*b*(2*x+3) + a*a*(-2*y+2); - ++x; - --y; - } - rotX = (matXY[0] * x + matXY[1] * y); - rotY = (matXY[2] * x + matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - rotX = (matXY[0] * x - matXY[1] * y); - rotY = (matXY[2] * x - matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - rotX = (-matXY[0] * x - matXY[1] * y); - rotY = (-matXY[2] * x - matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - rotX = (-matXY[0] * x + matXY[1] * y); - rotY = (-matXY[2] * x + matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - } - d2 = b*b*(x+.5)*(x+.5) + a*a*(y-1)*(y-1) - a*a*b*b; - while (y > 0) { - if (d2 < 0) { - d2 += b*b*(2*x+2) + a*a*(-2*y+3); - --y; - ++x; - } else { - d2 += a*a*(-2*y+3); - --y; - } - rotX = (matXY[0] * x + matXY[1] * y); - rotY = (matXY[2] * x + matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - rotX = (matXY[0] * x - matXY[1] * y); - rotY = (matXY[2] * x - matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - rotX = (-matXY[0] * x - matXY[1] * y); - rotY = (-matXY[2] * x - matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - rotX = (-matXY[0] * x + matXY[1] * y); - rotY = (-matXY[2] * x + matXY[3] * y); - safePutPixel(yc + rotY, xc + rotX, col, pim); - } -} - -// Bresenham approach do not allow to draw concentric circle without holes. -// So it's better the use the Andres method. -// http://fr.wikipedia.org/wiki/Algorithme_de_tracé_de_cercle_d'Andres. -template -void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) { - Image &im = *pim; - if ( im.Contains(y + radius, x + radius) - || im.Contains(y + radius, x - radius) - || im.Contains(y - radius, x + radius) - || im.Contains(y - radius, x - radius)) { - int x1 = 0; - int y1 = radius; - int d = radius - 1; - while (y1 >= x1) { - // Draw the point for each octant. - safePutPixel( y1 + y, x1 + x, col, pim); - safePutPixel( x1 + y, y1 + x, col, pim); - safePutPixel( y1 + y, -x1 + x, col, pim); - safePutPixel( x1 + y, -y1 + x, col, pim); - safePutPixel(-y1 + y, x1 + x, col, pim); - safePutPixel(-x1 + y, y1 + x, col, pim); - safePutPixel(-y1 + y, -x1 + x, col, pim); - safePutPixel(-x1 + y, -y1 + x, col, pim); - if (d >= 2 * x1) { - d = d - 2 * x1 - 1; - x1 += 1; - } else { - if (d <= 2 * (radius - y1)) { - d = d + 2 * y1 - 1; - y1 -= 1; - } else { - d = d + 2 * (y1 - x1 - 1); - y1 -= 1; - x1 += 1; - } - } - } - } -} - -// Bresenham algorithm -template -void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { - Image &im = *pim; - - // If one point is outside the image - // Replace the outside point by the intersection of the line and - // the limit (either x=width or y=height). - if (!im.Contains(ya, xa) || !im.Contains(yb, xb)) { - int width = pim->Width(); - int height = pim->Height(); - const bool xdir = xa < xb, ydir = ya < yb; - float nx0 = xa, nx1 = xb, ny0 = ya, ny1 = yb, - &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, - &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0, - &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, - &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0; - - if (xright < 0 || xleft >= width) return; - if (xleft < 0) { - yleft -= xleft*(yright - yleft)/(xright - xleft); - xleft = 0; - } - if (xright >= width) { - yright -= (xright - width)*(yright - yleft)/(xright - xleft); - xright = width - 1; - } - if (ydown < 0 || yup >= height) return; - if (yup < 0) { - xup -= yup*(xdown - xup)/(ydown - yup); - yup = 0; - } - if (ydown >= height) { - xdown -= (ydown - height)*(xdown - xup)/(ydown - yup); - ydown = height - 1; - } - - xa = (int) xleft; - xb = (int) xright; - ya = (int) yleft; - yb = (int) yright; - } - - int xbas, xhaut, ybas, yhaut; - // Check the condition ybas < yhaut. - if (ya <= yb) { - xbas = xa; - ybas = ya; - xhaut = xb; - yhaut = yb; - } else { - xbas = xb; - ybas = yb; - xhaut = xa; - yhaut = ya; - } - // Initialize slope. - int x, y, dx, dy, incrmX, incrmY, dp, N, S; - dx = xhaut - xbas; - dy = yhaut - ybas; - if (dx > 0) { // If xhaut > xbas we will increment X. - incrmX = 1; - } else { - incrmX = -1; // else we will decrement X. - dx *= -1; - } - if (dy > 0) { // Positive slope will increment X. - incrmY = 1; - } else { // Negative slope. - incrmY = -1; - } - if (dx >= dy) { - dp = 2 * dy - dx; - S = 2 * dy; - N = 2 * (dy - dx); - y = ybas; - x = xbas; - while (x != xhaut) { - safePutPixel(y, x, col, pim); - x += incrmX; - if (dp <= 0) { // Go in direction of the South Pixel. - dp += S; - } else { // Go to the North. - dp += N; - y+=incrmY; - } - } - } else { - dp = 2 * dx - dy; - S = 2 * dx; - N = 2 * (dx - dy); - x = xbas; - y = ybas; - while (y < yhaut) { - safePutPixel(y, x, col, pim); - y += incrmY; - if (dp <= 0) { // Go in direction of the South Pixel. - dp += S; - } else { // Go to the North. - dp += N; - x += incrmX; - } - } - } - safePutPixel(y, x, col, pim); -} - -} // namespace libmv - -#endif // LIBMV_IMAGE_IMAGE_DRAWING_H diff --git a/extern/libmv/libmv/image/image_test.cc b/extern/libmv/libmv/image/image_test.cc deleted file mode 100644 index 241f49f2244..00000000000 --- a/extern/libmv/libmv/image/image_test.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include - -#include "libmv/image/image.h" -#include "testing/testing.h" - -using libmv::Image; -using libmv::Array3Df; - -namespace { - -TEST(Image, SimpleImageAccessors) { - Array3Df *array = new Array3Df(2, 3); - Image image(array); - EXPECT_EQ(array, image.AsArray3Df()); - EXPECT_TRUE(NULL == image.AsArray3Du()); -} - -TEST(Image, MemorySizeInBytes) { - Array3Df *array = new Array3Df(2, 3); - Image image(array); - int size = sizeof(image) + array->MemorySizeInBytes(); - EXPECT_EQ(size, image.MemorySizeInBytes()); -} - -} // namespace diff --git a/extern/libmv/libmv/image/sample.h b/extern/libmv/libmv/image/sample.h deleted file mode 100644 index 24eb9ccd57d..00000000000 --- a/extern/libmv/libmv/image/sample.h +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_IMAGE_SAMPLE_H_ -#define LIBMV_IMAGE_SAMPLE_H_ - -#include "libmv/image/image.h" - -namespace libmv { - -/// Nearest neighbor interpolation. -template -inline T SampleNearest(const Array3D &image, - float y, float x, int v = 0) { - const int i = int(round(y)); - const int j = int(round(x)); - return image(i, j, v); -} - -inline void LinearInitAxis(float x, int size, - int *x1, int *x2, - float *dx) { - const int ix = static_cast(x); - if (ix < 0) { - *x1 = 0; - *x2 = 0; - *dx = 1.0; - } else if (ix > size - 2) { - *x1 = size - 1; - *x2 = size - 1; - *dx = 1.0; - } else { - *x1 = ix; - *x2 = ix + 1; - *dx = *x2 - x; - } -} - -/// Linear interpolation. -template -inline T SampleLinear(const Array3D &image, float y, float x, int v = 0) { - int x1, y1, x2, y2; - float dx, dy; - - LinearInitAxis(y, image.Height(), &y1, &y2, &dy); - LinearInitAxis(x, image.Width(), &x1, &x2, &dx); - - const T im11 = image(y1, x1, v); - const T im12 = image(y1, x2, v); - const T im21 = image(y2, x1, v); - const T im22 = image(y2, x2, v); - - return T( dy * (dx * im11 + (1.0 - dx) * im12) + - (1 - dy) * (dx * im21 + (1.0 - dx) * im22)); -} - -/// Linear interpolation, of all channels. The sample is assumed to have the -/// same size as the number of channels in image. -template -inline void SampleLinear(const Array3D &image, float y, float x, T *sample) { - int x1, y1, x2, y2; - float dx, dy; - - LinearInitAxis(y, image.Height(), &y1, &y2, &dy); - LinearInitAxis(x, image.Width(), &x1, &x2, &dx); - - for (int i = 0; i < image.Depth(); ++i) { - const T im11 = image(y1, x1, i); - const T im12 = image(y1, x2, i); - const T im21 = image(y2, x1, i); - const T im22 = image(y2, x2, i); - - sample[i] = T( dy * (dx * im11 + (1.0 - dx) * im12) + - (1 - dy) * (dx * im21 + (1.0 - dx) * im22)); - } -} - -// Downsample all channels by 2. If the image has odd width or height, the last -// row or column is ignored. -// FIXME(MatthiasF): this implementation shouldn't be in an interface file -inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) { - int height = in.Height() / 2; - int width = in.Width() / 2; - int depth = in.Depth(); - - out->Resize(height, width, depth); - - // 2x2 box filter downsampling. - for (int r = 0; r < height; ++r) { - for (int c = 0; c < width; ++c) { - for (int k = 0; k < depth; ++k) { - (*out)(r, c, k) = (in(2 * r, 2 * c, k) + - in(2 * r + 1, 2 * c, k) + - in(2 * r, 2 * c + 1, k) + - in(2 * r + 1, 2 * c + 1, k)) / 4.0f; - } - } - } -} - -// Sample a region centered at x,y in image with size extending by half_width -// from x,y. Channels specifies the number of channels to sample from. -inline void SamplePattern(const FloatImage &image, - double x, double y, - int half_width, - int channels, - FloatImage *sampled) { - sampled->Resize(2 * half_width + 1, 2 * half_width + 1, channels); - for (int r = -half_width; r <= half_width; ++r) { - for (int c = -half_width; c <= half_width; ++c) { - for (int i = 0; i < channels; ++i) { - (*sampled)(r + half_width, c + half_width, i) = - SampleLinear(image, y + r, x + c, i); - } - } - } -} - -} // namespace libmv - -#endif // LIBMV_IMAGE_SAMPLE_H_ diff --git a/extern/libmv/libmv/image/sample_test.cc b/extern/libmv/libmv/image/sample_test.cc deleted file mode 100644 index c8a0ce470c2..00000000000 --- a/extern/libmv/libmv/image/sample_test.cc +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/image/sample.h" -#include "testing/testing.h" - -using namespace libmv; - -namespace { - -TEST(Image, Nearest) { - Array3Du image(2, 2); - image(0, 0) = 0; - image(0, 1) = 1; - image(1, 0) = 2; - image(1, 1) = 3; - EXPECT_EQ(0, SampleNearest(image, -0.4f, -0.4f)); - EXPECT_EQ(0, SampleNearest(image, 0.4f, 0.4f)); - EXPECT_EQ(3, SampleNearest(image, 0.6f, 0.6f)); - EXPECT_EQ(3, SampleNearest(image, 1.4f, 1.4f)); -} - -TEST(Image, Linear) { - Array3Df image(2, 2); - image(0, 0) = 0; - image(0, 1) = 1; - image(1, 0) = 2; - image(1, 1) = 3; - EXPECT_EQ(1.5, SampleLinear(image, 0.5, 0.5)); -} - -TEST(Image, DownsampleBy2) { - Array3Df image(2, 2); - image(0, 0) = 0; - image(0, 1) = 1; - image(1, 0) = 2; - image(1, 1) = 3; - Array3Df resampled_image; - DownsampleChannelsBy2(image, &resampled_image); - ASSERT_EQ(1, resampled_image.Height()); - ASSERT_EQ(1, resampled_image.Width()); - ASSERT_EQ(1, resampled_image.Depth()); - EXPECT_FLOAT_EQ(6./4., resampled_image(0, 0)); -} - -TEST(Image, DownsampleBy2MultiChannel) { - Array3Df image(2, 2, 3); - image(0, 0, 0) = 0; - image(0, 1, 0) = 1; - image(1, 0, 0) = 2; - image(1, 1, 0) = 3; - - image(0, 0, 1) = 5; - image(0, 1, 1) = 6; - image(1, 0, 1) = 7; - image(1, 1, 1) = 8; - - image(0, 0, 2) = 9; - image(0, 1, 2) = 10; - image(1, 0, 2) = 11; - image(1, 1, 2) = 12; - - Array3Df resampled_image; - DownsampleChannelsBy2(image, &resampled_image); - ASSERT_EQ(1, resampled_image.Height()); - ASSERT_EQ(1, resampled_image.Width()); - ASSERT_EQ(3, resampled_image.Depth()); - EXPECT_FLOAT_EQ((0+1+2+3)/4., resampled_image(0, 0, 0)); - EXPECT_FLOAT_EQ((5+6+7+8)/4., resampled_image(0, 0, 1)); - EXPECT_FLOAT_EQ((9+10+11+12)/4., resampled_image(0, 0, 2)); -} -} // namespace diff --git a/extern/libmv/libmv/image/tuple.h b/extern/libmv/libmv/image/tuple.h deleted file mode 100644 index c8dc36f2e18..00000000000 --- a/extern/libmv/libmv/image/tuple.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_IMAGE_TUPLE_H -#define LIBMV_IMAGE_TUPLE_H - -#include - -namespace libmv { - -// A vector of elements with fixed lenght and deep copy semantics. -template -class Tuple { - public: - enum { SIZE = N }; - Tuple() {} - Tuple(T initial_value) { Reset(initial_value); } - - template - Tuple(D *values) { Reset(values); } - - template - Tuple(const Tuple &b) { Reset(b); } - - template - Tuple& operator=(const Tuple& b) { - Reset(b); - return *this; - } - - template - void Reset(const Tuple& b) { Reset(b.Data()); } - - template - void Reset(D *values) { - for (int i = 0;i < N; i++) { - data_[i] = T(values[i]); - } - } - - // Set all tuple values to the same thing. - void Reset(T value) { - for (int i = 0;i < N; i++) { - data_[i] = value; - } - } - - // Pointer to the first element. - T *Data() { return &data_[0]; } - const T *Data() const { return &data_[0]; } - - T &operator()(int i) { return data_[i]; } - const T &operator()(int i) const { return data_[i]; } - - bool operator==(const Tuple &other) const { - for (int i = 0; i < N; ++i) { - if ((*this)(i) != other(i)) { - return false; - } - } - return true; - } - bool operator!=(const Tuple &other) const { - return !(*this == other); - } - - private: - T data_[N]; -}; - -} // namespace libmv - -#endif // LIBMV_IMAGE_TUPLE_H diff --git a/extern/libmv/libmv/image/tuple_test.cc b/extern/libmv/libmv/image/tuple_test.cc deleted file mode 100644 index df44e5638b5..00000000000 --- a/extern/libmv/libmv/image/tuple_test.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/image/tuple.h" -#include "testing/testing.h" - -#include - -using libmv::Tuple; - -namespace { - -TEST(Tuple, InitConstantValue) { - Tuple t(5); - EXPECT_EQ(t(0), 5); - EXPECT_EQ(t(0), 5); - EXPECT_EQ(t(0), 5); -} - -TEST(Tuple, InitFromPointer) { - float vals[3] = {1.0f, 2.0f, 3.0f}; - - Tuple t(vals); - for (int i = 0; i < 3; i++) - EXPECT_EQ(t(i), vals[i]); - - Tuple b(t); - EXPECT_EQ(b(0), int(vals[0])); - EXPECT_EQ(b(1), int(vals[1])); - EXPECT_EQ(b(2), int(vals[2])); -} - -TEST(Tuple, Swap) { - unsigned char vala[3] = {1, 2, 3}; - unsigned char valb[3] = {4, 5, 6}; - - Tuple a(vala); - Tuple b(valb); - - std::swap(a, b); - - EXPECT_EQ(a(0), int(valb[0])); - EXPECT_EQ(a(1), int(valb[1])); - EXPECT_EQ(a(2), int(valb[2])); - EXPECT_EQ(b(0), int(vala[0])); - EXPECT_EQ(b(1), int(vala[1])); - EXPECT_EQ(b(2), int(vala[2])); -} - -TEST(Tuple, IsEqualOperator) { - Tuple a; - a(0) = 1; - a(1) = 2; - a(2) = 3; - Tuple b; - b(0) = 1; - b(1) = 2; - b(2) = 3; - EXPECT_TRUE(a == b); - EXPECT_FALSE(a != b); - b(1) = 5; - EXPECT_TRUE(a != b); - EXPECT_FALSE(a == b); -} - -} // namespace diff --git a/extern/libmv/libmv/logging/logging.h b/extern/libmv/libmv/logging/logging.h deleted file mode 100644 index 776d9d52f7a..00000000000 --- a/extern/libmv/libmv/logging/logging.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2007, 2008, 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_LOGGING_LOGGING_H -#define LIBMV_LOGGING_LOGGING_H - -#include - -#define LG LOG(INFO) -#define V0 LOG(INFO) -#define V1 LOG(INFO) -#define V2 LOG(INFO) - -#endif // LIBMV_LOGGING_LOGGING_H diff --git a/extern/libmv/libmv/multiview/conditioning.cc b/extern/libmv/libmv/multiview/conditioning.cc deleted file mode 100644 index 0afbf119ea3..00000000000 --- a/extern/libmv/libmv/multiview/conditioning.cc +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2010 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/multiview/conditioning.h" -#include "libmv/multiview/projection.h" - -namespace libmv { - -// HZ 4.4.4 pag.109: Point conditioning (non isotropic) -void PreconditionerFromPoints(const Mat &points, Mat3 *T) { - Vec mean, variance; - MeanAndVarianceAlongRows(points, &mean, &variance); - - double xfactor = sqrt(2.0 / variance(0)); - double yfactor = sqrt(2.0 / variance(1)); - - // If variance is equal to 0.0 set scaling factor to identity. - // -> Else it will provide nan value (because division by 0). - if (variance(0) < 1e-8) - xfactor = mean(0) = 1.0; - if (variance(1) < 1e-8) - yfactor = mean(1) = 1.0; - - *T << xfactor, 0, -xfactor * mean(0), - 0, yfactor, -yfactor * mean(1), - 0, 0, 1; -} -// HZ 4.4.4 pag.107: Point conditioning (isotropic) -void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T) { - Vec mean, variance; - MeanAndVarianceAlongRows(points, &mean, &variance); - - double var_norm = variance.norm(); - double factor = sqrt(2.0 / var_norm); - - // If variance is equal to 0.0 set scaling factor to identity. - // -> Else it will provide nan value (because division by 0). - if (var_norm < 1e-8) { - factor = 1.0; - mean.setOnes(); - } - - *T << factor, 0, -factor * mean(0), - 0, factor, -factor * mean(1), - 0, 0, 1; -} - -void ApplyTransformationToPoints(const Mat &points, - const Mat3 &T, - Mat *transformed_points) { - int n = points.cols(); - transformed_points->resize(2, n); - Mat3X p(3, n); - EuclideanToHomogeneous(points, &p); - p = T * p; - HomogeneousToEuclidean(p, transformed_points); -} - -void NormalizePoints(const Mat &points, - Mat *normalized_points, - Mat3 *T) { - PreconditionerFromPoints(points, T); - ApplyTransformationToPoints(points, *T, normalized_points); -} - -void NormalizeIsotropicPoints(const Mat &points, - Mat *normalized_points, - Mat3 *T) { - IsotropicPreconditionerFromPoints(points, T); - ApplyTransformationToPoints(points, *T, normalized_points); -} - -// Denormalize the results. See HZ page 109. -void UnnormalizerT::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H) { - *H = T2.transpose() * (*H) * T1; -} - -void UnnormalizerI::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H) { - *H = T2.inverse() * (*H) * T1; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/multiview/conditioning.h b/extern/libmv/libmv/multiview/conditioning.h deleted file mode 100644 index 8f3e3a76070..00000000000 --- a/extern/libmv/libmv/multiview/conditioning.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2010 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_CONDITIONNING_H_ -#define LIBMV_MULTIVIEW_CONDITIONNING_H_ - -#include "libmv/numeric/numeric.h" - -namespace libmv { - -// Point conditioning (non isotropic) -void PreconditionerFromPoints(const Mat &points, Mat3 *T); -// Point conditioning (isotropic) -void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T); - -void ApplyTransformationToPoints(const Mat &points, - const Mat3 &T, - Mat *transformed_points); - -void NormalizePoints(const Mat &points, - Mat *normalized_points, - Mat3 *T); - -void NormalizeIsotropicPoints(const Mat &points, - Mat *normalized_points, - Mat3 *T); - -/// Use inverse for unnormalize -struct UnnormalizerI { - // Denormalize the results. See HZ page 109. - static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H); -}; - -/// Use transpose for unnormalize -struct UnnormalizerT { - // Denormalize the results. See HZ page 109. - static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H); -}; - -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_CONDITIONNING_H_ diff --git a/extern/libmv/libmv/multiview/euclidean_resection.cc b/extern/libmv/libmv/multiview/euclidean_resection.cc deleted file mode 100644 index 245b027fb7c..00000000000 --- a/extern/libmv/libmv/multiview/euclidean_resection.cc +++ /dev/null @@ -1,774 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/multiview/euclidean_resection.h" - -#include -#include - -#include -#include - -#include "libmv/base/vector.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/projection.h" - -namespace libmv { -namespace euclidean_resection { - -typedef unsigned int uint; - -bool EuclideanResection(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t, - ResectionMethod method) { - switch (method) { - case RESECTION_ANSAR_DANIILIDIS: - EuclideanResectionAnsarDaniilidis(x_camera, X_world, R, t); - break; - case RESECTION_EPNP: - return EuclideanResectionEPnP(x_camera, X_world, R, t); - break; - case RESECTION_PPNP: - return EuclideanResectionPPnP(x_camera, X_world, R, t); - break; - default: - LOG(FATAL) << "Unknown resection method."; - } - return false; -} - -bool EuclideanResection(const Mat &x_image, - const Mat3X &X_world, - const Mat3 &K, - Mat3 *R, Vec3 *t, - ResectionMethod method) { - CHECK(x_image.rows() == 2 || x_image.rows() == 3) - << "Invalid size for x_image: " - << x_image.rows() << "x" << x_image.cols(); - - Mat2X x_camera; - if (x_image.rows() == 2) { - EuclideanToNormalizedCamera(x_image, K, &x_camera); - } else if (x_image.rows() == 3) { - HomogeneousToNormalizedCamera(x_image, K, &x_camera); - } - return EuclideanResection(x_camera, X_world, R, t, method); -} - -void AbsoluteOrientation(const Mat3X &X, - const Mat3X &Xp, - Mat3 *R, - Vec3 *t) { - int num_points = X.cols(); - Vec3 C = X.rowwise().sum() / num_points; // Centroid of X. - Vec3 Cp = Xp.rowwise().sum() / num_points; // Centroid of Xp. - - // Normalize the two point sets. - Mat3X Xn(3, num_points), Xpn(3, num_points); - for (int i = 0; i < num_points; ++i) { - Xn.col(i) = X.col(i) - C; - Xpn.col(i) = Xp.col(i) - Cp; - } - - // Construct the N matrix (pg. 635). - double Sxx = Xn.row(0).dot(Xpn.row(0)); - double Syy = Xn.row(1).dot(Xpn.row(1)); - double Szz = Xn.row(2).dot(Xpn.row(2)); - double Sxy = Xn.row(0).dot(Xpn.row(1)); - double Syx = Xn.row(1).dot(Xpn.row(0)); - double Sxz = Xn.row(0).dot(Xpn.row(2)); - double Szx = Xn.row(2).dot(Xpn.row(0)); - double Syz = Xn.row(1).dot(Xpn.row(2)); - double Szy = Xn.row(2).dot(Xpn.row(1)); - - Mat4 N; - N << Sxx + Syy + Szz, Syz - Szy, Szx - Sxz, Sxy - Syx, - Syz - Szy, Sxx - Syy - Szz, Sxy + Syx, Szx + Sxz, - Szx - Sxz, Sxy + Syx, -Sxx + Syy - Szz, Syz + Szy, - Sxy - Syx, Szx + Sxz, Syz + Szy, -Sxx - Syy + Szz; - - // Find the unit quaternion q that maximizes qNq. It is the eigenvector - // corresponding to the lagest eigenvalue. - Vec4 q = N.jacobiSvd(Eigen::ComputeFullU).matrixU().col(0); - - // Retrieve the 3x3 rotation matrix. - Vec4 qq = q.array() * q.array(); - double q0q1 = q(0) * q(1); - double q0q2 = q(0) * q(2); - double q0q3 = q(0) * q(3); - double q1q2 = q(1) * q(2); - double q1q3 = q(1) * q(3); - double q2q3 = q(2) * q(3); - - (*R) << qq(0) + qq(1) - qq(2) - qq(3), - 2 * (q1q2 - q0q3), - 2 * (q1q3 + q0q2), - 2 * (q1q2+ q0q3), - qq(0) - qq(1) + qq(2) - qq(3), - 2 * (q2q3 - q0q1), - 2 * (q1q3 - q0q2), - 2 * (q2q3 + q0q1), - qq(0) - qq(1) - qq(2) + qq(3); - - // Fix the handedness of the R matrix. - if (R->determinant() < 0) { - R->row(2) = -R->row(2); - } - // Compute the final translation. - *t = Cp - *R * C; -} - -// Convert i and j indices of the original variables into their quadratic -// permutation single index. It follows that t_ij = t_ji. -static int IJToPointIndex(int i, int j, int num_points) { - // Always make sure that j is bigger than i. This handles t_ij = t_ji. - if (j < i) { - std::swap(i, j); - } - int idx; - int num_permutation_rows = num_points * (num_points - 1) / 2; - - // All t_ii's are located at the end of the t vector after all t_ij's. - if (j == i) { - idx = num_permutation_rows + i; - } else { - int offset = (num_points - i - 1) * (num_points - i) / 2; - idx = (num_permutation_rows - offset + j - i - 1); - } - return idx; -}; - -// Convert i and j indexes of the solution for lambda to their linear indexes. -static int IJToIndex(int i, int j, int num_lambda) { - if (j < i) { - std::swap(i, j); - } - int A = num_lambda * (num_lambda + 1) / 2; - int B = num_lambda - i; - int C = B * (B + 1) / 2; - int idx = A - C + j - i; - return idx; -}; - -static int Sign(double value) { - return (value < 0) ? -1 : 1; -}; - -// Organizes a square matrix into a single row constraint on the elements of -// Lambda to create the constraints in equation (5) in "Linear Pose Estimation -// from Points or Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no. -// 5. -static Vec MatrixToConstraint(const Mat &A, - int num_k_columns, - int num_lambda) { - Vec C(num_k_columns); - C.setZero(); - int idx = 0; - for (int i = 0; i < num_lambda; ++i) { - for (int j = i; j < num_lambda; ++j) { - C(idx) = A(i, j); - if (i != j) { - C(idx) += A(j, i); - } - ++idx; - } - } - return C; -} - -// Normalizes the columns of vectors. -static void NormalizeColumnVectors(Mat3X *vectors) { - int num_columns = vectors->cols(); - for (int i = 0; i < num_columns; ++i) { - vectors->col(i).normalize(); - } -} - -void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, - Vec3 *t) { - CHECK(x_camera.cols() == X_world.cols()); - CHECK(x_camera.cols() > 3); - - int num_points = x_camera.cols(); - - // Copy the normalized camera coords into 3 vectors and normalize them so - // that they are unit vectors from the camera center. - Mat3X x_camera_unit(3, num_points); - x_camera_unit.block(0, 0, 2, num_points) = x_camera; - x_camera_unit.row(2).setOnes(); - NormalizeColumnVectors(&x_camera_unit); - - int num_m_rows = num_points * (num_points - 1) / 2; - int num_tt_variables = num_points * (num_points + 1) / 2; - int num_m_columns = num_tt_variables + 1; - Mat M(num_m_columns, num_m_columns); - M.setZero(); - Matu ij_index(num_tt_variables, 2); - - // Create the constraint equations for the t_ij variables (7) and arrange - // them into the M matrix (8). Also store the initial (i, j) indices. - int row = 0; - for (int i = 0; i < num_points; ++i) { - for (int j = i+1; j < num_points; ++j) { - M(row, row) = -2 * x_camera_unit.col(i).dot(x_camera_unit.col(j)); - M(row, num_m_rows + i) = x_camera_unit.col(i).dot(x_camera_unit.col(i)); - M(row, num_m_rows + j) = x_camera_unit.col(j).dot(x_camera_unit.col(j)); - Vec3 Xdiff = X_world.col(i) - X_world.col(j); - double center_to_point_distance = Xdiff.norm(); - M(row, num_m_columns - 1) = - - center_to_point_distance * center_to_point_distance; - ij_index(row, 0) = i; - ij_index(row, 1) = j; - ++row; - } - ij_index(i + num_m_rows, 0) = i; - ij_index(i + num_m_rows, 1) = i; - } - - int num_lambda = num_points + 1; // Dimension of the null space of M. - Mat V = M.jacobiSvd(Eigen::ComputeFullV).matrixV().block(0, - num_m_rows, - num_m_columns, - num_lambda); - - // TODO(vess): The number of constraint equations in K (num_k_rows) must be - // (num_points + 1) * (num_points + 2)/2. This creates a performance issue - // for more than 4 points. It is fine for 4 points at the moment with 18 - // instead of 15 equations. - int num_k_rows = num_m_rows + num_points * - (num_points*(num_points-1)/2 - num_points+1); - int num_k_columns = num_lambda * (num_lambda + 1) / 2; - Mat K(num_k_rows, num_k_columns); - K.setZero(); - - // Construct the first part of the K matrix corresponding to (t_ii, t_jk) for - // i != j. - int counter_k_row = 0; - for (int idx1 = num_m_rows; idx1 < num_tt_variables; ++idx1) { - for (int idx2 = 0; idx2 < num_m_rows; ++idx2) { - unsigned int i = ij_index(idx1, 0); - unsigned int j = ij_index(idx2, 0); - unsigned int k = ij_index(idx2, 1); - - if (i != j && i != k) { - int idx3 = IJToPointIndex(i, j, num_points); - int idx4 = IJToPointIndex(i, k, num_points); - - K.row(counter_k_row) = - MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)- - V.row(idx3).transpose() * V.row(idx4), - num_k_columns, - num_lambda); - ++counter_k_row; - } - } - } - - // Construct the second part of the K matrix corresponding to (t_ii,t_jk) for - // j==k. - for (int idx1 = num_m_rows; idx1 < num_tt_variables; ++idx1) { - for (int idx2 = idx1 + 1; idx2 < num_tt_variables; ++idx2) { - unsigned int i = ij_index(idx1, 0); - unsigned int j = ij_index(idx2, 0); - unsigned int k = ij_index(idx2, 1); - - int idx3 = IJToPointIndex(i, j, num_points); - int idx4 = IJToPointIndex(i, k, num_points); - - K.row(counter_k_row) = - MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)- - V.row(idx3).transpose() * V.row(idx4), - num_k_columns, - num_lambda); - ++counter_k_row; - } - } - Vec L_sq = K.jacobiSvd(Eigen::ComputeFullV).matrixV().col(num_k_columns - 1); - - // Pivot on the largest element for numerical stability. Afterwards recover - // the sign of the lambda solution. - double max_L_sq_value = fabs(L_sq(IJToIndex(0, 0, num_lambda))); - int max_L_sq_index = 1; - for (int i = 1; i < num_lambda; ++i) { - double abs_sq_value = fabs(L_sq(IJToIndex(i, i, num_lambda))); - if (max_L_sq_value < abs_sq_value) { - max_L_sq_value = abs_sq_value; - max_L_sq_index = i; - } - } - // Ensure positiveness of the largest value corresponding to lambda_ii. - L_sq = L_sq * Sign(L_sq(IJToIndex(max_L_sq_index, - max_L_sq_index, - num_lambda))); - - Vec L(num_lambda); - L(max_L_sq_index) = sqrt(L_sq(IJToIndex(max_L_sq_index, - max_L_sq_index, - num_lambda))); - - for (int i = 0; i < num_lambda; ++i) { - if (i != max_L_sq_index) { - L(i) = L_sq(IJToIndex(max_L_sq_index, i, num_lambda)) / L(max_L_sq_index); - } - } - - // Correct the scale using the fact that the last constraint is equal to 1. - L = L / (V.row(num_m_columns - 1).dot(L)); - Vec X = V * L; - - // Recover the distances from the camera center to the 3D points Q. - Vec d(num_points); - d.setZero(); - for (int c_point = num_m_rows; c_point < num_tt_variables; ++c_point) { - d(c_point - num_m_rows) = sqrt(X(c_point)); - } - - // Create the 3D points in the camera system. - Mat X_cam(3, num_points); - for (int c_point = 0; c_point < num_points; ++c_point) { - X_cam.col(c_point) = d(c_point) * x_camera_unit.col(c_point); - } - // Recover the camera translation and rotation. - AbsoluteOrientation(X_world, X_cam, R, t); -} - -// Selects 4 virtual control points using mean and PCA. -static void SelectControlPoints(const Mat3X &X_world, - Mat *X_centered, - Mat34 *X_control_points) { - size_t num_points = X_world.cols(); - - // The first virtual control point, C0, is the centroid. - Vec mean, variance; - MeanAndVarianceAlongRows(X_world, &mean, &variance); - X_control_points->col(0) = mean; - - // Computes PCA - X_centered->resize(3, num_points); - for (size_t c = 0; c < num_points; c++) { - X_centered->col(c) = X_world.col(c) - mean; - } - Mat3 X_centered_sq = (*X_centered) * X_centered->transpose(); - Eigen::JacobiSVD X_centered_sq_svd(X_centered_sq, Eigen::ComputeFullU); - Vec3 w = X_centered_sq_svd.singularValues(); - Mat3 u = X_centered_sq_svd.matrixU(); - for (size_t c = 0; c < 3; c++) { - double k = sqrt(w(c) / num_points); - X_control_points->col(c + 1) = mean + k * u.col(c); - } -} - -// Computes the barycentric coordinates for all real points -static void ComputeBarycentricCoordinates(const Mat3X &X_world_centered, - const Mat34 &X_control_points, - Mat4X *alphas) { - size_t num_points = X_world_centered.cols(); - Mat3 C2; - for (size_t c = 1; c < 4; c++) { - C2.col(c-1) = X_control_points.col(c) - X_control_points.col(0); - } - - Mat3 C2inv = C2.inverse(); - Mat3X a = C2inv * X_world_centered; - - alphas->resize(4, num_points); - alphas->setZero(); - alphas->block(1, 0, 3, num_points) = a; - for (size_t c = 0; c < num_points; c++) { - (*alphas)(0, c) = 1.0 - alphas->col(c).sum(); - } -} - -// Estimates the coordinates of all real points in the camera coordinate frame -static void ComputePointsCoordinatesInCameraFrame( - const Mat4X &alphas, - const Vec4 &betas, - const Eigen::Matrix &U, - Mat3X *X_camera) { - size_t num_points = alphas.cols(); - - // Estimates the control points in the camera reference frame. - Mat34 C2b; C2b.setZero(); - for (size_t cu = 0; cu < 4; cu++) { - for (size_t c = 0; c < 4; c++) { - C2b.col(c) += betas(cu) * U.block(11 - cu, c * 3, 1, 3).transpose(); - } - } - - // Estimates the 3D points in the camera reference frame - X_camera->resize(3, num_points); - for (size_t c = 0; c < num_points; c++) { - X_camera->col(c) = C2b * alphas.col(c); - } - - // Check the sign of the z coordinate of the points (should be positive) - uint num_z_neg = 0; - for (size_t i = 0; i < X_camera->cols(); ++i) { - if ((*X_camera)(2, i) < 0) { - num_z_neg++; - } - } - - // If more than 50% of z are negative, we change the signs - if (num_z_neg > 0.5 * X_camera->cols()) { - C2b = -C2b; - *X_camera = -(*X_camera); - } -} - -bool EuclideanResectionEPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t) { - CHECK(x_camera.cols() == X_world.cols()); - CHECK(x_camera.cols() > 3); - size_t num_points = X_world.cols(); - - // Select the control points. - Mat34 X_control_points; - Mat X_centered; - SelectControlPoints(X_world, &X_centered, &X_control_points); - - // Compute the barycentric coordinates. - Mat4X alphas(4, num_points); - ComputeBarycentricCoordinates(X_centered, X_control_points, &alphas); - - // Estimates the M matrix with the barycentric coordinates - Mat M(2 * num_points, 12); - Eigen::Matrix sub_M; - for (size_t c = 0; c < num_points; c++) { - double a0 = alphas(0, c); - double a1 = alphas(1, c); - double a2 = alphas(2, c); - double a3 = alphas(3, c); - double ui = x_camera(0, c); - double vi = x_camera(1, c); - M.block(2*c, 0, 2, 12) << a0, 0, - a0*(-ui), a1, 0, - a1*(-ui), a2, 0, - a2*(-ui), a3, 0, - a3*(-ui), 0, - a0, a0*(-vi), 0, - a1, a1*(-vi), 0, - a2, a2*(-vi), 0, - a3, a3*(-vi); - } - - // TODO(julien): Avoid the transpose by rewriting the u2.block() calls. - Eigen::JacobiSVD MtMsvd(M.transpose()*M, Eigen::ComputeFullU); - Eigen::Matrix u2 = MtMsvd.matrixU().transpose(); - - // Estimate the L matrix. - Eigen::Matrix dv1; - Eigen::Matrix dv2; - Eigen::Matrix dv3; - Eigen::Matrix dv4; - - dv1.row(0) = u2.block(11, 0, 1, 3) - u2.block(11, 3, 1, 3); - dv1.row(1) = u2.block(11, 0, 1, 3) - u2.block(11, 6, 1, 3); - dv1.row(2) = u2.block(11, 0, 1, 3) - u2.block(11, 9, 1, 3); - dv1.row(3) = u2.block(11, 3, 1, 3) - u2.block(11, 6, 1, 3); - dv1.row(4) = u2.block(11, 3, 1, 3) - u2.block(11, 9, 1, 3); - dv1.row(5) = u2.block(11, 6, 1, 3) - u2.block(11, 9, 1, 3); - dv2.row(0) = u2.block(10, 0, 1, 3) - u2.block(10, 3, 1, 3); - dv2.row(1) = u2.block(10, 0, 1, 3) - u2.block(10, 6, 1, 3); - dv2.row(2) = u2.block(10, 0, 1, 3) - u2.block(10, 9, 1, 3); - dv2.row(3) = u2.block(10, 3, 1, 3) - u2.block(10, 6, 1, 3); - dv2.row(4) = u2.block(10, 3, 1, 3) - u2.block(10, 9, 1, 3); - dv2.row(5) = u2.block(10, 6, 1, 3) - u2.block(10, 9, 1, 3); - dv3.row(0) = u2.block(9, 0, 1, 3) - u2.block(9, 3, 1, 3); - dv3.row(1) = u2.block(9, 0, 1, 3) - u2.block(9, 6, 1, 3); - dv3.row(2) = u2.block(9, 0, 1, 3) - u2.block(9, 9, 1, 3); - dv3.row(3) = u2.block(9, 3, 1, 3) - u2.block(9, 6, 1, 3); - dv3.row(4) = u2.block(9, 3, 1, 3) - u2.block(9, 9, 1, 3); - dv3.row(5) = u2.block(9, 6, 1, 3) - u2.block(9, 9, 1, 3); - dv4.row(0) = u2.block(8, 0, 1, 3) - u2.block(8, 3, 1, 3); - dv4.row(1) = u2.block(8, 0, 1, 3) - u2.block(8, 6, 1, 3); - dv4.row(2) = u2.block(8, 0, 1, 3) - u2.block(8, 9, 1, 3); - dv4.row(3) = u2.block(8, 3, 1, 3) - u2.block(8, 6, 1, 3); - dv4.row(4) = u2.block(8, 3, 1, 3) - u2.block(8, 9, 1, 3); - dv4.row(5) = u2.block(8, 6, 1, 3) - u2.block(8, 9, 1, 3); - - Eigen::Matrix L; - for (size_t r = 0; r < 6; r++) { - L.row(r) << dv1.row(r).dot(dv1.row(r)), - 2.0 * dv1.row(r).dot(dv2.row(r)), - dv2.row(r).dot(dv2.row(r)), - 2.0 * dv1.row(r).dot(dv3.row(r)), - 2.0 * dv2.row(r).dot(dv3.row(r)), - dv3.row(r).dot(dv3.row(r)), - 2.0 * dv1.row(r).dot(dv4.row(r)), - 2.0 * dv2.row(r).dot(dv4.row(r)), - 2.0 * dv3.row(r).dot(dv4.row(r)), - dv4.row(r).dot(dv4.row(r)); - } - Vec6 rho; - rho << (X_control_points.col(0) - X_control_points.col(1)).squaredNorm(), - (X_control_points.col(0) - X_control_points.col(2)).squaredNorm(), - (X_control_points.col(0) - X_control_points.col(3)).squaredNorm(), - (X_control_points.col(1) - X_control_points.col(2)).squaredNorm(), - (X_control_points.col(1) - X_control_points.col(3)).squaredNorm(), - (X_control_points.col(2) - X_control_points.col(3)).squaredNorm(); - - // There are three possible solutions based on the three approximations of L - // (betas). Below, each one is solved for then the best one is chosen. - Mat3X X_camera; - Mat3 K; K.setIdentity(); - vector Rs(3); - vector ts(3); - Vec rmse(3); - - // At one point this threshold was 1e-3, and caused no end of problems in - // Blender by causing frames to not resect when they would have worked fine. - // When the resect failed, the projective followup is run leading to worse - // results, and often the dreaded "flipping" where objects get flipped - // between frames. Instead, disable the check for now, always succeeding. The - // ultimate check is always reprojection error anyway. - // - // TODO(keir): Decide if setting this to infinity, effectively disabling the - // check, is the right approach. So far this seems the case. - double kSuccessThreshold = std::numeric_limits::max(); - - // Find the first possible solution for R, t corresponding to: - // Betas = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33] - // Betas_approx_1 = [b00 b01 b02 b03] - Vec4 betas = Vec4::Zero(); - Eigen::Matrix l_6x4; - for (size_t r = 0; r < 6; r++) { - l_6x4.row(r) << L(r, 0), L(r, 1), L(r, 3), L(r, 6); - } - Eigen::JacobiSVD svd_of_l4(l_6x4, - Eigen::ComputeFullU | Eigen::ComputeFullV); - Vec4 b4 = svd_of_l4.solve(rho); - if ((l_6x4 * b4).isApprox(rho, kSuccessThreshold)) { - if (b4(0) < 0) { - b4 = -b4; - } - b4(0) = std::sqrt(b4(0)); - betas << b4(0), b4(1) / b4(0), b4(2) / b4(0), b4(3) / b4(0); - ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera); - AbsoluteOrientation(X_world, X_camera, &Rs[0], &ts[0]); - rmse(0) = RootMeanSquareError(x_camera, X_world, K, Rs[0], ts[0]); - } else { - LOG(ERROR) << "First approximation of beta not good enough."; - ts[0].setZero(); - rmse(0) = std::numeric_limits::max(); - } - - // Find the second possible solution for R, t corresponding to: - // Betas = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33] - // Betas_approx_2 = [b00 b01 b11] - betas.setZero(); - Eigen::Matrix l_6x3; - l_6x3 = L.block(0, 0, 6, 3); - Eigen::JacobiSVD svdOfL3(l_6x3, - Eigen::ComputeFullU | Eigen::ComputeFullV); - Vec3 b3 = svdOfL3.solve(rho); - VLOG(2) << " rho = " << rho; - VLOG(2) << " l_6x3 * b3 = " << l_6x3 * b3; - if ((l_6x3 * b3).isApprox(rho, kSuccessThreshold)) { - if (b3(0) < 0) { - betas(0) = std::sqrt(-b3(0)); - betas(1) = (b3(2) < 0) ? std::sqrt(-b3(2)) : 0; - } else { - betas(0) = std::sqrt(b3(0)); - betas(1) = (b3(2) > 0) ? std::sqrt(b3(2)) : 0; - } - if (b3(1) < 0) { - betas(0) = -betas(0); - } - betas(2) = 0; - betas(3) = 0; - ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera); - AbsoluteOrientation(X_world, X_camera, &Rs[1], &ts[1]); - rmse(1) = RootMeanSquareError(x_camera, X_world, K, Rs[1], ts[1]); - } else { - LOG(ERROR) << "Second approximation of beta not good enough."; - ts[1].setZero(); - rmse(1) = std::numeric_limits::max(); - } - - // Find the third possible solution for R, t corresponding to: - // Betas = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33] - // Betas_approx_3 = [b00 b01 b11 b02 b12] - betas.setZero(); - Eigen::Matrix l_6x5; - l_6x5 = L.block(0, 0, 6, 5); - Eigen::JacobiSVD svdOfL5(l_6x5, - Eigen::ComputeFullU | Eigen::ComputeFullV); - Vec5 b5 = svdOfL5.solve(rho); - if ((l_6x5 * b5).isApprox(rho, kSuccessThreshold)) { - if (b5(0) < 0) { - betas(0) = std::sqrt(-b5(0)); - if (b5(2) < 0) { - betas(1) = std::sqrt(-b5(2)); - } else { - b5(2) = 0; - } - } else { - betas(0) = std::sqrt(b5(0)); - if (b5(2) > 0) { - betas(1) = std::sqrt(b5(2)); - } else { - b5(2) = 0; - } - } - if (b5(1) < 0) { - betas(0) = -betas(0); - } - betas(2) = b5(3) / betas(0); - betas(3) = 0; - ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera); - AbsoluteOrientation(X_world, X_camera, &Rs[2], &ts[2]); - rmse(2) = RootMeanSquareError(x_camera, X_world, K, Rs[2], ts[2]); - } else { - LOG(ERROR) << "Third approximation of beta not good enough."; - ts[2].setZero(); - rmse(2) = std::numeric_limits::max(); - } - - // Finally, with all three solutions, select the (R, t) with the best RMSE. - VLOG(2) << "RMSE for solution 0: " << rmse(0); - VLOG(2) << "RMSE for solution 1: " << rmse(1); - VLOG(2) << "RMSE for solution 2: " << rmse(2); - size_t n = 0; - if (rmse(1) < rmse(0)) { - n = 1; - } - if (rmse(2) < rmse(n)) { - n = 2; - } - if (rmse(n) == std::numeric_limits::max()) { - LOG(ERROR) << "All three possibilities failed. Reporting failure."; - return false; - } - - VLOG(1) << "RMSE for best solution #" << n << ": " << rmse(n); - *R = Rs[n]; - *t = ts[n]; - - // TODO(julien): Improve the solutions with non-linear refinement. - return true; -} - -/* - - Straight from the paper: - http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf - - function [R T] = ppnp(P,S,tol) - % input - % P : matrix (nx3) image coordinates in camera reference [u v 1] - % S : matrix (nx3) coordinates in world reference [X Y Z] - % tol: exit threshold - % - % output - % R : matrix (3x3) rotation (world-to-camera) - % T : vector (3x1) translation (world-to-camera) - % - n = size(P,1); - Z = zeros(n); - e = ones(n,1); - A = eye(n)-((e*e’)./n); - II = e./n; - err = +Inf; - E_old = 1000*ones(n,3); - while err>tol - [U,Ëœ,V] = svd(P’*Z*A*S); - VT = V’; - R=U*[1 0 0; 0 1 0; 0 0 det(U*VT)]*VT; - PR = P*R; - c = (S-Z*PR)’*II; - Y = S-e*c’; - Zmindiag = diag(PR*Y’)./(sum(P.*P,2)); - Zmindiag(Zmindiag<0)=0; - Z = diag(Zmindiag); - E = Y-Z*PR; - err = norm(E-E_old,’fro’); - E_old = E; - end - T = -R*c; - end - - */ -// TODO(keir): Re-do all the variable names and add comments matching the paper. -// This implementation has too much of the terseness of the original. On the -// other hand, it did work on the first try. -bool EuclideanResectionPPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t) { - int n = x_camera.cols(); - Mat Z = Mat::Zero(n, n); - Vec e = Vec::Ones(n); - Mat A = Mat::Identity(n, n) - (e * e.transpose() / n); - Vec II = e / n; - - Mat P(n, 3); - P.col(0) = x_camera.row(0); - P.col(1) = x_camera.row(1); - P.col(2).setConstant(1.0); - - Mat S = X_world.transpose(); - - double error = std::numeric_limits::infinity(); - Mat E_old = 1000 * Mat::Ones(n, 3); - - Vec3 c; - Mat E(n, 3); - - int iteration = 0; - double tolerance = 1e-5; - // TODO(keir): The limit of 100 can probably be reduced, but this will require - // some investigation. - while (error > tolerance && iteration < 100) { - Mat3 tmp = P.transpose() * Z * A * S; - Eigen::JacobiSVD svd(tmp, Eigen::ComputeFullU | Eigen::ComputeFullV); - Mat3 U = svd.matrixU(); - Mat3 VT = svd.matrixV().transpose(); - Vec3 s; - s << 1, 1, (U * VT).determinant(); - *R = U * s.asDiagonal() * VT; - Mat PR = P * *R; // n x 3 - c = (S - Z*PR).transpose() * II; - Mat Y = S - e*c.transpose(); // n x 3 - Vec Zmindiag = (PR * Y.transpose()).diagonal() - .cwiseQuotient(P.rowwise().squaredNorm()); - for (int i = 0; i < n; ++i) { - Zmindiag[i] = std::max(Zmindiag[i], 0.0); - } - Z = Zmindiag.asDiagonal(); - E = Y - Z*PR; - error = (E - E_old).norm(); - LOG(INFO) << "PPnP error(" << (iteration++) << "): " << error; - E_old = E; - } - *t = -*R*c; - - // TODO(keir): Figure out what the failure cases are. Is it too many - // iterations? Spend some time going through the math figuring out if there - // is some way to detect that the algorithm is going crazy, and return false. - return true; -} - - -} // namespace resection -} // namespace libmv diff --git a/extern/libmv/libmv/multiview/euclidean_resection.h b/extern/libmv/libmv/multiview/euclidean_resection.h deleted file mode 100644 index 28eae92611c..00000000000 --- a/extern/libmv/libmv/multiview/euclidean_resection.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) 2010 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ -#define LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ - -#include "libmv/numeric/numeric.h" -#include "libmv/multiview/projection.h" - -namespace libmv { -namespace euclidean_resection { - -enum ResectionMethod { - RESECTION_ANSAR_DANIILIDIS, - - // The "EPnP" algorithm by Lepetit et al. - // http://cvlab.epfl.ch/~lepetit/papers/lepetit_ijcv08.pdf - RESECTION_EPNP, - - // The Procrustes PNP algorithm ("PPnP") - // http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf - RESECTION_PPNP -}; - -/** - * Computes the extrinsic parameters, R and t for a calibrated camera - * from 4 or more 3D points and their normalized images. - * - * \param x_camera Image points in normalized camera coordinates e.g. x_camera - * = inv(K) * x_image. - * \param X_world 3D points in the world coordinate system - * \param R Solution for the camera rotation matrix - * \param t Solution for the camera translation vector - * \param method The resection method to use. - */ -bool EuclideanResection(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t, - ResectionMethod method = RESECTION_EPNP); - -/** - * Computes the extrinsic parameters, R and t for a calibrated camera - * from 4 or more 3D points and their images. - * - * \param x_image Image points in non-normalized image coordinates. The - * coordates are laid out one per row. The matrix can be Nx2 - * or Nx3 for euclidean or homogenous 2D coordinates. - * \param X_world 3D points in the world coordinate system - * \param K Intrinsic parameters camera matrix - * \param R Solution for the camera rotation matrix - * \param t Solution for the camera translation vector - * \param method Resection method - */ -bool EuclideanResection(const Mat &x_image, - const Mat3X &X_world, - const Mat3 &K, - Mat3 *R, Vec3 *t, - ResectionMethod method = RESECTION_EPNP); - -/** - * The absolute orientation algorithm recovers the transformation between a set - * of 3D points, X and Xp such that: - * - * Xp = R*X + t - * - * The recovery of the absolute orientation is implemented after this article: - * Horn, Hilden, "Closed-form solution of absolute orientation using - * orthonormal matrices" - */ -void AbsoluteOrientation(const Mat3X &X, - const Mat3X &Xp, - Mat3 *R, - Vec3 *t); - -/** - * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or - * more 3D points and their images. - * - * \param x_camera Image points in normalized camera coordinates, e.g. - * x_camera=inv(K)*x_image - * \param X_world 3D points in the world coordinate system - * \param R Solution for the camera rotation matrix - * \param t Solution for the camera translation vector - * - * This is the algorithm described in: "Linear Pose Estimation from Points or - * Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no. 5. - */ -void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t); -/** - * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or - * more 3D points and their images. - * - * \param x_camera Image points in normalized camera coordinates, - * e.g. x_camera = inv(K) * x_image - * \param X_world 3D points in the world coordinate system - * \param R Solution for the camera rotation matrix - * \param t Solution for the camera translation vector - * - * This is the algorithm described in: - * "{EP$n$P: An Accurate $O(n)$ Solution to the P$n$P Problem", by V. Lepetit - * and F. Moreno-Noguer and P. Fua, IJCV 2009. vol. 81, no. 2 - * \note: the non-linear optimization is not implemented here. - */ -bool EuclideanResectionEPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t); - -/** - * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or - * more 3D points and their images. - * - * \param x_camera Image points in normalized camera coordinates, - * e.g. x_camera = inv(K) * x_image - * \param X_world 3D points in the world coordinate system - * \param R Solution for the camera rotation matrix - * \param t Solution for the camera translation vector - * - * Straight from the paper: - * http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf - */ -bool EuclideanResectionPPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t); - -} // namespace euclidean_resection -} // namespace libmv - - -#endif /* LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ */ diff --git a/extern/libmv/libmv/multiview/euclidean_resection_test.cc b/extern/libmv/libmv/multiview/euclidean_resection_test.cc deleted file mode 100644 index 5ec9dbda3cf..00000000000 --- a/extern/libmv/libmv/multiview/euclidean_resection_test.cc +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/multiview/euclidean_resection.h" -#include "libmv/numeric/numeric.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/projection.h" -#include "testing/testing.h" - -using namespace libmv::euclidean_resection; -using namespace libmv; - -// Generates all necessary inputs and expected outputs for EuclideanResection. -void CreateCameraSystem(const Mat3& KK, - const Mat3X& x_image, - const Vec& X_distances, - const Mat3& R_input, - const Vec3& T_input, - Mat2X *x_camera, - Mat3X *X_world, - Mat3 *R_expected, - Vec3 *T_expected) { - int num_points = x_image.cols(); - - Mat3X x_unit_cam(3, num_points); - x_unit_cam = KK.inverse() * x_image; - - // Create normalized camera coordinates to be used as an input to the PnP - // function, instead of using NormalizeColumnVectors(&x_unit_cam). - *x_camera = x_unit_cam.block(0, 0, 2, num_points); - for (int i = 0; i < num_points; ++i) { - x_unit_cam.col(i).normalize(); - } - - // Create the 3D points in the camera system. - Mat X_camera(3, num_points); - for (int i = 0; i < num_points; ++i) { - X_camera.col(i) = X_distances(i) * x_unit_cam.col(i); - } - - // Apply the transformation to the camera 3D points - Mat translation_matrix(3, num_points); - translation_matrix.row(0).setConstant(T_input(0)); - translation_matrix.row(1).setConstant(T_input(1)); - translation_matrix.row(2).setConstant(T_input(2)); - - *X_world = R_input * X_camera + translation_matrix; - - // Create the expected result for comparison. - *R_expected = R_input.transpose(); - *T_expected = *R_expected * (-T_input); -}; - -TEST(AbsoluteOrientation, QuaternionSolution) { - int num_points = 4; - Mat X; - Mat Xp; - X = 100 * Mat::Random(3, num_points); - - // Create a random translation and rotation. - Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); - - Vec3 t_input; - t_input.setRandom(); - t_input = 100 * t_input; - - Mat translation_matrix(3, num_points); - translation_matrix.row(0).setConstant(t_input(0)); - translation_matrix.row(1).setConstant(t_input(1)); - translation_matrix.row(2).setConstant(t_input(2)); - - // Create the transformed 3D points Xp as Xp = R * X + t. - Xp = R_input * X + translation_matrix; - - // Output variables. - Mat3 R; - Vec3 t; - - AbsoluteOrientation(X, Xp, &R, &t); - - EXPECT_MATRIX_NEAR(t, t_input, 1e-6); - EXPECT_MATRIX_NEAR(R, R_input, 1e-8); -} - -TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { - // In this test only the translation and rotation are random. The image - // points are selected from a real case and are well conditioned. - Vec2i image_dimensions; - image_dimensions << 1600, 1200; - - Mat3 KK; - KK << 2796, 0, 804, - 0 , 2796, 641, - 0, 0, 1; - - // The real image points. - int num_points = 4; - Mat3X x_image(3, num_points); - x_image << 1164.06, 734.948, 749.599, 430.727, - 681.386, 844.59, 496.315, 580.775, - 1, 1, 1, 1; - - - // A vector of the 4 distances to the 3D points. - Vec X_distances = 100 * Vec::Random(num_points).array().abs(); - - // Create the random camera motion R and t that resection should recover. - Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); - - Vec3 T_input; - T_input.setRandom(); - T_input = 100 * T_input; - - // Create the camera system, also getting the expected result of the - // transformation. - Mat3 R_expected; - Vec3 T_expected; - Mat3X X_world; - Mat2X x_camera; - CreateCameraSystem(KK, x_image, X_distances, R_input, T_input, - &x_camera, &X_world, &R_expected, &T_expected); - - // Finally, run the code under test. - Mat3 R_output; - Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_ANSAR_DANIILIDIS); - - EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); - EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); - - // For now, the EPnP doesn't have a non-linear optimization step and so is - // not precise enough with only 4 points. - // - // TODO(jmichot): Reenable this test when there is nonlinear refinement. -#if 0 - R_output.setIdentity(); - T_output.setZero(); - - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_EPNP); - - EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); - EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);*/ -#endif -} - -// TODO(jmichot): Reduce the code duplication here with the code above. -TEST(EuclideanResection, Points6AllRandomInput) { - Mat3 KK; - KK << 2796, 0, 804, - 0 , 2796, 641, - 0, 0, 1; - - // Create random image points for a 1600x1200 image. - int w = 1600; - int h = 1200; - int num_points = 6; - Mat3X x_image(3, num_points); - x_image.row(0) = w * Vec::Random(num_points).array().abs(); - x_image.row(1) = h * Vec::Random(num_points).array().abs(); - x_image.row(2).setOnes(); - - // Normalized camera coordinates to be used as an input to the PnP function. - Mat2X x_camera; - Vec X_distances = 100 * Vec::Random(num_points).array().abs(); - - // Create the random camera motion R and t that resection should recover. - Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); - - Vec3 T_input; - T_input.setRandom(); - T_input = 100 * T_input; - - // Create the camera system. - Mat3 R_expected; - Vec3 T_expected; - Mat3X X_world; - CreateCameraSystem(KK, x_image, X_distances, R_input, T_input, - &x_camera, &X_world, &R_expected, &T_expected); - - // Test each of the resection methods. - { - Mat3 R_output; - Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_ANSAR_DANIILIDIS); - EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); - EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); - } - { - Mat3 R_output; - Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_EPNP); - EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); - EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); - } - { - Mat3 R_output; - Vec3 T_output; - EuclideanResection(x_image, X_world, KK, - &R_output, &T_output); - EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); - EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); - } -} diff --git a/extern/libmv/libmv/multiview/fundamental.cc b/extern/libmv/libmv/multiview/fundamental.cc deleted file mode 100644 index ea8594c8cc0..00000000000 --- a/extern/libmv/libmv/multiview/fundamental.cc +++ /dev/null @@ -1,544 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/multiview/fundamental.h" - -#include "ceres/ceres.h" -#include "libmv/logging/logging.h" -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/poly.h" -#include "libmv/multiview/conditioning.h" -#include "libmv/multiview/projection.h" -#include "libmv/multiview/triangulation.h" - -namespace libmv { - -static void EliminateRow(const Mat34 &P, int row, Mat *X) { - X->resize(2, 4); - - int first_row = (row + 1) % 3; - int second_row = (row + 2) % 3; - - for (int i = 0; i < 4; ++i) { - (*X)(0, i) = P(first_row, i); - (*X)(1, i) = P(second_row, i); - } -} - -void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2) { - *P1 << Mat3::Identity(), Vec3::Zero(); - Vec3 e2; - Mat3 Ft = F.transpose(); - Nullspace(&Ft, &e2); - *P2 << CrossProductMatrix(e2) * F, e2; -} - -// Addapted from vgg_F_from_P. -void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F) { - Mat X[3]; - Mat Y[3]; - Mat XY; - - for (int i = 0; i < 3; ++i) { - EliminateRow(P1, i, X + i); - EliminateRow(P2, i, Y + i); - } - - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - VerticalStack(X[j], Y[i], &XY); - (*F)(i, j) = XY.determinant(); - } - } -} - -// HZ 11.1 pag.279 (x1 = x, x2 = x') -// http://www.cs.unc.edu/~marc/tutorial/node54.html -static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) { - DCHECK_EQ(x1.rows(), 2); - DCHECK_GE(x1.cols(), 8); - DCHECK_EQ(x1.rows(), x2.rows()); - DCHECK_EQ(x1.cols(), x2.cols()); - - int n = x1.cols(); - Mat A(n, 9); - for (int i = 0; i < n; ++i) { - A(i, 0) = x2(0, i) * x1(0, i); - A(i, 1) = x2(0, i) * x1(1, i); - A(i, 2) = x2(0, i); - A(i, 3) = x2(1, i) * x1(0, i); - A(i, 4) = x2(1, i) * x1(1, i); - A(i, 5) = x2(1, i); - A(i, 6) = x1(0, i); - A(i, 7) = x1(1, i); - A(i, 8) = 1; - } - - Vec9 f; - double smaller_singular_value = Nullspace(&A, &f); - *F = Map(f.data()); - return smaller_singular_value; -} - -// HZ 11.1.1 pag.280 -void EnforceFundamentalRank2Constraint(Mat3 *F) { - Eigen::JacobiSVD USV(*F, Eigen::ComputeFullU | Eigen::ComputeFullV); - Vec3 d = USV.singularValues(); - d(2) = 0.0; - *F = USV.matrixU() * d.asDiagonal() * USV.matrixV().transpose(); -} - -// HZ 11.2 pag.281 (x1 = x, x2 = x') -double NormalizedEightPointSolver(const Mat &x1, - const Mat &x2, - Mat3 *F) { - DCHECK_EQ(x1.rows(), 2); - DCHECK_GE(x1.cols(), 8); - DCHECK_EQ(x1.rows(), x2.rows()); - DCHECK_EQ(x1.cols(), x2.cols()); - - // Normalize the data. - Mat3 T1, T2; - PreconditionerFromPoints(x1, &T1); - PreconditionerFromPoints(x2, &T2); - Mat x1_normalized, x2_normalized; - ApplyTransformationToPoints(x1, T1, &x1_normalized); - ApplyTransformationToPoints(x2, T2, &x2_normalized); - - // Estimate the fundamental matrix. - double smaller_singular_value = - EightPointSolver(x1_normalized, x2_normalized, F); - EnforceFundamentalRank2Constraint(F); - - // Denormalize the fundamental matrix. - *F = T2.transpose() * (*F) * T1; - - return smaller_singular_value; -} - -// Seven-point algorithm. -// http://www.cs.unc.edu/~marc/tutorial/node55.html -double FundamentalFrom7CorrespondencesLinear(const Mat &x1, - const Mat &x2, - std::vector *F) { - DCHECK_EQ(x1.rows(), 2); - DCHECK_EQ(x1.cols(), 7); - DCHECK_EQ(x1.rows(), x2.rows()); - DCHECK_EQ(x2.cols(), x2.cols()); - - // Build a 9 x n matrix from point matches, where each row is equivalent to - // the equation x'T*F*x = 0 for a single correspondence pair (x', x). The - // domain of the matrix is a 9 element vector corresponding to F. The - // nullspace should be rank two; the two dimensions correspond to the set of - // F matrices satisfying the epipolar geometry. - Matrix A; - for (int ii = 0; ii < 7; ++ii) { - A(ii, 0) = x1(0, ii) * x2(0, ii); // 0 represents x coords, - A(ii, 1) = x1(1, ii) * x2(0, ii); // 1 represents y coords. - A(ii, 2) = x2(0, ii); - A(ii, 3) = x1(0, ii) * x2(1, ii); - A(ii, 4) = x1(1, ii) * x2(1, ii); - A(ii, 5) = x2(1, ii); - A(ii, 6) = x1(0, ii); - A(ii, 7) = x1(1, ii); - A(ii, 8) = 1.0; - } - - // Find the two F matrices in the nullspace of A. - Vec9 f1, f2; - double s = Nullspace2(&A, &f1, &f2); - Mat3 F1 = Map(f1.data()); - Mat3 F2 = Map(f2.data()); - - // Then, use the condition det(F) = 0 to determine F. In other words, solve - // det(F1 + a*F2) = 0 for a. - double a = F1(0, 0), j = F2(0, 0), - b = F1(0, 1), k = F2(0, 1), - c = F1(0, 2), l = F2(0, 2), - d = F1(1, 0), m = F2(1, 0), - e = F1(1, 1), n = F2(1, 1), - f = F1(1, 2), o = F2(1, 2), - g = F1(2, 0), p = F2(2, 0), - h = F1(2, 1), q = F2(2, 1), - i = F1(2, 2), r = F2(2, 2); - - // Run fundamental_7point_coeffs.py to get the below coefficients. - // The coefficients are in ascending powers of alpha, i.e. P[N]*x^N. - double P[4] = { - a*e*i + b*f*g + c*d*h - a*f*h - b*d*i - c*e*g, - a*e*r + a*i*n + b*f*p + b*g*o + c*d*q + c*h*m + d*h*l + e*i*j + f*g*k - - a*f*q - a*h*o - b*d*r - b*i*m - c*e*p - c*g*n - d*i*k - e*g*l - f*h*j, - a*n*r + b*o*p + c*m*q + d*l*q + e*j*r + f*k*p + g*k*o + h*l*m + i*j*n - - a*o*q - b*m*r - c*n*p - d*k*r - e*l*p - f*j*q - g*l*n - h*j*o - i*k*m, - j*n*r + k*o*p + l*m*q - j*o*q - k*m*r - l*n*p, - }; - - // Solve for the roots of P[3]*x^3 + P[2]*x^2 + P[1]*x + P[0] = 0. - double roots[3]; - int num_roots = SolveCubicPolynomial(P, roots); - - // Build the fundamental matrix for each solution. - for (int kk = 0; kk < num_roots; ++kk) { - F->push_back(F1 + roots[kk] * F2); - } - return s; -} - -double FundamentalFromCorrespondences7Point(const Mat &x1, - const Mat &x2, - std::vector *F) { - DCHECK_EQ(x1.rows(), 2); - DCHECK_GE(x1.cols(), 7); - DCHECK_EQ(x1.rows(), x2.rows()); - DCHECK_EQ(x1.cols(), x2.cols()); - - // Normalize the data. - Mat3 T1, T2; - PreconditionerFromPoints(x1, &T1); - PreconditionerFromPoints(x2, &T2); - Mat x1_normalized, x2_normalized; - ApplyTransformationToPoints(x1, T1, &x1_normalized); - ApplyTransformationToPoints(x2, T2, &x2_normalized); - - // Estimate the fundamental matrix. - double smaller_singular_value = - FundamentalFrom7CorrespondencesLinear(x1_normalized, x2_normalized, &(*F)); - - for (int k = 0; k < F->size(); ++k) { - Mat3 & Fmat = (*F)[k]; - // Denormalize the fundamental matrix. - Fmat = T2.transpose() * Fmat * T1; - } - return smaller_singular_value; -} - -void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized) { - *F_normalized = F / FrobeniusNorm(F); - if ((*F_normalized)(2, 2) < 0) { - *F_normalized *= -1; - } -} - -double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { - Vec3 x(x1(0), x1(1), 1.0); - Vec3 y(x2(0), x2(1), 1.0); - - Vec3 F_x = F * x; - Vec3 Ft_y = F.transpose() * y; - double y_F_x = y.dot(F_x); - - return Square(y_F_x) / ( F_x.head<2>().squaredNorm() - + Ft_y.head<2>().squaredNorm()); -} - -double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { - Vec3 x(x1(0), x1(1), 1.0); - Vec3 y(x2(0), x2(1), 1.0); - - Vec3 F_x = F * x; - Vec3 Ft_y = F.transpose() * y; - double y_F_x = y.dot(F_x); - - return Square(y_F_x) * ( 1 / F_x.head<2>().squaredNorm() - + 1 / Ft_y.head<2>().squaredNorm()); -} - -// HZ 9.6 pag 257 (formula 9.12) -void EssentialFromFundamental(const Mat3 &F, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *E) { - *E = K2.transpose() * F * K1; -} - -// HZ 9.6 pag 257 (formula 9.12) -// Or http://ai.stanford.edu/~birch/projective/node20.html -void FundamentalFromEssential(const Mat3 &E, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *F) { - *F = K2.inverse().transpose() * E * K1.inverse(); -} - -void RelativeCameraMotion(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *R, - Vec3 *t) { - *R = R2 * R1.transpose(); - *t = t2 - (*R) * t1; -} - -// HZ 9.6 pag 257 -void EssentialFromRt(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *E) { - Mat3 R; - Vec3 t; - RelativeCameraMotion(R1, t1, R2, t2, &R, &t); - Mat3 Tx = CrossProductMatrix(t); - *E = Tx * R; -} - -// HZ 9.6 pag 259 (Result 9.19) -void MotionFromEssential(const Mat3 &E, - std::vector *Rs, - std::vector *ts) { - Eigen::JacobiSVD USV(E, Eigen::ComputeFullU | Eigen::ComputeFullV); - Mat3 U = USV.matrixU(); - Mat3 Vt = USV.matrixV().transpose(); - - // Last column of U is undetermined since d = (a a 0). - if (U.determinant() < 0) { - U.col(2) *= -1; - } - // Last row of Vt is undetermined since d = (a a 0). - if (Vt.determinant() < 0) { - Vt.row(2) *= -1; - } - - Mat3 W; - W << 0, -1, 0, - 1, 0, 0, - 0, 0, 1; - - Mat3 U_W_Vt = U * W * Vt; - Mat3 U_Wt_Vt = U * W.transpose() * Vt; - - Rs->resize(4); - (*Rs)[0] = U_W_Vt; - (*Rs)[1] = U_W_Vt; - (*Rs)[2] = U_Wt_Vt; - (*Rs)[3] = U_Wt_Vt; - - ts->resize(4); - (*ts)[0] = U.col(2); - (*ts)[1] = -U.col(2); - (*ts)[2] = U.col(2); - (*ts)[3] = -U.col(2); -} - -int MotionFromEssentialChooseSolution(const std::vector &Rs, - const std::vector &ts, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2) { - DCHECK_EQ(4, Rs.size()); - DCHECK_EQ(4, ts.size()); - - Mat34 P1, P2; - Mat3 R1; - Vec3 t1; - R1.setIdentity(); - t1.setZero(); - P_From_KRt(K1, R1, t1, &P1); - for (int i = 0; i < 4; ++i) { - const Mat3 &R2 = Rs[i]; - const Vec3 &t2 = ts[i]; - P_From_KRt(K2, R2, t2, &P2); - Vec3 X; - TriangulateDLT(P1, x1, P2, x2, &X); - double d1 = Depth(R1, t1, X); - double d2 = Depth(R2, t2, X); - // Test if point is front to the two cameras. - if (d1 > 0 && d2 > 0) { - return i; - } - } - return -1; -} - -bool MotionFromEssentialAndCorrespondence(const Mat3 &E, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2, - Mat3 *R, - Vec3 *t) { - std::vector Rs; - std::vector ts; - MotionFromEssential(E, &Rs, &ts); - int solution = MotionFromEssentialChooseSolution(Rs, ts, K1, x1, K2, x2); - if (solution >= 0) { - *R = Rs[solution]; - *t = ts[solution]; - return true; - } else { - return false; - } -} - -void FundamentalToEssential(const Mat3 &F, Mat3 *E) { - Eigen::JacobiSVD svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV); - - // See Hartley & Zisserman page 294, result 11.1, which shows how to get the - // closest essential matrix to a matrix that is "almost" an essential matrix. - double a = svd.singularValues()(0); - double b = svd.singularValues()(1); - double s = (a + b) / 2.0; - - LG << "Initial reconstruction's rotation is non-euclidean by " - << (((a - b) / std::max(a, b)) * 100) << "%; singular values:" - << svd.singularValues().transpose(); - - Vec3 diag; - diag << s, s, 0; - - *E = svd.matrixU() * diag.asDiagonal() * svd.matrixV().transpose(); -} - -// Default settings for fundamental estimation which should be suitable -// for a wide range of use cases. -EstimateFundamentalOptions::EstimateFundamentalOptions(void) : - max_num_iterations(50), - expected_average_symmetric_distance(1e-16) { -} - -namespace { -// Cost functor which computes symmetric epipolar distance -// used for fundamental matrix refinement. -class FundamentalSymmetricEpipolarCostFunctor { - public: - FundamentalSymmetricEpipolarCostFunctor(const Vec2 &x, - const Vec2 &y) - : x_(x), y_(y) {} - - template - bool operator()(const T *fundamental_parameters, T *residuals) const { - typedef Eigen::Matrix Mat3; - typedef Eigen::Matrix 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_; -}; - -// Termination checking callback used for fundamental estimation. -// It finished the minimization as soon as actual average of -// symmetric epipolar distance is less or equal to the expected -// average value. -class TerminationCheckingCallback : public ceres::IterationCallback { - public: - TerminationCheckingCallback(const Mat &x1, const Mat &x2, - const EstimateFundamentalOptions &options, - Mat3 *F) - : options_(options), x1_(x1), x2_(x2), F_(F) {} - - virtual ceres::CallbackReturnType operator()( - const ceres::IterationSummary& summary) { - // If the step wasn't successful, there's nothing to do. - if (!summary.step_is_successful) { - return ceres::SOLVER_CONTINUE; - } - - // Calculate average of symmetric epipolar distance. - double average_distance = 0.0; - for (int i = 0; i < x1_.cols(); i++) { - average_distance = SymmetricEpipolarDistance(*F_, - x1_.col(i), - x2_.col(i)); - } - average_distance /= x1_.cols(); - - if (average_distance <= options_.expected_average_symmetric_distance) { - return ceres::SOLVER_TERMINATE_SUCCESSFULLY; - } - - return ceres::SOLVER_CONTINUE; - } - - private: - const EstimateFundamentalOptions &options_; - const Mat &x1_; - const Mat &x2_; - Mat3 *F_; -}; -} // namespace - -/* Fundamental transformation estimation. */ -bool EstimateFundamentalFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateFundamentalOptions &options, - Mat3 *F) { - // Step 1: Algebraic fundamental estimation. - - // Assume algebraic estiation always succeeds, - NormalizedEightPointSolver(x1, x2, F); - - LG << "Estimated matrix after algebraic estimation:\n" << *F; - - // 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; - - // Terminate if the average symmetric distance is good enough. - TerminationCheckingCallback callback(x1, x2, options, F); - solver_options.callbacks.push_back(&callback); - - // 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.IsSolutionUsable(); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/multiview/fundamental.h b/extern/libmv/libmv/multiview/fundamental.h deleted file mode 100644 index 51067aefc2b..00000000000 --- a/extern/libmv/libmv/multiview/fundamental.h +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2007, 2008, 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_FUNDAMENTAL_H_ -#define LIBMV_MULTIVIEW_FUNDAMENTAL_H_ - -#include - -#include "libmv/numeric/numeric.h" - -namespace libmv { - -void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2); -void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F); - -/** - * The normalized 8-point fundamental matrix solver. - */ -double NormalizedEightPointSolver(const Mat &x1, - const Mat &x2, - Mat3 *F); - -/** - * 7 points (minimal case, points coordinates must be normalized before): - */ -double FundamentalFrom7CorrespondencesLinear(const Mat &x1, - const Mat &x2, - std::vector *F); - -/** - * 7 points (points coordinates must be in image space): - */ -double FundamentalFromCorrespondences7Point(const Mat &x1, - const Mat &x2, - std::vector *F); - -/** - * 8 points (points coordinates must be in image space): - */ -double NormalizedEightPointSolver(const Mat &x1, - const Mat &x2, - Mat3 *F); - -/** - * Fundamental matrix utility function: - */ -void EnforceFundamentalRank2Constraint(Mat3 *F); - -void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized); - -/** - * Approximate squared reprojection errror. - * - * See page 287 of HZ equation 11.9. This avoids triangulating the point, - * relying only on the entries in F. - */ -double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2); - -/** - * Calculates the sum of the distances from the points to the epipolar lines. - * - * See page 288 of HZ equation 11.10. - */ -double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2); - -/** - * Compute the relative camera motion between two cameras. - * - * Given the motion parameters of two cameras, computes the motion parameters - * of the second one assuming the first one to be at the origin. - * If T1 and T2 are the camera motions, the computed relative motion is - * T = T2 T1^{-1} - */ -void RelativeCameraMotion(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *R, - Vec3 *t); - -void EssentialFromFundamental(const Mat3 &F, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *E); - -void FundamentalFromEssential(const Mat3 &E, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *F); - -void EssentialFromRt(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *E); - -void MotionFromEssential(const Mat3 &E, - std::vector *Rs, - std::vector *ts); - -/** - * Choose one of the four possible motion solutions from an essential matrix. - * - * Decides the right solution by checking that the triangulation of a match - * x1--x2 lies in front of the cameras. See HZ 9.6 pag 259 (9.6.3 Geometrical - * interpretation of the 4 solutions) - * - * \return index of the right solution or -1 if no solution. - */ -int MotionFromEssentialChooseSolution(const std::vector &Rs, - const std::vector &ts, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2); - -bool MotionFromEssentialAndCorrespondence(const Mat3 &E, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2, - Mat3 *R, - Vec3 *t); - -/** - * Find closest essential matrix E to fundamental F - */ -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 EstimateFundamentalOptions { - // Default constructor which sets up a options for generic usage. - EstimateFundamentalOptions(void); - - // Maximal number of iterations for refinement step. - int max_num_iterations; - - // Expected average of symmetric epipolar distance between - // actual destination points and original ones transformed by - // estimated fundamental matrix. - // - // Refinement will finish as soon as average of symmetric - // epipolar distance is less or equal to this value. - // - // This distance is measured in the same units as input points are. - double expected_average_symmetric_distance; -}; - -/** - * 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 EstimateFundamentalFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateFundamentalOptions &options, - Mat3 *F); - -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_FUNDAMENTAL_H_ diff --git a/extern/libmv/libmv/multiview/fundamental_test.cc b/extern/libmv/libmv/multiview/fundamental_test.cc deleted file mode 100644 index da0eb449b8f..00000000000 --- a/extern/libmv/libmv/multiview/fundamental_test.cc +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include - -#include "libmv/logging/logging.h" -#include "libmv/multiview/conditioning.h" -#include "libmv/multiview/fundamental.h" -#include "libmv/multiview/projection.h" -#include "libmv/multiview/test_data_sets.h" -#include "libmv/numeric/numeric.h" -#include "testing/testing.h" - -namespace { - -using namespace libmv; - -TEST(Fundamental, FundamentalFromProjections) { - Mat34 P1_gt, P2_gt; - P1_gt << 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0; - P2_gt << 1, 1, 1, 3, - 0, 2, 0, 3, - 0, 1, 1, 0; - Mat3 F_gt; - FundamentalFromProjections(P1_gt, P2_gt, &F_gt); - - Mat34 P1, P2; - ProjectionsFromFundamental(F_gt, &P1, &P2); - - Mat3 F; - FundamentalFromProjections(P1, P2, &F); - - EXPECT_MATRIX_PROP(F_gt, F, 1e-6); -} - -TEST(Fundamental, PreconditionerFromPoints) { - int n = 4; - Mat points(2, n); - points << 0, 0, 1, 1, - 0, 2, 1, 3; - - Mat3 T; - PreconditionerFromPoints(points, &T); - - Mat normalized_points; - ApplyTransformationToPoints(points, T, &normalized_points); - - Vec mean, variance; - MeanAndVarianceAlongRows(normalized_points, &mean, &variance); - - EXPECT_NEAR(0, mean(0), 1e-8); - EXPECT_NEAR(0, mean(1), 1e-8); - EXPECT_NEAR(2, variance(0), 1e-8); - EXPECT_NEAR(2, variance(1), 1e-8); -} - -TEST(Fundamental, EssentialFromFundamental) { - TwoViewDataSet d = TwoRealisticCameras(); - - Mat3 E_from_Rt; - EssentialFromRt(d.R1, d.t1, d.R2, d.t2, &E_from_Rt); - - Mat3 E_from_F; - EssentialFromFundamental(d.F, d.K1, d.K2, &E_from_F); - - EXPECT_MATRIX_PROP(E_from_Rt, E_from_F, 1e-6); -} - -TEST(Fundamental, MotionFromEssential) { - TwoViewDataSet d = TwoRealisticCameras(); - - Mat3 E; - EssentialFromRt(d.R1, d.t1, d.R2, d.t2, &E); - - Mat3 R; - Vec3 t; - RelativeCameraMotion(d.R1, d.t1, d.R2, d.t2, &R, &t); - NormalizeL2(&t); - - std::vector Rs; - std::vector ts; - MotionFromEssential(E, &Rs, &ts); - bool one_solution_is_correct = false; - for (size_t i = 0; i < Rs.size(); ++i) { - if (FrobeniusDistance(Rs[i], R) < 1e-8 && DistanceL2(ts[i], t) < 1e-8) { - one_solution_is_correct = true; - break; - } - } - EXPECT_TRUE(one_solution_is_correct); -} - -TEST(Fundamental, MotionFromEssentialChooseSolution) { - TwoViewDataSet d = TwoRealisticCameras(); - - Mat3 E; - EssentialFromRt(d.R1, d.t1, d.R2, d.t2, &E); - - Mat3 R; - Vec3 t; - RelativeCameraMotion(d.R1, d.t1, d.R2, d.t2, &R, &t); - NormalizeL2(&t); - - std::vector Rs; - std::vector ts; - MotionFromEssential(E, &Rs, &ts); - - Vec2 x1, x2; - MatrixColumn(d.x1, 0, &x1); - MatrixColumn(d.x2, 0, &x2); - int solution = MotionFromEssentialChooseSolution(Rs, ts, d.K1, x1, d.K2, x2); - - EXPECT_LE(0, solution); - EXPECT_LE(solution, 3); - EXPECT_LE(FrobeniusDistance(Rs[solution], R), 1e-8); - EXPECT_LE(DistanceL2(ts[solution], t), 1e-8); -} - -TEST(Fundamental, MotionFromEssentialAndCorrespondence) { - TwoViewDataSet d = TwoRealisticCameras(); - - Mat3 E; - EssentialFromRt(d.R1, d.t1, d.R2, d.t2, &E); - - Mat3 R; - Vec3 t; - RelativeCameraMotion(d.R1, d.t1, d.R2, d.t2, &R, &t); - NormalizeL2(&t); - - Vec2 x1, x2; - MatrixColumn(d.x1, 0, &x1); - MatrixColumn(d.x2, 0, &x2); - - Mat3 R_estimated; - Vec3 t_estimated; - MotionFromEssentialAndCorrespondence(E, d.K1, x1, d.K2, x2, - &R_estimated, &t_estimated); - - EXPECT_LE(FrobeniusDistance(R_estimated, R), 1e-8); - EXPECT_LE(DistanceL2(t_estimated, t), 1e-8); -} - -} // namespace diff --git a/extern/libmv/libmv/multiview/homography.cc b/extern/libmv/libmv/multiview/homography.cc deleted file mode 100644 index ce533a3ead2..00000000000 --- a/extern/libmv/libmv/multiview/homography.cc +++ /dev/null @@ -1,465 +0,0 @@ -// Copyright (c) 2008, 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/multiview/homography.h" - -#include "ceres/ceres.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/conditioning.h" -#include "libmv/multiview/homography_parameterization.h" - -namespace libmv { -/** 2D Homography transformation estimation in the case that points are in - * euclidean coordinates. - * - * x = H y - * x and y vector must have the same direction, we could write - * crossproduct(|x|, * H * |y| ) = |0| - * - * | 0 -1 x2| |a b c| |y1| |0| - * | 1 0 -x1| * |d e f| * |y2| = |0| - * |-x2 x1 0| |g h 1| |1 | |0| - * - * That gives : - * - * (-d+x2*g)*y1 + (-e+x2*h)*y2 + -f+x2 |0| - * (a-x1*g)*y1 + (b-x1*h)*y2 + c-x1 = |0| - * (-x2*a+x1*d)*y1 + (-x2*b+x1*e)*y2 + -x2*c+x1*f |0| - */ -static bool Homography2DFromCorrespondencesLinearEuc( - const Mat &x1, - const Mat &x2, - Mat3 *H, - double expected_precision) { - assert(2 == x1.rows()); - assert(4 <= x1.cols()); - assert(x1.rows() == x2.rows()); - assert(x1.cols() == x2.cols()); - - int n = x1.cols(); - MatX8 L = Mat::Zero(n * 3, 8); - Mat b = Mat::Zero(n * 3, 1); - for (int i = 0; i < n; ++i) { - int j = 3 * i; - L(j, 0) = x1(0, i); // a - L(j, 1) = x1(1, i); // b - L(j, 2) = 1.0; // c - L(j, 6) = -x2(0, i) * x1(0, i); // g - L(j, 7) = -x2(0, i) * x1(1, i); // h - b(j, 0) = x2(0, i); // i - - ++j; - L(j, 3) = x1(0, i); // d - L(j, 4) = x1(1, i); // e - L(j, 5) = 1.0; // f - L(j, 6) = -x2(1, i) * x1(0, i); // g - L(j, 7) = -x2(1, i) * x1(1, i); // h - b(j, 0) = x2(1, i); // i - - // This ensures better stability - // TODO(julien) make a lite version without this 3rd set - ++j; - L(j, 0) = x2(1, i) * x1(0, i); // a - L(j, 1) = x2(1, i) * x1(1, i); // b - L(j, 2) = x2(1, i); // c - L(j, 3) = -x2(0, i) * x1(0, i); // d - L(j, 4) = -x2(0, i) * x1(1, i); // e - L(j, 5) = -x2(0, i); // f - } - // Solve Lx=B - Vec h = L.fullPivLu().solve(b); - Homography2DNormalizedParameterization::To(h, H); - if ((L * h).isApprox(b, expected_precision)) { - return true; - } else { - return false; - } -} - -/** 2D Homography transformation estimation in the case that points are in - * homogeneous coordinates. - * - * | 0 -x3 x2| |a b c| |y1| -x3*d+x2*g -x3*e+x2*h -x3*f+x2*1 |y1| (-x3*d+x2*g)*y1 (-x3*e+x2*h)*y2 (-x3*f+x2*1)*y3 |0| - * | x3 0 -x1| * |d e f| * |y2| = x3*a-x1*g x3*b-x1*h x3*c-x1*1 * |y2| = (x3*a-x1*g)*y1 (x3*b-x1*h)*y2 (x3*c-x1*1)*y3 = |0| - * |-x2 x1 0| |g h 1| |y3| -x2*a+x1*d -x2*b+x1*e -x2*c+x1*f |y3| (-x2*a+x1*d)*y1 (-x2*b+x1*e)*y2 (-x2*c+x1*f)*y3 |0| - * X = |a b c d e f g h|^t - */ -bool Homography2DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat3 *H, - double expected_precision) { - if (x1.rows() == 2) { - return Homography2DFromCorrespondencesLinearEuc(x1, x2, H, - expected_precision); - } - assert(3 == x1.rows()); - assert(4 <= x1.cols()); - assert(x1.rows() == x2.rows()); - assert(x1.cols() == x2.cols()); - - const int x = 0; - const int y = 1; - const int w = 2; - int n = x1.cols(); - MatX8 L = Mat::Zero(n * 3, 8); - Mat b = Mat::Zero(n * 3, 1); - for (int i = 0; i < n; ++i) { - int j = 3 * i; - L(j, 0) = x2(w, i) * x1(x, i); // a - L(j, 1) = x2(w, i) * x1(y, i); // b - L(j, 2) = x2(w, i) * x1(w, i); // c - L(j, 6) = -x2(x, i) * x1(x, i); // g - L(j, 7) = -x2(x, i) * x1(y, i); // h - b(j, 0) = x2(x, i) * x1(w, i); - - ++j; - L(j, 3) = x2(w, i) * x1(x, i); // d - L(j, 4) = x2(w, i) * x1(y, i); // e - L(j, 5) = x2(w, i) * x1(w, i); // f - L(j, 6) = -x2(y, i) * x1(x, i); // g - L(j, 7) = -x2(y, i) * x1(y, i); // h - b(j, 0) = x2(y, i) * x1(w, i); - - // This ensures better stability - ++j; - L(j, 0) = x2(y, i) * x1(x, i); // a - L(j, 1) = x2(y, i) * x1(y, i); // b - L(j, 2) = x2(y, i) * x1(w, i); // c - L(j, 3) = -x2(x, i) * x1(x, i); // d - L(j, 4) = -x2(x, i) * x1(y, i); // e - L(j, 5) = -x2(x, i) * x1(w, i); // f - } - // Solve Lx=B - Vec h = L.fullPivLu().solve(b); - if ((L * h).isApprox(b, expected_precision)) { - Homography2DNormalizedParameterization::To(h, H); - return true; - } else { - return false; - } -} - -// Default settings for homography estimation which should be suitable -// for a wide range of use cases. -EstimateHomographyOptions::EstimateHomographyOptions(void) : - use_normalization(true), - max_num_iterations(50), - expected_average_symmetric_distance(1e-16) { -} - -namespace { -void GetNormalizedPoints(const Mat &original_points, - Mat *normalized_points, - Mat3 *normalization_matrix) { - IsotropicPreconditionerFromPoints(original_points, normalization_matrix); - ApplyTransformationToPoints(original_points, - *normalization_matrix, - normalized_points); -} - -// Cost functor which computes symmetric geometric distance -// used for homography matrix refinement. -class HomographySymmetricGeometricCostFunctor { - public: - HomographySymmetricGeometricCostFunctor(const Vec2 &x, - const Vec2 &y) - : x_(x), y_(y) { } - - template - bool operator()(const T *homography_parameters, T *residuals) const { - typedef Eigen::Matrix Mat3; - typedef Eigen::Matrix 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_; -}; - -// Termination checking callback used for homography estimation. -// It finished the minimization as soon as actual average of -// symmetric geometric distance is less or equal to the expected -// average value. -class TerminationCheckingCallback : public ceres::IterationCallback { - public: - TerminationCheckingCallback(const Mat &x1, const Mat &x2, - const EstimateHomographyOptions &options, - Mat3 *H) - : options_(options), x1_(x1), x2_(x2), H_(H) {} - - virtual ceres::CallbackReturnType operator()( - const ceres::IterationSummary& summary) { - // If the step wasn't successful, there's nothing to do. - if (!summary.step_is_successful) { - return ceres::SOLVER_CONTINUE; - } - - // Calculate average of symmetric geometric distance. - double average_distance = 0.0; - for (int i = 0; i < x1_.cols(); i++) { - average_distance = SymmetricGeometricDistance(*H_, - x1_.col(i), - x2_.col(i)); - } - average_distance /= x1_.cols(); - - if (average_distance <= options_.expected_average_symmetric_distance) { - return ceres::SOLVER_TERMINATE_SUCCESSFULLY; - } - - return ceres::SOLVER_CONTINUE; - } - - private: - const EstimateHomographyOptions &options_; - const Mat &x1_; - const Mat &x2_; - Mat3 *H_; -}; -} // namespace - -/** 2D Homography transformation estimation in the case that points are in - * euclidean coordinates. - */ -bool EstimateHomography2DFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateHomographyOptions &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()); - - Mat3 T1 = Mat3::Identity(), - T2 = Mat3::Identity(); - - // Step 1: Algebraic homography estimation. - Mat x1_normalized, x2_normalized; - - if (options.use_normalization) { - LG << "Estimating homography using normalization."; - GetNormalizedPoints(x1, &x1_normalized, &T1); - GetNormalizedPoints(x2, &x2_normalized, &T2); - } else { - x1_normalized = x1; - x2_normalized = x2; - } - - // Assume algebraic estiation always suceeds, - Homography2DFromCorrespondencesLinear(x1_normalized, x2_normalized, H); - - // Denormalize the homography matrix. - if (options.use_normalization) { - *H = T2.inverse() * (*H) * T1; - } - - LG << "Estimated matrix after algebraic estimation:\n" << *H; - - // 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; - - // Terminate if the average symmetric distance is good enough. - TerminationCheckingCallback callback(x1, x2, options, H); - solver_options.callbacks.push_back(&callback); - - // 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.IsSolutionUsable(); -} - -/** - * x2 ~ A * x1 - * x2^t * Hi * A *x1 = 0 - * H1 = H2 = H3 = - * | 0 0 0 1| |-x2w| |0 0 0 0| | 0 | | 0 0 1 0| |-x2z| - * | 0 0 0 0| -> | 0 | |0 0 1 0| -> |-x2z| | 0 0 0 0| -> | 0 | - * | 0 0 0 0| | 0 | |0-1 0 0| | x2y| |-1 0 0 0| | x2x| - * |-1 0 0 0| | x2x| |0 0 0 0| | 0 | | 0 0 0 0| | 0 | - * H4 = H5 = H6 = - * |0 0 0 0| | 0 | | 0 1 0 0| |-x2y| |0 0 0 0| | 0 | - * |0 0 0 1| -> |-x2w| |-1 0 0 0| -> | x2x| |0 0 0 0| -> | 0 | - * |0 0 0 0| | 0 | | 0 0 0 0| | 0 | |0 0 0 1| |-x2w| - * |0-1 0 0| | x2y| | 0 0 0 0| | 0 | |0 0-1 0| | x2z| - * |a b c d| - * A = |e f g h| - * |i j k l| - * |m n o 1| - * - * x2^t * H1 * A *x1 = (-x2w*a +x2x*m )*x1x + (-x2w*b +x2x*n )*x1y + (-x2w*c +x2x*o )*x1z + (-x2w*d +x2x*1 )*x1w = 0 - * x2^t * H2 * A *x1 = (-x2z*e +x2y*i )*x1x + (-x2z*f +x2y*j )*x1y + (-x2z*g +x2y*k )*x1z + (-x2z*h +x2y*l )*x1w = 0 - * x2^t * H3 * A *x1 = (-x2z*a +x2x*i )*x1x + (-x2z*b +x2x*j )*x1y + (-x2z*c +x2x*k )*x1z + (-x2z*d +x2x*l )*x1w = 0 - * x2^t * H4 * A *x1 = (-x2w*e +x2y*m )*x1x + (-x2w*f +x2y*n )*x1y + (-x2w*g +x2y*o )*x1z + (-x2w*h +x2y*1 )*x1w = 0 - * x2^t * H5 * A *x1 = (-x2y*a +x2x*e )*x1x + (-x2y*b +x2x*f )*x1y + (-x2y*c +x2x*g )*x1z + (-x2y*d +x2x*h )*x1w = 0 - * x2^t * H6 * A *x1 = (-x2w*i +x2z*m )*x1x + (-x2w*j +x2z*n )*x1y + (-x2w*k +x2z*o )*x1z + (-x2w*l +x2z*1 )*x1w = 0 - * - * X = |a b c d e f g h i j k l m n o|^t -*/ -bool Homography3DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat4 *H, - double expected_precision) { - assert(4 == x1.rows()); - assert(5 <= x1.cols()); - assert(x1.rows() == x2.rows()); - assert(x1.cols() == x2.cols()); - const int x = 0; - const int y = 1; - const int z = 2; - const int w = 3; - int n = x1.cols(); - MatX15 L = Mat::Zero(n * 6, 15); - Mat b = Mat::Zero(n * 6, 1); - for (int i = 0; i < n; ++i) { - int j = 6 * i; - L(j, 0) = -x2(w, i) * x1(x, i); // a - L(j, 1) = -x2(w, i) * x1(y, i); // b - L(j, 2) = -x2(w, i) * x1(z, i); // c - L(j, 3) = -x2(w, i) * x1(w, i); // d - L(j, 12) = x2(x, i) * x1(x, i); // m - L(j, 13) = x2(x, i) * x1(y, i); // n - L(j, 14) = x2(x, i) * x1(z, i); // o - b(j, 0) = -x2(x, i) * x1(w, i); - - ++j; - L(j, 4) = -x2(z, i) * x1(x, i); // e - L(j, 5) = -x2(z, i) * x1(y, i); // f - L(j, 6) = -x2(z, i) * x1(z, i); // g - L(j, 7) = -x2(z, i) * x1(w, i); // h - L(j, 8) = x2(y, i) * x1(x, i); // i - L(j, 9) = x2(y, i) * x1(y, i); // j - L(j, 10) = x2(y, i) * x1(z, i); // k - L(j, 11) = x2(y, i) * x1(w, i); // l - - ++j; - L(j, 0) = -x2(z, i) * x1(x, i); // a - L(j, 1) = -x2(z, i) * x1(y, i); // b - L(j, 2) = -x2(z, i) * x1(z, i); // c - L(j, 3) = -x2(z, i) * x1(w, i); // d - L(j, 8) = x2(x, i) * x1(x, i); // i - L(j, 9) = x2(x, i) * x1(y, i); // j - L(j, 10) = x2(x, i) * x1(z, i); // k - L(j, 11) = x2(x, i) * x1(w, i); // l - - ++j; - L(j, 4) = -x2(w, i) * x1(x, i); // e - L(j, 5) = -x2(w, i) * x1(y, i); // f - L(j, 6) = -x2(w, i) * x1(z, i); // g - L(j, 7) = -x2(w, i) * x1(w, i); // h - L(j, 12) = x2(y, i) * x1(x, i); // m - L(j, 13) = x2(y, i) * x1(y, i); // n - L(j, 14) = x2(y, i) * x1(z, i); // o - b(j, 0) = -x2(y, i) * x1(w, i); - - ++j; - L(j, 0) = -x2(y, i) * x1(x, i); // a - L(j, 1) = -x2(y, i) * x1(y, i); // b - L(j, 2) = -x2(y, i) * x1(z, i); // c - L(j, 3) = -x2(y, i) * x1(w, i); // d - L(j, 4) = x2(x, i) * x1(x, i); // e - L(j, 5) = x2(x, i) * x1(y, i); // f - L(j, 6) = x2(x, i) * x1(z, i); // g - L(j, 7) = x2(x, i) * x1(w, i); // h - - ++j; - L(j, 8) = -x2(w, i) * x1(x, i); // i - L(j, 9) = -x2(w, i) * x1(y, i); // j - L(j, 10) = -x2(w, i) * x1(z, i); // k - L(j, 11) = -x2(w, i) * x1(w, i); // l - L(j, 12) = x2(z, i) * x1(x, i); // m - L(j, 13) = x2(z, i) * x1(y, i); // n - L(j, 14) = x2(z, i) * x1(z, i); // o - b(j, 0) = -x2(z, i) * x1(w, i); - } - // Solve Lx=B - Vec h = L.fullPivLu().solve(b); - if ((L * h).isApprox(b, expected_precision)) { - Homography3DNormalizedParameterization::To(h, H); - return true; - } else { - return false; - } -} - -double SymmetricGeometricDistance(const Mat3 &H, - const Vec2 &x1, - const Vec2 &x2) { - Vec3 x(x1(0), x1(1), 1.0); - Vec3 y(x2(0), x2(1), 1.0); - - Vec3 H_x = H * x; - Vec3 Hinv_y = H.inverse() * y; - - H_x /= H_x(2); - Hinv_y /= Hinv_y(2); - - return (H_x.head<2>() - y.head<2>()).squaredNorm() + - (Hinv_y.head<2>() - x.head<2>()).squaredNorm(); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/multiview/homography.h b/extern/libmv/libmv/multiview/homography.h deleted file mode 100644 index 6d810c845ed..00000000000 --- a/extern/libmv/libmv/multiview/homography.h +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_HOMOGRAPHY_H_ -#define LIBMV_MULTIVIEW_HOMOGRAPHY_H_ - -#include "libmv/numeric/numeric.h" - -namespace libmv { - -/** - * 2D homography transformation estimation. - * - * This function estimates the homography transformation from a list of 2D - * correspondences which represents either: - * - * - 3D points on a plane, with a general moving camera. - * - 3D points with a rotating camera (pure rotation). - * - 3D points + different planar projections - * - * \param x1 The first 2xN or 3xN matrix of euclidean or homogeneous points. - * \param x2 The second 2xN or 3xN matrix of euclidean or homogeneous points. - * \param H The 3x3 homography transformation matrix (8 dof) such that - * x2 = H * x1 with |a b c| - * H = |d e f| - * |g h 1| - * \param expected_precision The expected precision in order for instance - * to accept almost homography matrices. - * - * \return True if the transformation estimation has succeeded. - * \note There must be at least 4 non-colinear points. - */ -bool Homography2DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat3 *H, - double expected_precision = - 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 EstimateHomographyOptions { - // Default constructor which sets up a options for generic usage. - EstimateHomographyOptions(void); - - // Normalize correspondencies before estimating the homography - // in order to increase estimation stability. - // - // Normaliztion will make it so centroid od correspondences - // is the coordinate origin and their average distance from - // the origin is sqrt(2). - // - // See: - // - R. Hartley and A. Zisserman. Multiple View Geometry in Computer - // Vision. Cambridge University Press, second edition, 2003. - // - https://www.cs.ubc.ca/grads/resources/thesis/May09/Dubrofsky_Elan.pdf - bool use_normalization; - - // Maximal number of iterations for the refinement step. - int max_num_iterations; - - // Expected average of symmetric geometric distance between - // actual destination points and original ones transformed by - // estimated homography matrix. - // - // Refinement will finish as soon as average of symmetric - // geometric distance is less or equal to this value. - // - // This distance is measured in the same units as input points are. - double expected_average_symmetric_distance; -}; - -/** - * 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 EstimateHomography2DFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateHomographyOptions &options, - Mat3 *H); - -/** - * 3D Homography transformation estimation. - * - * This function can be used in order to estimate the homography transformation - * from a list of 3D correspondences. - * - * \param[in] x1 The first 4xN matrix of homogeneous points - * \param[in] x2 The second 4xN matrix of homogeneous points - * \param[out] H The 4x4 homography transformation matrix (15 dof) such that - * x2 = H * x1 with |a b c d| - * H = |e f g h| - * |i j k l| - * |m n o 1| - * \param[in] expected_precision The expected precision in order for instance - * to accept almost homography matrices. - * - * \return true if the transformation estimation has succeeded - * - * \note Need at least 5 non coplanar points - * \note Points coordinates must be in homogeneous coordinates - */ -bool Homography3DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat4 *H, - double expected_precision = - EigenDouble::dummy_precision()); - -/** - * Calculate symmetric geometric cost: - * - * D(H * x1, x2)^2 + D(H^-1 * x2, x1) - */ -double SymmetricGeometricDistance(const Mat3 &H, - const Vec2 &x1, - const Vec2 &x2); - -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_HOMOGRAPHY_H_ diff --git a/extern/libmv/libmv/multiview/homography_error.h b/extern/libmv/libmv/multiview/homography_error.h deleted file mode 100644 index f8b9d45e73c..00000000000 --- a/extern/libmv/libmv/multiview/homography_error.h +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_HOMOGRAPHY_ERRORS_H_ -#define LIBMV_MULTIVIEW_HOMOGRAPHY_ERRORS_H_ - -#include "libmv/multiview/projection.h" - -namespace libmv { -namespace homography { -namespace homography2D { - - /** - * Structure for estimating the asymmetric error between a vector x2 and the - * transformed x1 such that - * Error = ||x2 - Psi(H * x1)||^2 - * where Psi is the function that transforms homogeneous to euclidean coords. - * \note It should be distributed as Chi-squared with k = 2. - */ -struct AsymmetricError { - /** - * Computes the asymmetric residuals between a set of 2D points x2 and the - * transformed 2D point set x1 such that - * Residuals_i = x2_i - Psi(H * x1_i) - * where Psi is the function that transforms homogeneous to euclidean coords. - * - * \param[in] H The 3x3 homography matrix. - * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A set of 2D points (2xN or 3xN matrix of column vectors). - * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). - * \param[out] dx A 2xN matrix of column vectors of residuals errors - */ - static void Residuals(const Mat &H, const Mat &x1, - const Mat &x2, Mat2X *dx) { - dx->resize(2, x1.cols()); - Mat3X x2h_est; - if (x1.rows() == 2) - x2h_est = H * EuclideanToHomogeneous(static_cast(x1)); - else - x2h_est = H * x1; - dx->row(0) = x2h_est.row(0).array() / x2h_est.row(2).array(); - dx->row(1) = x2h_est.row(1).array() / x2h_est.row(2).array(); - if (x2.rows() == 2) - *dx = x2 - *dx; - else - *dx = HomogeneousToEuclidean(static_cast(x2)) - *dx; - } - /** - * Computes the asymmetric residuals between a 2D point x2 and the transformed - * 2D point x1 such that - * Residuals = x2 - Psi(H * x1) - * where Psi is the function that transforms homogeneous to euclidean coords. - * - * \param[in] H The 3x3 homography matrix. - * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[out] dx A vector of size 2 of the residual error - */ - static void Residuals(const Mat &H, const Vec &x1, - const Vec &x2, Vec2 *dx) { - Vec3 x2h_est; - if (x1.rows() == 2) - x2h_est = H * EuclideanToHomogeneous(static_cast(x1)); - else - x2h_est = H * x1; - if (x2.rows() == 2) - *dx = x2 - x2h_est.head<2>() / x2h_est[2]; - else - *dx = HomogeneousToEuclidean(static_cast(x2)) - - x2h_est.head<2>() / x2h_est[2]; - } - /** - * Computes the squared norm of the residuals between a set of 2D points x2 - * and the transformed 2D point set x1 such that - * Error = || x2 - Psi(H * x1) ||^2 - * where Psi is the function that transforms homogeneous to euclidean coords. - * - * \param[in] H The 3x3 homography matrix. - * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A set of 2D points (2xN or 3xN matrix of column vectors). - * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). - * \return The squared norm of the asymmetric residuals errors - */ - static double Error(const Mat &H, const Mat &x1, const Mat &x2) { - Mat2X dx; - Residuals(H, x1, x2, &dx); - return dx.squaredNorm(); - } - /** - * Computes the squared norm of the residuals between a 2D point x2 and the - * transformed 2D point x1 such that rms = || x2 - Psi(H * x1) ||^2 - * where Psi is the function that transforms homogeneous to euclidean coords. - * - * \param[in] H The 3x3 homography matrix. - * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \return The squared norm of the asymmetric residual error - */ - static double Error(const Mat &H, const Vec &x1, const Vec &x2) { - Vec2 dx; - Residuals(H, x1, x2, &dx); - return dx.squaredNorm(); - } -}; - - /** - * Structure for estimating the symmetric error - * between a vector x2 and the transformed x1 such that - * Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2 - * where Psi is the function that transforms homogeneous to euclidean coords. - * \note It should be distributed as Chi-squared with k = 4. - */ -struct SymmetricError { - /** - * Computes the squared norm of the residuals between x2 and the - * transformed x1 such that - * Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2 - * where Psi is the function that transforms homogeneous to euclidean coords. - * - * \param[in] H The 3x3 homography matrix. - * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \return The squared norm of the symmetric residuals errors - */ - static double Error(const Mat &H, const Vec &x1, const Vec &x2) { - // TODO(keir): This is awesomely inefficient because it does a 3x3 - // inversion for each evaluation. - Mat3 Hinv = H.inverse(); - return AsymmetricError::Error(H, x1, x2) + - AsymmetricError::Error(Hinv, x2, x1); - } - // TODO(julien) Add residuals function \see AsymmetricError -}; - /** - * Structure for estimating the algebraic error (cross product) - * between a vector x2 and the transformed x1 such that - * Error = ||[x2] * H * x1||^^2 - * where [x2] is the skew matrix of x2. - */ -struct AlgebraicError { - // TODO(julien) Make an AlgebraicError2Rows and AlgebraicError3Rows - - /** - * Computes the algebraic residuals (cross product) between a set of 2D - * points x2 and the transformed 2D point set x1 such that - * [x2] * H * x1 where [x2] is the skew matrix of x2. - * - * \param[in] H The 3x3 homography matrix. - * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A set of 2D points (2xN or 3xN matrix of column vectors). - * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). - * \param[out] dx A 3xN matrix of column vectors of residuals errors - */ - static void Residuals(const Mat &H, const Mat &x1, - const Mat &x2, Mat3X *dx) { - dx->resize(3, x1.cols()); - Vec3 col; - for (int i = 0; i < x1.cols(); ++i) { - Residuals(H, x1.col(i), x2.col(i), &col); - dx->col(i) = col; - } - } - /** - * Computes the algebraic residuals (cross product) between a 2D point x2 - * and the transformed 2D point x1 such that - * [x2] * H * x1 where [x2] is the skew matrix of x2. - * - * \param[in] H The 3x3 homography matrix. - * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[out] dx A vector of size 3 of the residual error - */ - static void Residuals(const Mat &H, const Vec &x1, - const Vec &x2, Vec3 *dx) { - Vec3 x2h_est; - if (x1.rows() == 2) - x2h_est = H * EuclideanToHomogeneous(static_cast(x1)); - else - x2h_est = H * x1; - if (x2.rows() == 2) - *dx = SkewMat(EuclideanToHomogeneous(static_cast(x2))) * x2h_est; - else - *dx = SkewMat(x2) * x2h_est; - // TODO(julien) This is inefficient since it creates an - // identical 3x3 skew matrix for each evaluation. - } - /** - * Computes the squared norm of the algebraic residuals between a set of 2D - * points x2 and the transformed 2D point set x1 such that - * [x2] * H * x1 where [x2] is the skew matrix of x2. - * - * \param[in] H The 3x3 homography matrix. - * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A set of 2D points (2xN or 3xN matrix of column vectors). - * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). - * \return The squared norm of the asymmetric residuals errors - */ - static double Error(const Mat &H, const Mat &x1, const Mat &x2) { - Mat3X dx; - Residuals(H, x1, x2, &dx); - return dx.squaredNorm(); - } - /** - * Computes the squared norm of the algebraic residuals between a 2D point x2 - * and the transformed 2D point x1 such that - * [x2] * H * x1 where [x2] is the skew matrix of x2. - * - * \param[in] H The 3x3 homography matrix. - * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \return The squared norm of the asymmetric residual error - */ - static double Error(const Mat &H, const Vec &x1, const Vec &x2) { - Vec3 dx; - Residuals(H, x1, x2, &dx); - return dx.squaredNorm(); - } -}; -// TODO(keir): Add error based on ideal points. - -} // namespace homography2D -// TODO(julien) add homography3D errors -} // namespace homography -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_HOMOGRAPHY_ERRORS_H_ diff --git a/extern/libmv/libmv/multiview/homography_parameterization.h b/extern/libmv/libmv/multiview/homography_parameterization.h deleted file mode 100644 index ca8fbd8066e..00000000000 --- a/extern/libmv/libmv/multiview/homography_parameterization.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_HOMOGRAPHY_PARAMETERIZATION_H_ -#define LIBMV_MULTIVIEW_HOMOGRAPHY_PARAMETERIZATION_H_ - -#include "libmv/numeric/numeric.h" - -namespace libmv { - -/** A parameterization of the 2D homography matrix that uses 8 parameters so - * that the matrix is normalized (H(2,2) == 1). - * The homography matrix H is built from a list of 8 parameters (a, b,...g, h) - * as follows - * |a b c| - * H = |d e f| - * |g h 1| - */ -template -class Homography2DNormalizedParameterization { - public: - typedef Eigen::Matrix Parameters; // a, b, ... g, h - typedef Eigen::Matrix Parameterized; // H - - /// Convert from the 8 parameters to a H matrix. - static void To(const Parameters &p, Parameterized *h) { - *h << p(0), p(1), p(2), - p(3), p(4), p(5), - p(6), p(7), 1.0; - } - - /// Convert from a H matrix to the 8 parameters. - static void From(const Parameterized &h, Parameters *p) { - *p << h(0, 0), h(0, 1), h(0, 2), - h(1, 0), h(1, 1), h(1, 2), - h(2, 0), h(2, 1); - } -}; - -/** A parameterization of the 2D homography matrix that uses 15 parameters so - * that the matrix is normalized (H(3,3) == 1). - * The homography matrix H is built from a list of 15 parameters (a, b,...n, o) - * as follows - * |a b c d| - * H = |e f g h| - * |i j k l| - * |m n o 1| - */ -template -class Homography3DNormalizedParameterization { - public: - typedef Eigen::Matrix Parameters; // a, b, ... n, o - typedef Eigen::Matrix Parameterized; // H - - /// Convert from the 15 parameters to a H matrix. - static void To(const Parameters &p, Parameterized *h) { - *h << p(0), p(1), p(2), p(3), - p(4), p(5), p(6), p(7), - p(8), p(9), p(10), p(11), - p(12), p(13), p(14), 1.0; - } - - /// Convert from a H matrix to the 15 parameters. - static void From(const Parameterized &h, Parameters *p) { - *p << h(0, 0), h(0, 1), h(0, 2), h(0, 3), - h(1, 0), h(1, 1), h(1, 2), h(1, 3), - h(2, 0), h(2, 1), h(2, 2), h(2, 3), - h(3, 0), h(3, 1), h(3, 2); - } -}; - -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_HOMOGRAPHY_PARAMETERIZATION_H_ diff --git a/extern/libmv/libmv/multiview/homography_test.cc b/extern/libmv/libmv/multiview/homography_test.cc deleted file mode 100644 index 8d7266e3d11..00000000000 --- a/extern/libmv/libmv/multiview/homography_test.cc +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "testing/testing.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/projection.h" -#include "libmv/multiview/homography.h" - -namespace { -using namespace libmv; - -namespace { - -// Check whether homography transform M actually transforms -// given vectors x1 to x2. Used to check validness of a reconstructed -// homography matrix. -// TODO(sergey): Consider using this in all tests since possible homography -// matrix is not fixed to a single value and different-looking matrices -// might actually crrespond to the same exact transform. -void CheckHomography2DTransform(const Mat3 &H, - const Mat &x1, - const Mat &x2) { - for (int i = 0; i < x2.cols(); ++i) { - Vec3 x2_expected = x2.col(i); - Vec3 x2_observed = H * x1.col(i); - x2_observed /= x2_observed(2); - EXPECT_MATRIX_NEAR(x2_expected, x2_observed, 1e-8); - } -} - -} // namespace - -TEST(Homography2DTest, Rotation45AndTranslationXY) { - Mat x1(3, 4); - x1 << 0, 1, 0, 5, - 0, 0, 2, 3, - 1, 1, 1, 1; - - double angle = 45.0; - Mat3 m; - m << cos(angle), -sin(angle), -2, - sin(angle), cos(angle), 5, - 0, 0, 1; - - Mat x2 = x1; - // Transform point from ground truth matrix - for (int i = 0; i < x2.cols(); ++i) - x2.col(i) = m * x1.col(i); - - Mat3 homography_mat; - EXPECT_TRUE(Homography2DFromCorrespondencesLinear(x1, x2, &homography_mat)); - VLOG(1) << "Mat Homography2D "; - VLOG(1) << homography_mat; - VLOG(1) << "Mat GT "; - VLOG(1) << m; - EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8); -} - -TEST(Homography2DTest, AffineGeneral4) { - // TODO(julien) find why it doesn't work with 4 points!!! - Mat x1(3, 4); - x1 << 0, 1, 0, 2, - 0, 0, 1, 2, - 1, 1, 1, 1; - Mat3 m; - m << 3, -1, 4, - 6, -2, -3, - 0, 0, 1; - - Mat x2 = x1; - for (int i = 0; i < x2.cols(); ++i) { - x2.col(i) = m * x1.col(i); - } - - Mat3 homography_mat; - EXPECT_TRUE(Homography2DFromCorrespondencesLinear(x1, x2, &homography_mat)); - VLOG(1) << "Mat Homography2D"; - VLOG(1) << homography_mat; - CheckHomography2DTransform(homography_mat, x1, x2); - - // Test with euclidean coordinates - Mat eX1, eX2; - HomogeneousToEuclidean(x1, &eX1); - HomogeneousToEuclidean(x2, &eX2); - homography_mat.setIdentity(); - EXPECT_TRUE(Homography2DFromCorrespondencesLinear(eX1, eX2, &homography_mat)); - - VLOG(1) << "Mat Homography2D "; - VLOG(1) << homography_mat; - CheckHomography2DTransform(homography_mat, x1, x2); -} - -TEST(Homography2DTest, AffineGeneral5) { - Mat x1(3, 5); - x1 << 0, 1, 0, 2, 5, - 0, 0, 1, 2, 2, - 1, 1, 1, 1, 1; - Mat3 m; - m << 3, -1, 4, - 6, -2, -3, - 0, 0, 1; - - Mat x2 = x1; - for (int i = 0; i < x2.cols(); ++i) - x2.col(i) = m * x1.col(i); - - Mat3 homography_mat; - EXPECT_TRUE(Homography2DFromCorrespondencesLinear(x1, x2, &homography_mat)); - - VLOG(1) << "Mat Homography2D "; - VLOG(1) << homography_mat; - EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8); - - // Test with euclidean coordinates - Mat eX1, eX2; - HomogeneousToEuclidean(x1, &eX1); - HomogeneousToEuclidean(x2, &eX2); - homography_mat.setIdentity(); - EXPECT_TRUE(Homography2DFromCorrespondencesLinear(eX1, eX2, &homography_mat)); - - VLOG(1) << "Mat Homography2D "; - VLOG(1) << homography_mat; - EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8); -} - -TEST(Homography2DTest, HomographyGeneral) { - Mat x1(3, 4); - x1 << 0, 1, 0, 5, - 0, 0, 2, 3, - 1, 1, 1, 1; - Mat3 m; - m << 3, -1, 4, - 6, -2, -3, - 1, -3, 1; - - Mat x2 = x1; - for (int i = 0; i < x2.cols(); ++i) - x2.col(i) = m * x1.col(i); - - Mat3 homography_mat; - EXPECT_TRUE(Homography2DFromCorrespondencesLinear(x1, x2, &homography_mat)); - - VLOG(1) << "Mat Homography2D "; - VLOG(1) << homography_mat; - EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8); -} - -TEST(Homography3DTest, RotationAndTranslationXYZ) { - Mat x1(4, 5); - x1 << 0, 0, 1, 5, 2, - 0, 1, 2, 3, 5, - 0, 2, 0, 1, 5, - 1, 1, 1, 1, 1; - Mat4 M; - M.setIdentity(); - /* - M = AngleAxisd(45.0, Vector3f::UnitZ()) - * AngleAxisd(25.0, Vector3f::UnitX()) - * AngleAxisd(5.0, Vector3f::UnitZ());*/ - - // Rotation on x + translation - double angle = 45.0; - Mat4 rot; - rot << 1, 0, 0, 1, - 0, cos(angle), -sin(angle), 3, - 0, sin(angle), cos(angle), -2, - 0, 0, 0, 1; - M *= rot; - // Rotation on y - angle = 25.0; - rot << cos(angle), 0, sin(angle), 0, - 0, 1, 0, 0, - -sin(angle), 0, cos(angle), 0, - 0, 0, 0, 1; - M *= rot; - // Rotation on z - angle = 5.0; - rot << cos(angle), -sin(angle), 0, 0, - sin(angle), cos(angle), 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1; - M *= rot; - Mat x2 = x1; - for (int i = 0; i < x2.cols(); ++i) { - x2.col(i) = M * x1.col(i); - } - - Mat4 homography_mat; - EXPECT_TRUE(Homography3DFromCorrespondencesLinear(x1, x2, &homography_mat)); - - VLOG(1) << "Mat Homography3D " << homography_mat; - VLOG(1) << "Mat GT " << M; - EXPECT_MATRIX_NEAR(homography_mat, M, 1e-8); -} - -TEST(Homography3DTest, AffineGeneral) { - Mat x1(4, 5); - x1 << 0, 0, 1, 5, 2, - 0, 1, 2, 3, 5, - 0, 2, 0, 1, 5, - 1, 1, 1, 1, 1; - Mat4 m; - m << 3, -1, 4, 1, - 6, -2, -3, -6, - 1, 0, 1, 2, - 0, 0, 0, 1; - - Mat x2 = x1; - for (int i = 0; i < x2.cols(); ++i) { - x2.col(i) = m * x1.col(i); - } - - Mat4 homography_mat; - EXPECT_TRUE(Homography3DFromCorrespondencesLinear(x1, x2, &homography_mat)); - VLOG(1) << "Mat Homography3D "; - VLOG(1) << homography_mat; - EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8); -} - -TEST(Homography3DTest, HomographyGeneral) { - Mat x1(4, 5); - x1 << 0, 0, 1, 5, 2, - 0, 1, 2, 3, 5, - 0, 2, 0, 1, 5, - 1, 1, 1, 1, 1; - Mat4 m; - m << 3, -1, 4, 1, - 6, -2, -3, -6, - 1, 0, 1, 2, - -3, 1, 0, 1; - - Mat x2 = x1; - for (int i = 0; i < x2.cols(); ++i) { - x2.col(i) = m * x1.col(i); - } - - Mat4 homography_mat; - EXPECT_TRUE(Homography3DFromCorrespondencesLinear(x1, x2, &homography_mat)); - VLOG(1) << "Mat Homography3D"; - VLOG(1) << homography_mat; - EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8); -} - -} // namespace diff --git a/extern/libmv/libmv/multiview/nviewtriangulation.h b/extern/libmv/libmv/multiview/nviewtriangulation.h deleted file mode 100644 index f4614ab1a5c..00000000000 --- a/extern/libmv/libmv/multiview/nviewtriangulation.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Compute a 3D position of a point from several images of it. In particular, -// compute the projective point X in R^4 such that x = PX. -// -// Algorithm is the standard DLT; for derivation see appendix of Keir's thesis. - -#ifndef LIBMV_MULTIVIEW_NVIEWTRIANGULATION_H -#define LIBMV_MULTIVIEW_NVIEWTRIANGULATION_H - -#include "libmv/base/vector.h" -#include "libmv/logging/logging.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { - -// x's are 2D coordinates (x,y,1) in each image; Ps are projective cameras. The -// output, X, is a homogeneous four vectors. -template -void NViewTriangulate(const Matrix &x, - const vector > &Ps, - Matrix *X) { - int nviews = x.cols(); - assert(nviews == Ps.size()); - - Matrix design(3*nviews, 4 + nviews); - design.setConstant(0.0); - for (int i = 0; i < nviews; i++) { - design.template block<3, 4>(3*i, 0) = -Ps[i]; - design(3*i + 0, 4 + i) = x(0, i); - design(3*i + 1, 4 + i) = x(1, i); - design(3*i + 2, 4 + i) = 1.0; - } - Matrix X_and_alphas; - Nullspace(&design, &X_and_alphas); - X->resize(4); - *X = X_and_alphas.head(4); -} - -// x's are 2D coordinates (x,y,1) in each image; Ps are projective cameras. The -// output, X, is a homogeneous four vectors. -// This method uses the algebraic distance approximation. -// Note that this method works better when the 2D points are normalized -// with an isotopic normalization. -template -void NViewTriangulateAlgebraic(const Matrix &x, - const vector > &Ps, - Matrix *X) { - int nviews = x.cols(); - assert(nviews == Ps.size()); - - Matrix design(2*nviews, 4); - for (int i = 0; i < nviews; i++) { - design.template block<2, 4>(2*i, 0) = SkewMatMinimal(x.col(i)) * Ps[i]; - } - X->resize(4); - Nullspace(&design, X); -} - -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_RESECTION_H diff --git a/extern/libmv/libmv/multiview/nviewtriangulation_test.cc b/extern/libmv/libmv/multiview/nviewtriangulation_test.cc deleted file mode 100644 index 5a4d8499753..00000000000 --- a/extern/libmv/libmv/multiview/nviewtriangulation_test.cc +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include - -#include "libmv/base/vector.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/nviewtriangulation.h" -#include "libmv/multiview/projection.h" -#include "libmv/multiview/test_data_sets.h" -#include "libmv/numeric/numeric.h" -#include "testing/testing.h" - -namespace { - -using namespace libmv; - -TEST(NViewTriangulate, FiveViews) { - int nviews = 5; - int npoints = 6; - NViewDataSet d = NRealisticCamerasFull(nviews, npoints); - - // Collect P matrices together. - vector Ps(nviews); - for (int j = 0; j < nviews; ++j) { - Ps[j] = d.P(j); - } - - for (int i = 0; i < npoints; ++i) { - // Collect the image of point i in each frame. - Mat2X xs(2, nviews); - for (int j = 0; j < nviews; ++j) { - xs.col(j) = d.x[j].col(i); - } - Vec4 X; - NViewTriangulate(xs, Ps, &X); - - // Check reprojection error. Should be nearly zero. - for (int j = 0; j < nviews; ++j) { - Vec3 x_reprojected = Ps[j]*X; - x_reprojected /= x_reprojected(2); - double error = (x_reprojected.head(2) - xs.col(j)).norm(); - EXPECT_NEAR(error, 0.0, 1e-9); - } - } -} - -TEST(NViewTriangulateAlgebraic, FiveViews) { - int nviews = 5; - int npoints = 6; - NViewDataSet d = NRealisticCamerasFull(nviews, npoints); - - // Collect P matrices together. - vector Ps(nviews); - for (int j = 0; j < nviews; ++j) { - Ps[j] = d.P(j); - } - - for (int i = 0; i < npoints; ++i) { - // Collect the image of point i in each frame. - Mat2X xs(2, nviews); - for (int j = 0; j < nviews; ++j) { - xs.col(j) = d.x[j].col(i); - } - Vec4 X; - NViewTriangulate(xs, Ps, &X); - - // Check reprojection error. Should be nearly zero. - for (int j = 0; j < nviews; ++j) { - Vec3 x_reprojected = Ps[j]*X; - x_reprojected /= x_reprojected(2); - double error = (x_reprojected.head<2>() - xs.col(j)).norm(); - EXPECT_NEAR(error, 0.0, 1e-9); - } - } -} -} // namespace diff --git a/extern/libmv/libmv/multiview/panography.cc b/extern/libmv/libmv/multiview/panography.cc deleted file mode 100644 index b62802948c4..00000000000 --- a/extern/libmv/libmv/multiview/panography.cc +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// - -#include "libmv/multiview/panography.h" - -namespace libmv { - -static bool Build_Minimal2Point_PolynomialFactor( - const Mat & x1, const Mat & x2, - double * P) { // P must be a double[4] - assert(2 == x1.rows()); - assert(2 == x1.cols()); - assert(x1.rows() == x2.rows()); - assert(x1.cols() == x2.cols()); - - // Setup the variable of the input problem: - Vec xx1 = (x1.col(0)).transpose(); - Vec yx1 = (x1.col(1)).transpose(); - - double a12 = xx1.dot(yx1); - Vec xx2 = (x2.col(0)).transpose(); - Vec yx2 = (x2.col(1)).transpose(); - double b12 = xx2.dot(yx2); - - double a1 = xx1.squaredNorm(); - double a2 = yx1.squaredNorm(); - - double b1 = xx2.squaredNorm(); - double b2 = yx2.squaredNorm(); - - // Build the 3rd degre polynomial in F^2. - // - // f^6 * p + f^4 * q + f^2* r + s = 0; - // - // Coefficients in ascending powers of alpha, i.e. P[N]*x^N. - // Run panography_coeffs.py to get the below coefficients. - P[0] = b1*b2*a12*a12-a1*a2*b12*b12; - P[1] = -2*a1*a2*b12+2*a12*b1*b2+b1*a12*a12+b2*a12*a12-a1*b12*b12-a2*b12*b12; - P[2] = b1*b2-a1*a2-2*a1*b12-2*a2*b12+2*a12*b1+2*a12*b2+a12*a12-b12*b12; - P[3] = b1+b2-2*b12-a1-a2+2*a12; - - // If P[3] equal to 0 we get ill conditionned data - return (P[3] != 0.0); -} - -// This implements a minimal solution (2 points) for panoramic stitching: -// -// http://www.cs.ubc.ca/~mbrown/minimal/minimal.html -// -// [1] M. Brown and R. Hartley and D. Nister. Minimal Solutions for Panoramic -// Stitching. CVPR07. -void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, - vector *fs) { - // Build Polynomial factor to get squared focal value. - double P[4]; - Build_Minimal2Point_PolynomialFactor(x1, x2, &P[0]); - - // Solve it by using F = f^2 and a Cubic polynomial solver - // - // F^3 * p + F^2 * q + F^1 * r + s = 0 - // - double roots[3]; - int num_roots = SolveCubicPolynomial(P, roots); - for (int i = 0; i < num_roots; ++i) { - if (roots[i] > 0.0) { - fs->push_back(sqrt(roots[i])); - } - } -} - -// Compute the 3x3 rotation matrix that fits two 3D point clouds in the least -// square sense. The method is from: -// -// K. Arun,T. Huand and D. Blostein. Least-squares fitting of 2 3-D point -// sets. IEEE Transactions on Pattern Analysis and Machine Intelligence, -// 9:698-700, 1987. -void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2, - const double focal, - Mat3 *R) { - assert(3 == x1.rows()); - assert(2 <= x1.cols()); - assert(x1.rows() == x2.rows()); - assert(x1.cols() == x2.cols()); - - // Build simplified K matrix - Mat3 K(Mat3::Identity() * 1.0/focal); - K(2, 2)= 1.0; - - // Build the correlation matrix; equation (22) in [1]. - Mat3 C = Mat3::Zero(); - for (int i = 0; i < x1.cols(); ++i) { - Mat r1i = (K * x1.col(i)).normalized(); - Mat r2i = (K * x2.col(i)).normalized(); - C += r2i * r1i.transpose(); - } - - // Solve for rotation. Equations (24) and (25) in [1]. - Eigen::JacobiSVD svd(C, Eigen::ComputeThinU | Eigen::ComputeThinV); - Mat3 scale = Mat3::Identity(); - scale(2, 2) = ((svd.matrixU() * svd.matrixV().transpose()).determinant() > 0.0) - ? 1.0 - : -1.0; - - (*R) = svd.matrixU() * scale * svd.matrixV().transpose(); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/multiview/panography.h b/extern/libmv/libmv/multiview/panography.h deleted file mode 100644 index 6e87bd71304..00000000000 --- a/extern/libmv/libmv/multiview/panography.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// - -#ifndef LIBMV_MULTIVIEW_PANOGRAPHY_H -#define LIBMV_MULTIVIEW_PANOGRAPHY_H - -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/poly.h" -#include "libmv/base/vector.h" - -namespace libmv { - -// This implements a minimal solution (2 points) for panoramic stitching: -// -// http://www.cs.ubc.ca/~mbrown/minimal/minimal.html -// -// [1] M. Brown and R. Hartley and D. Nister. Minimal Solutions for Panoramic -// Stitching. CVPR07. -// -// The 2-point algorithm solves for the rotation of the camera with a single -// focal length (4 degrees of freedom). -// -// Compute from 1 to 3 possible focal lenght for 2 point correspondences. -// Suppose that the cameras share the same optical center and focal lengths: -// -// Image 1 => H*x = x' => Image 2 -// x (u1j) x' (u2j) -// a (u11) a' (u21) -// b (u12) b' (u22) -// -// The return values are 1 to 3 possible values for the focal lengths such -// that: -// -// [f 0 0] -// K = [0 f 0] -// [0 0 1] -// -void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, - vector *fs); - -// Compute the 3x3 rotation matrix that fits two 3D point clouds in the least -// square sense. The method is from: -// -// K. Arun,T. Huand and D. Blostein. Least-squares fitting of 2 3-D point -// sets. IEEE Transactions on Pattern Analysis and Machine Intelligence, -// 9:698-700, 1987. -// -// Given the calibration matrices K1, K2 solve for the rotation from -// corresponding image rays. -// -// R = min || X2 - R * x1 ||. -// -// In case of panography, which is for a camera that shares the same camera -// center, -// -// H = K2 * R * K1.inverse(); -// -// For the full explanation, see Section 8, Solving for Rotation from [1]. -// -// Parameters: -// -// x1 : Point cloud A (3D coords) -// x2 : Point cloud B (3D coords) -// -// [f 0 0] -// K1 = [0 f 0] -// [0 0 1] -// -// K2 (the same form as K1, but may have different f) -// -// Returns: A rotation matrix that minimizes -// -// R = arg min || X2 - R * x1 || -// -void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2, - const double focal, - Mat3 *R); - -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_PANOGRAPHY_H diff --git a/extern/libmv/libmv/multiview/panography_kernel.cc b/extern/libmv/libmv/multiview/panography_kernel.cc deleted file mode 100644 index 8fdc9e79aed..00000000000 --- a/extern/libmv/libmv/multiview/panography_kernel.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2008, 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/multiview/panography_kernel.h" -#include "libmv/multiview/panography.h" - -namespace libmv { -namespace panography { -namespace kernel { - -void TwoPointSolver::Solve(const Mat &x1, const Mat &x2, vector *Hs) { - // Solve for the focal lengths. - vector fs; - F_FromCorrespondance_2points(x1, x2, &fs); - - // Then solve for the rotations and homographies. - Mat x1h, x2h; - EuclideanToHomogeneous(x1, &x1h); - EuclideanToHomogeneous(x2, &x2h); - for (int i = 0; i < fs.size(); ++i) { - Mat3 K1 = Mat3::Identity() * fs[i]; - K1(2, 2) = 1.0; - - Mat3 R; - GetR_FixedCameraCenter(x1h, x2h, fs[i], &R); - R /= R(2, 2); - - (*Hs).push_back(K1 * R * K1.inverse()); - } -} - -} // namespace kernel -} // namespace panography -} // namespace libmv diff --git a/extern/libmv/libmv/multiview/panography_kernel.h b/extern/libmv/libmv/multiview/panography_kernel.h deleted file mode 100644 index a6adbd54b20..00000000000 --- a/extern/libmv/libmv/multiview/panography_kernel.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_PANOGRAPHY_KERNEL_H -#define LIBMV_MULTIVIEW_PANOGRAPHY_KERNEL_H - -#include "libmv/base/vector.h" -#include "libmv/multiview/conditioning.h" -#include "libmv/multiview/projection.h" -#include "libmv/multiview/two_view_kernel.h" -#include "libmv/multiview/homography_error.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { -namespace panography { -namespace kernel { - -struct TwoPointSolver { - enum { MINIMUM_SAMPLES = 2 }; - static void Solve(const Mat &x1, const Mat &x2, vector *Hs); -}; - -typedef two_view::kernel::Kernel< - TwoPointSolver, homography::homography2D::AsymmetricError, Mat3> - UnnormalizedKernel; - -typedef two_view::kernel::Kernel< - two_view::kernel::NormalizedSolver, - homography::homography2D::AsymmetricError, - Mat3> - Kernel; - -} // namespace kernel -} // namespace panography -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_PANOGRAPHY_KERNEL_H diff --git a/extern/libmv/libmv/multiview/panography_test.cc b/extern/libmv/libmv/multiview/panography_test.cc deleted file mode 100644 index f6faf0f6022..00000000000 --- a/extern/libmv/libmv/multiview/panography_test.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/logging/logging.h" -#include "libmv/multiview/panography.h" -#include "libmv/multiview/panography_kernel.h" -#include "libmv/multiview/projection.h" -#include "libmv/numeric/numeric.h" -#include "testing/testing.h" - -namespace libmv { -namespace { - -TEST(Panography, PrintSomeSharedFocalEstimationValues) { - Mat x1(2, 2), x2(2, 2); - x1<< 158, 78, - 124, 113; - x2<< 300, 214, - 125, 114; - - // Normalize data (set principal point 0,0 and image border to 1.0). - x1.block<1, 2>(0, 0) /= 320; - x1.block<1, 2>(1, 0) /= 240; - x2.block<1, 2>(0, 0) /= 320; - x2.block<1, 2>(1, 0) /= 240; - x1+=Mat2::Constant(0.5); - x2+=Mat2::Constant(0.5); - - vector fs; - F_FromCorrespondance_2points(x1, x2, &fs); - - // Assert we found a valid solution. - EXPECT_EQ(1, fs.size()); - EXPECT_NEAR(1.01667, fs[1], 1e-3); -} - -TEST(Panography, GetR_FixedCameraCenterWithIdentity) { - Mat x1(3, 3); - x1 << 0.5, 0.6, 0.7, - 0.5, 0.5, 0.4, - 10.0, 10.0, 10.0; - - Mat3 R; - GetR_FixedCameraCenter(x1, x1, 1.0, &R); - R /= R(2, 2); - EXPECT_MATRIX_NEAR(Mat3::Identity(), R, 1e-8); - LOG(INFO) << "R \n" << R; -} - -TEST(Panography, Homography_GetR_Test_PitchY30) { - int n = 3; - - Mat x1(3, n); - x1 << 0.5, 0.6, 0.7, - 0.5, 0.5, 0.4, - 10, 10, 10; - - Mat x2 = x1; - const double alpha = 30.0 * M_PI / 180.0; - Mat3 rotY; - rotY << cos(alpha), 0, -sin(alpha), - 0, 1, 0, - sin(alpha), 0, cos(alpha); - - for (int i = 0; i < n; ++i) { - x2.block<3, 1>(0, i) = rotY * x1.col(i); - } - - Mat3 R; - GetR_FixedCameraCenter(x1, x2, 1.0, &R); - - // Assert that residuals are small enough - for (int i = 0; i < n; ++i) { - Vec residuals = (R * x1.col(i)) - x2.col(i); - EXPECT_NEAR(0, residuals.norm(), 1e-6); - } - - // Check that the rotation angle along Y is the expected one. - // Use the euler approximation to recover the angle. - double pitch_y = asin(R(2, 0)) * 180.0 / M_PI; - EXPECT_NEAR(30, pitch_y, 1e-4); -} - -TEST(MinimalPanoramic, Real_Case_Kernel) { - const int n = 2; - Mat x1(2, n); // From image 0.jpg - x1<< 158, 78, - 124, 113; - - Mat x2(2, n); // From image 3.jpg - x2<< 300, 214, - 125, 114; - - Mat3 Ground_TruthHomography; - Ground_TruthHomography<< 1, 0.02, 129.83, - -0.02, 1.012, 0.07823, - 0, 0, 1; - - vector Hs; - - libmv::panography::kernel::TwoPointSolver::Solve(x1, x2, &Hs); - - LOG(INFO) << "Got " << Hs.size() << " solutions."; - for (int j = 0; j < Hs.size(); ++j) { - Mat3 H = Hs[j]; - - EXPECT_MATRIX_NEAR(H, Ground_TruthHomography, 1e-1); - - Mat x1h, x2h; - EuclideanToHomogeneous(x1, &x1h); - EuclideanToHomogeneous(x2, &x2h); - - // Assert that residuals are small enough - for (int i = 0; i < n; ++i) { - Vec x1p = H * x1h.col(i); - Vec residuals = x1p/x1p(2) - x2h.col(i); - EXPECT_MATRIX_NEAR_ZERO(residuals, 1e-5); - } - } -} - -} // namespace -} // namespace libmv - -// TODO(pmoulon): Add a real test case based on images. -// TODO(pmoulon): Add a check for the actual f value for the real images. -// TODO(pmoulon): Add a test that has some inliers and outliers. diff --git a/extern/libmv/libmv/multiview/projection.cc b/extern/libmv/libmv/multiview/projection.cc deleted file mode 100644 index f8bece3de68..00000000000 --- a/extern/libmv/libmv/multiview/projection.cc +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/multiview/projection.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { - -void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P) { - P->block<3, 3>(0, 0) = R; - P->col(3) = t; - (*P) = K * (*P); -} - -void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { - // Decompose using the RQ decomposition HZ A4.1.1 pag.579. - Mat3 K = P.block(0, 0, 3, 3); - - Mat3 Q; - Q.setIdentity(); - - // Set K(2,1) to zero. - if (K(2, 1) != 0) { - double c = -K(2, 2); - double s = K(2, 1); - double l = sqrt(c * c + s * s); - c /= l; - s /= l; - Mat3 Qx; - Qx << 1, 0, 0, - 0, c, -s, - 0, s, c; - K = K * Qx; - Q = Qx.transpose() * Q; - } - // Set K(2,0) to zero. - if (K(2, 0) != 0) { - double c = K(2, 2); - double s = K(2, 0); - double l = sqrt(c * c + s * s); - c /= l; - s /= l; - Mat3 Qy; - Qy << c, 0, s, - 0, 1, 0, - -s, 0, c; - K = K * Qy; - Q = Qy.transpose() * Q; - } - // Set K(1,0) to zero. - if (K(1, 0) != 0) { - double c = -K(1, 1); - double s = K(1, 0); - double l = sqrt(c * c + s * s); - c /= l; - s /= l; - Mat3 Qz; - Qz << c, -s, 0, - s, c, 0, - 0, 0, 1; - K = K * Qz; - Q = Qz.transpose() * Q; - } - - Mat3 R = Q; - - // Ensure that the diagonal is positive. - // TODO(pau) Change this to ensure that: - // - K(0,0) > 0 - // - K(2,2) = 1 - // - det(R) = 1 - if (K(2, 2) < 0) { - K = -K; - R = -R; - } - if (K(1, 1) < 0) { - Mat3 S; - S << 1, 0, 0, - 0, -1, 0, - 0, 0, 1; - K = K * S; - R = S * R; - } - if (K(0, 0) < 0) { - Mat3 S; - S << -1, 0, 0, - 0, 1, 0, - 0, 0, 1; - K = K * S; - R = S * R; - } - - // Compute translation. - Vec p(3); - p << P(0, 3), P(1, 3), P(2, 3); - // TODO(pau) This sould be done by a SolveLinearSystem(A, b, &x) call. - // TODO(keir) use the eigen LU solver syntax... - Vec3 t = K.inverse() * p; - - // scale K so that K(2,2) = 1 - K = K / K(2, 2); - - *Kp = K; - *Rp = R; - *tp = t; -} - -void ProjectionShiftPrincipalPoint(const Mat34 &P, - const Vec2 &principal_point, - const Vec2 &principal_point_new, - Mat34 *P_new) { - Mat3 T; - T << 1, 0, principal_point_new(0) - principal_point(0), - 0, 1, principal_point_new(1) - principal_point(1), - 0, 0, 1; - *P_new = T * P; -} - -void ProjectionChangeAspectRatio(const Mat34 &P, - const Vec2 &principal_point, - double aspect_ratio, - double aspect_ratio_new, - Mat34 *P_new) { - Mat3 T; - T << 1, 0, 0, - 0, aspect_ratio_new / aspect_ratio, 0, - 0, 0, 1; - Mat34 P_temp; - - ProjectionShiftPrincipalPoint(P, principal_point, Vec2(0, 0), &P_temp); - P_temp = T * P_temp; - ProjectionShiftPrincipalPoint(P_temp, Vec2(0, 0), principal_point, P_new); -} - -void HomogeneousToEuclidean(const Mat &H, Mat *X) { - int d = H.rows() - 1; - int n = H.cols(); - X->resize(d, n); - for (size_t i = 0; i < n; ++i) { - double h = H(d, i); - for (int j = 0; j < d; ++j) { - (*X)(j, i) = H(j, i) / h; - } - } -} - -void HomogeneousToEuclidean(const Mat3X &h, Mat2X *e) { - e->resize(2, h.cols()); - e->row(0) = h.row(0).array() / h.row(2).array(); - e->row(1) = h.row(1).array() / h.row(2).array(); -} -void HomogeneousToEuclidean(const Mat4X &h, Mat3X *e) { - e->resize(3, h.cols()); - e->row(0) = h.row(0).array() / h.row(3).array(); - e->row(1) = h.row(1).array() / h.row(3).array(); - e->row(2) = h.row(2).array() / h.row(3).array(); -} - -void HomogeneousToEuclidean(const Vec3 &H, Vec2 *X) { - double w = H(2); - *X << H(0) / w, H(1) / w; -} - -void HomogeneousToEuclidean(const Vec4 &H, Vec3 *X) { - double w = H(3); - *X << H(0) / w, H(1) / w, H(2) / w; -} - -void EuclideanToHomogeneous(const Mat &X, Mat *H) { - int d = X.rows(); - int n = X.cols(); - H->resize(d + 1, n); - H->block(0, 0, d, n) = X; - H->row(d).setOnes(); -} - -void EuclideanToHomogeneous(const Vec2 &X, Vec3 *H) { - *H << X(0), X(1), 1; -} - -void EuclideanToHomogeneous(const Vec3 &X, Vec4 *H) { - *H << X(0), X(1), X(2), 1; -} - -// TODO(julien) Call conditioning.h/ApplyTransformationToPoints ? -void EuclideanToNormalizedCamera(const Mat2X &x, const Mat3 &K, Mat2X *n) { - Mat3X x_image_h; - EuclideanToHomogeneous(x, &x_image_h); - Mat3X x_camera_h = K.inverse() * x_image_h; - HomogeneousToEuclidean(x_camera_h, n); -} - -void HomogeneousToNormalizedCamera(const Mat3X &x, const Mat3 &K, Mat2X *n) { - Mat3X x_camera_h = K.inverse() * x; - HomogeneousToEuclidean(x_camera_h, n); -} - -double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X) { - return (R*X)(2) + t(2); -} - -double Depth(const Mat3 &R, const Vec3 &t, const Vec4 &X) { - Vec3 Xe = X.head<3>() / X(3); - return Depth(R, t, Xe); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/multiview/projection.h b/extern/libmv/libmv/multiview/projection.h deleted file mode 100644 index 3220bc2dbbc..00000000000 --- a/extern/libmv/libmv/multiview/projection.h +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_PROJECTION_H_ -#define LIBMV_MULTIVIEW_PROJECTION_H_ - -#include "libmv/numeric/numeric.h" - -namespace libmv { - -void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P); -void KRt_From_P(const Mat34 &P, Mat3 *K, Mat3 *R, Vec3 *t); - -// Applies a change of basis to the image coordinates of the projection matrix -// so that the principal point becomes principal_point_new. -void ProjectionShiftPrincipalPoint(const Mat34 &P, - const Vec2 &principal_point, - const Vec2 &principal_point_new, - Mat34 *P_new); - -// Applies a change of basis to the image coordinates of the projection matrix -// so that the aspect ratio becomes aspect_ratio_new. This is done by -// stretching the y axis. The aspect ratio is defined as the quotient between -// the focal length of the y and the x axis. -void ProjectionChangeAspectRatio(const Mat34 &P, - const Vec2 &principal_point, - double aspect_ratio, - double aspect_ratio_new, - Mat34 *P_new); - -void HomogeneousToEuclidean(const Mat &H, Mat *X); -void HomogeneousToEuclidean(const Mat3X &h, Mat2X *e); -void HomogeneousToEuclidean(const Mat4X &h, Mat3X *e); -void HomogeneousToEuclidean(const Vec3 &H, Vec2 *X); -void HomogeneousToEuclidean(const Vec4 &H, Vec3 *X); -inline Vec2 HomogeneousToEuclidean(const Vec3 &h) { - return h.head<2>() / h(2); -} -inline Vec3 HomogeneousToEuclidean(const Vec4 &h) { - return h.head<3>() / h(3); -} -inline Mat2X HomogeneousToEuclidean(const Mat3X &h) { - Mat2X e(2, h.cols()); - e.row(0) = h.row(0).array() / h.row(2).array(); - e.row(1) = h.row(1).array() / h.row(2).array(); - return e; -} - -void EuclideanToHomogeneous(const Mat &X, Mat *H); -inline Mat3X EuclideanToHomogeneous(const Mat2X &x) { - Mat3X h(3, x.cols()); - h.block(0, 0, 2, x.cols()) = x; - h.row(2).setOnes(); - return h; -} -inline void EuclideanToHomogeneous(const Mat2X &x, Mat3X *h) { - h->resize(3, x.cols()); - h->block(0, 0, 2, x.cols()) = x; - h->row(2).setOnes(); -} -inline Mat4X EuclideanToHomogeneous(const Mat3X &x) { - Mat4X h(4, x.cols()); - h.block(0, 0, 3, x.cols()) = x; - h.row(3).setOnes(); - return h; -} -inline void EuclideanToHomogeneous(const Mat3X &x, Mat4X *h) { - h->resize(4, x.cols()); - h->block(0, 0, 3, x.cols()) = x; - h->row(3).setOnes(); -} -void EuclideanToHomogeneous(const Vec2 &X, Vec3 *H); -void EuclideanToHomogeneous(const Vec3 &X, Vec4 *H); -inline Vec3 EuclideanToHomogeneous(const Vec2 &x) { - return Vec3(x(0), x(1), 1); -} -inline Vec4 EuclideanToHomogeneous(const Vec3 &x) { - return Vec4(x(0), x(1), x(2), 1); -} -// Conversion from image coordinates to normalized camera coordinates -void EuclideanToNormalizedCamera(const Mat2X &x, const Mat3 &K, Mat2X *n); -void HomogeneousToNormalizedCamera(const Mat3X &x, const Mat3 &K, Mat2X *n); - -inline Vec2 Project(const Mat34 &P, const Vec3 &X) { - Vec4 HX; - HX << X, 1.0; - Vec3 hx = P * HX; - return hx.head<2>() / hx(2); -} - -inline void Project(const Mat34 &P, const Vec4 &X, Vec3 *x) { - *x = P * X; -} - -inline void Project(const Mat34 &P, const Vec4 &X, Vec2 *x) { - Vec3 hx = P * X; - *x = hx.head<2>() / hx(2); -} - -inline void Project(const Mat34 &P, const Vec3 &X, Vec3 *x) { - Vec4 HX; - HX << X, 1.0; - Project(P, HX, x); -} - -inline void Project(const Mat34 &P, const Vec3 &X, Vec2 *x) { - Vec3 hx; - Project(P, X, x); - *x = hx.head<2>() / hx(2); -} - -inline void Project(const Mat34 &P, const Mat4X &X, Mat2X *x) { - x->resize(2, X.cols()); - for (int c = 0; c < X.cols(); ++c) { - Vec3 hx = P * X.col(c); - x->col(c) = hx.head<2>() / hx(2); - } -} - -inline Mat2X Project(const Mat34 &P, const Mat4X &X) { - Mat2X x; - Project(P, X, &x); - return x; -} - -inline void Project(const Mat34 &P, const Mat3X &X, Mat2X *x) { - x->resize(2, X.cols()); - for (int c = 0; c < X.cols(); ++c) { - Vec4 HX; - HX << X.col(c), 1.0; - Vec3 hx = P * HX; - x->col(c) = hx.head<2>() / hx(2); - } -} - -inline void Project(const Mat34 &P, const Mat3X &X, const Vecu &ids, Mat2X *x) { - x->resize(2, ids.size()); - Vec4 HX; - Vec3 hx; - for (int c = 0; c < ids.size(); ++c) { - HX << X.col(ids[c]), 1.0; - hx = P * HX; - x->col(c) = hx.head<2>() / hx(2); - } -} - -inline Mat2X Project(const Mat34 &P, const Mat3X &X) { - Mat2X x(2, X.cols()); - Project(P, X, &x); - return x; -} - -inline Mat2X Project(const Mat34 &P, const Mat3X &X, const Vecu &ids) { - Mat2X x(2, ids.size()); - Project(P, X, ids, &x); - return x; -} - -double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X); -double Depth(const Mat3 &R, const Vec3 &t, const Vec4 &X); - -/** -* Returns true if the homogenious 3D point X is in front of -* the camera P. -*/ -inline bool isInFrontOfCamera(const Mat34 &P, const Vec4 &X) { - double condition_1 = P.row(2).dot(X) * X[3]; - double condition_2 = X[2] * X[3]; - if (condition_1 > 0 && condition_2 > 0) - return true; - else - return false; -} - -inline bool isInFrontOfCamera(const Mat34 &P, const Vec3 &X) { - Vec4 X_homo; - X_homo.segment<3>(0) = X; - X_homo(3) = 1; - return isInFrontOfCamera( P, X_homo); -} - -/** -* Transforms a 2D point from pixel image coordinates to a 2D point in -* normalized image coordinates. -*/ -inline Vec2 ImageToNormImageCoordinates(Mat3 &Kinverse, Vec2 &x) { - Vec3 x_h = Kinverse*EuclideanToHomogeneous(x); - return HomogeneousToEuclidean( x_h ); -} - -/// Estimates the root mean square error (2D) -inline double RootMeanSquareError(const Mat2X &x_image, - const Mat4X &X_world, - const Mat34 &P) { - size_t num_points = x_image.cols(); - Mat2X dx = Project(P, X_world) - x_image; - return dx.norm() / num_points; -} - -/// Estimates the root mean square error (2D) -inline double RootMeanSquareError(const Mat2X &x_image, - const Mat3X &X_world, - const Mat3 &K, - const Mat3 &R, - const Vec3 &t) { - Mat34 P; - P_From_KRt(K, R, t, &P); - size_t num_points = x_image.cols(); - Mat2X dx = Project(P, X_world) - x_image; - return dx.norm() / num_points; -} -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_PROJECTION_H_ diff --git a/extern/libmv/libmv/multiview/projection_test.cc b/extern/libmv/libmv/multiview/projection_test.cc deleted file mode 100644 index c060bfb0681..00000000000 --- a/extern/libmv/libmv/multiview/projection_test.cc +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include - -#include "libmv/multiview/projection.h" -#include "libmv/numeric/numeric.h" -#include "testing/testing.h" - -namespace { -using namespace libmv; - -TEST(Projection, P_From_KRt) { - Mat3 K, Kp; - K << 10, 1, 30, - 0, 20, 40, - 0, 0, 1; - - Mat3 R, Rp; - R << 1, 0, 0, - 0, 1, 0, - 0, 0, 1; - - Vec3 t, tp; - t << 1, 2, 3; - - Mat34 P; - P_From_KRt(K, R, t, &P); - KRt_From_P(P, &Kp, &Rp, &tp); - - EXPECT_MATRIX_NEAR(K, Kp, 1e-8); - EXPECT_MATRIX_NEAR(R, Rp, 1e-8); - EXPECT_MATRIX_NEAR(t, tp, 1e-8); - - // TODO(keir): Change the code to ensure det(R) == 1, which is not currently - // the case. Also add a test for that here. -} - -Vec4 GetRandomPoint() { - Vec4 X; - X.setRandom(); - X(3) = 1; - return X; -} - -TEST(Projection, isInFrontOfCamera) { - Mat34 P; - P << 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0; - - Vec4 X_front = GetRandomPoint(); - Vec4 X_back = GetRandomPoint(); - X_front(2) = 10; // Any point in the positive Z direction - // where Z > 1 is infront of the camera. - X_back(2) = -10; // Any point int he negative Z dirstaion - // is behind the camera. - - bool res_front = isInFrontOfCamera(P, X_front); - bool res_back = isInFrontOfCamera(P, X_back); - - EXPECT_EQ(true, res_front); - EXPECT_EQ(false, res_back); -} - -TEST(AutoCalibration, ProjectionShiftPrincipalPoint) { - Mat34 P1, P2; - P1 << 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0; - P2 << 1, 0, 3, 0, - 0, 1, 4, 0, - 0, 0, 1, 0; - Mat34 P1_computed, P2_computed; - ProjectionShiftPrincipalPoint(P1, Vec2(0, 0), Vec2(3, 4), &P2_computed); - ProjectionShiftPrincipalPoint(P2, Vec2(3, 4), Vec2(0, 0), &P1_computed); - - EXPECT_MATRIX_EQ(P1, P1_computed); - EXPECT_MATRIX_EQ(P2, P2_computed); -} - -TEST(AutoCalibration, ProjectionChangeAspectRatio) { - Mat34 P1, P2; - P1 << 1, 0, 3, 0, - 0, 1, 4, 0, - 0, 0, 1, 0; - P2 << 1, 0, 3, 0, - 0, 2, 4, 0, - 0, 0, 1, 0; - Mat34 P1_computed, P2_computed; - ProjectionChangeAspectRatio(P1, Vec2(3, 4), 1, 2, &P2_computed); - ProjectionChangeAspectRatio(P2, Vec2(3, 4), 2, 1, &P1_computed); - - EXPECT_MATRIX_EQ(P1, P1_computed); - EXPECT_MATRIX_EQ(P2, P2_computed); -} - -} // namespace diff --git a/extern/libmv/libmv/multiview/resection.h b/extern/libmv/libmv/multiview/resection.h deleted file mode 100644 index c142d6deeb2..00000000000 --- a/extern/libmv/libmv/multiview/resection.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Compute the projection matrix from a set of 3D points X and their -// projections x = PX in 2D. This is useful if a point cloud is reconstructed. -// -// Algorithm is the standard DLT as described in Hartley & Zisserman, page 179. - -#ifndef LIBMV_MULTIVIEW_RESECTION_H -#define LIBMV_MULTIVIEW_RESECTION_H - -#include "libmv/logging/logging.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { -namespace resection { - -// x's are 2D image coordinates, (x,y,1), and X's are homogeneous four vectors. -template -void Resection(const Matrix &x, - const Matrix &X, - Matrix *P) { - int N = x.cols(); - assert(X.cols() == N); - - Matrix design(2*N, 12); - design.setZero(); - for (int i = 0; i < N; i++) { - T xi = x(0, i); - T yi = x(1, i); - // See equation (7.2) on page 179 of H&Z. - design.template block<1, 4>(2*i, 4) = -X.col(i).transpose(); - design.template block<1, 4>(2*i, 8) = yi*X.col(i).transpose(); - design.template block<1, 4>(2*i + 1, 0) = X.col(i).transpose(); - design.template block<1, 4>(2*i + 1, 8) = -xi*X.col(i).transpose(); - } - Matrix p; - Nullspace(&design, &p); - reshape(p, 3, 4, P); -} - -} // namespace resection -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_RESECTION_H diff --git a/extern/libmv/libmv/multiview/resection_test.cc b/extern/libmv/libmv/multiview/resection_test.cc deleted file mode 100644 index 368e2281cfa..00000000000 --- a/extern/libmv/libmv/multiview/resection_test.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include - -#include "libmv/multiview/projection.h" -#include "libmv/multiview/resection.h" -#include "libmv/multiview/test_data_sets.h" -#include "libmv/numeric/numeric.h" -#include "testing/testing.h" -#include "libmv/logging/logging.h" - -namespace { - -using namespace libmv; -using namespace libmv::resection; - -TEST(Resection, ThreeViews) { - int nviews = 5; - int npoints = 6; - NViewDataSet d = NRealisticCamerasFull(nviews, npoints); - for (int i = 0; i < nviews; ++i) { - Mat4X X(4, npoints); - X.block(0, 0, 3, npoints) = d.X; - X.row(3).setOnes(); - const Mat2X &x = d.x[i]; - Mat34 P; - Resection(x, X, &P); - Mat34 P_expected = d.P(i); - - // Because the P matrices are homogeneous, it is necessary to be tricky - // about the scale factor to make them match. - P_expected *= 1/P_expected.array().abs().sum(); - P *= 1/P.array().abs().sum(); - if (!((P(0, 0) > 0 && P_expected(0, 0) > 0) || - (P(0, 0) < 0 && P_expected(0, 0) < 0))) { - P *= -1; - } - - EXPECT_MATRIX_NEAR(P_expected, P, 1e-9); - } -} - -} // namespace diff --git a/extern/libmv/libmv/multiview/test_data_sets.cc b/extern/libmv/libmv/multiview/test_data_sets.cc deleted file mode 100644 index 110bde6f762..00000000000 --- a/extern/libmv/libmv/multiview/test_data_sets.cc +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/multiview/test_data_sets.h" - -#include - -#include "libmv/numeric/numeric.h" -#include "libmv/multiview/projection.h" -#include "libmv/multiview/fundamental.h" - -namespace libmv { - -TwoViewDataSet TwoRealisticCameras(bool same_K) { - TwoViewDataSet d; - - d.K1 << 320, 0, 160, - 0, 320, 120, - 0, 0, 1; - if (same_K) { - d.K2 = d.K1; - } else { - d.K2 << 360, 0, 170, - 0, 360, 110, - 0, 0, 1; - } - d.R1 = RotationAroundZ(-0.1); - d.R2 = RotationAroundX(-0.1); - d.t1 << 1, 1, 10; - d.t2 << -2, -1, 10; - P_From_KRt(d.K1, d.R1, d.t1, &d.P1); - P_From_KRt(d.K2, d.R2, d.t2, &d.P2); - - FundamentalFromProjections(d.P1, d.P2, &d.F); - - d.X.resize(3, 30); - d.X.setRandom(); - - Project(d.P1, d.X, &d.x1); - Project(d.P2, d.X, &d.x2); - - return d; -} - -nViewDatasetConfigator::nViewDatasetConfigator(int fx , int fy, - int cx, int cy, - double distance, - double jitter_amount) { - _fx = fx; - _fy = fy; - _cx = cx; - _cy = cy; - _dist = distance; - _jitter_amount = jitter_amount; -} - -NViewDataSet NRealisticCamerasFull(int nviews, int npoints, - const nViewDatasetConfigator config) { - NViewDataSet d; - d.n = nviews; - d.K.resize(nviews); - d.R.resize(nviews); - d.t.resize(nviews); - d.C.resize(nviews); - d.x.resize(nviews); - d.x_ids.resize(nviews); - - d.X.resize(3, npoints); - d.X.setRandom(); - d.X *= 0.6; - - Vecu all_point_ids(npoints); - for (size_t j = 0; j < npoints; ++j) - all_point_ids[j] = j; - - for (size_t i = 0; i < nviews; ++i) { - Vec3 camera_center, t, jitter, lookdir; - - double theta = i * 2 * M_PI / nviews; - camera_center << sin(theta), 0.0, cos(theta); - camera_center *= config._dist; - d.C[i] = camera_center; - - jitter.setRandom(); - jitter *= config._jitter_amount / camera_center.norm(); - lookdir = -camera_center + jitter; - - d.K[i] << config._fx, 0, config._cx, - 0, config._fy, config._cy, - 0, 0, 1; - d.R[i] = LookAt(lookdir); - d.t[i] = -d.R[i] * camera_center; - d.x[i] = Project(d.P(i), d.X); - d.x_ids[i] = all_point_ids; - } - return d; -} - - -NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, - float view_ratio, unsigned min_projections, - const nViewDatasetConfigator config) { - assert(view_ratio <= 1.0); - assert(view_ratio > 0.0); - assert(min_projections <= npoints); - NViewDataSet d; - d.n = nviews; - d.K.resize(nviews); - d.R.resize(nviews); - d.t.resize(nviews); - d.C.resize(nviews); - d.x.resize(nviews); - d.x_ids.resize(nviews); - - d.X.resize(3, npoints); - d.X.setRandom(); - d.X *= 0.6; - - Mat visibility(nviews, npoints); - visibility.setZero(); - Mat randoms(nviews, npoints); - randoms.setRandom(); - randoms = (randoms.array() + 1)/2.0; - unsigned num_visibles = 0; - for (size_t i = 0; i < nviews; ++i) { - num_visibles = 0; - for (size_t j = 0; j < npoints; j++) { - if (randoms(i, j) <= view_ratio) { - visibility(i, j) = true; - num_visibles++; - } - } - if (num_visibles < min_projections) { - unsigned num_projections_to_add = min_projections - num_visibles; - for (size_t j = 0; j < npoints && num_projections_to_add > 0; ++j) { - if (!visibility(i, j)) { - num_projections_to_add--; - } - } - num_visibles += num_projections_to_add; - } - d.x_ids[i].resize(num_visibles); - d.x[i].resize(2, num_visibles); - } - - size_t j_visible = 0; - Vec3 X; - for (size_t i = 0; i < nviews; ++i) { - Vec3 camera_center, t, jitter, lookdir; - - double theta = i * 2 * M_PI / nviews; - camera_center << sin(theta), 0.0, cos(theta); - camera_center *= config._dist; - d.C[i] = camera_center; - - jitter.setRandom(); - jitter *= config._jitter_amount / camera_center.norm(); - lookdir = -camera_center + jitter; - - d.K[i] << config._fx, 0, config._cx, - 0, config._fy, config._cy, - 0, 0, 1; - d.R[i] = LookAt(lookdir); - d.t[i] = -d.R[i] * camera_center; - j_visible = 0; - for (size_t j = 0; j < npoints; j++) { - if (visibility(i, j)) { - X = d.X.col(j); - d.x[i].col(j_visible) = Project(d.P(i), X); - d.x_ids[i][j_visible] = j; - j_visible++; - } - } - } - return d; -} - - -} // namespace libmv diff --git a/extern/libmv/libmv/multiview/test_data_sets.h b/extern/libmv/libmv/multiview/test_data_sets.h deleted file mode 100644 index cf01663ca02..00000000000 --- a/extern/libmv/libmv/multiview/test_data_sets.h +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_TEST_DATA_SETS_H_ -#define LIBMV_MULTIVIEW_TEST_DATA_SETS_H_ - -#include "libmv/base/vector.h" -#include "libmv/multiview/fundamental.h" -#include "libmv/multiview/projection.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { - -struct TwoViewDataSet { - Mat3 K1, K2; // Internal parameters. - Mat3 R1, R2; // Rotation. - Vec3 t1, t2; // Translation. - Mat34 P1, P2; // Projection matrix, P = K(R|t) - Mat3 F; // Fundamental matrix. - Mat3X X; // 3D points. - Mat2X x1, x2; // Projected points. -}; - -// Two cameras at (-1,-1,-10) and (2,1,-10) looking approximately towards z+. -TwoViewDataSet TwoRealisticCameras(bool same_K = false); - -// An N-view metric dataset . An important difference between this -// and the other reconstruction data types is that all points are seen by all -// cameras. -struct NViewDataSet { - vector K; // Internal parameters (fx, fy, etc). - vector R; // Rotation. - vector t; // Translation. - vector C; // Camera centers. - Mat3X X; // 3D points. - vector x; // Projected points; may have noise added. - vector x_ids; // Indexes of points corresponding to the projections - - int n; // Actual number of cameras. - - Mat34 P(int i) { - assert(i < n); - return K[i] * HStack(R[i], t[i]); - } - Mat3 F(int i, int j) { - Mat3 F_; - FundamentalFromProjections(P(i), P(j), &F_); - return F_; - } - void Reproject() { - for (int i = 0; i < n; ++i) { - x[i] = Project(P(i), X); - } - } - // TODO(keir): Add gaussian jitter functions. -}; - -struct nViewDatasetConfigator { - /// Internal camera parameters - int _fx; - int _fy; - int _cx; - int _cy; - - /// Camera random position parameters - double _dist; - double _jitter_amount; - - nViewDatasetConfigator(int fx = 1000, int fy = 1000, - int cx = 500, int cy = 500, - double distance = 1.5, - double jitter_amount = 0.01); -}; - -NViewDataSet NRealisticCamerasFull(int nviews, int npoints, - const nViewDatasetConfigator - config = nViewDatasetConfigator()); - -// Generates sparse projections (not all points are projected) -NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, - float view_ratio = 0.6, - unsigned min_projections = 3, - const nViewDatasetConfigator - config = nViewDatasetConfigator()); - -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_TEST_DATA_SETS_H_ diff --git a/extern/libmv/libmv/multiview/triangulation.cc b/extern/libmv/libmv/multiview/triangulation.cc deleted file mode 100644 index 4d146c8f21b..00000000000 --- a/extern/libmv/libmv/multiview/triangulation.cc +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/multiview/triangulation.h" - -#include "libmv/numeric/numeric.h" -#include "libmv/multiview/projection.h" - -namespace libmv { - -// HZ 12.2 pag.312 -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec4 *X_homogeneous) { - Mat4 design; - for (int i = 0; i < 4; ++i) { - design(0, i) = x1(0) * P1(2, i) - P1(0, i); - design(1, i) = x1(1) * P1(2, i) - P1(1, i); - design(2, i) = x2(0) * P2(2, i) - P2(0, i); - design(3, i) = x2(1) * P2(2, i) - P2(1, i); - } - Nullspace(&design, X_homogeneous); -} - -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec3 *X_euclidean) { - Vec4 X_homogeneous; - TriangulateDLT(P1, x1, P2, x2, &X_homogeneous); - HomogeneousToEuclidean(X_homogeneous, X_euclidean); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/multiview/triangulation.h b/extern/libmv/libmv/multiview/triangulation.h deleted file mode 100644 index be878890242..00000000000 --- a/extern/libmv/libmv/multiview/triangulation.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_TRIANGULATION_H_ -#define LIBMV_MULTIVIEW_TRIANGULATION_H_ - -#include "libmv/numeric/numeric.h" - -namespace libmv { - -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec4 *X_homogeneous); - -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec3 *X_euclidean); - -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_TRIANGULATION_H_ diff --git a/extern/libmv/libmv/multiview/triangulation_test.cc b/extern/libmv/libmv/multiview/triangulation_test.cc deleted file mode 100644 index 66d1ee25a62..00000000000 --- a/extern/libmv/libmv/multiview/triangulation_test.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include - -#include "libmv/multiview/triangulation.h" -#include "libmv/multiview/fundamental.h" -#include "libmv/multiview/projection.h" -#include "libmv/multiview/test_data_sets.h" -#include "libmv/numeric/numeric.h" -#include "testing/testing.h" - -namespace { -using namespace libmv; - -TEST(Triangulation, TriangulateDLT) { - TwoViewDataSet d = TwoRealisticCameras(); - - for (int i = 0; i < d.X.cols(); ++i) { - Vec2 x1, x2; - MatrixColumn(d.x1, i, &x1); - MatrixColumn(d.x2, i, &x2); - Vec3 X_estimated, X_gt; - MatrixColumn(d.X, i, &X_gt); - TriangulateDLT(d.P1, x1, d.P2, x2, &X_estimated); - EXPECT_NEAR(0, DistanceLInfinity(X_estimated, X_gt), 1e-8); - } -} - -} // namespace diff --git a/extern/libmv/libmv/multiview/two_view_kernel.h b/extern/libmv/libmv/multiview/two_view_kernel.h deleted file mode 100644 index 7af0ed5ddab..00000000000 --- a/extern/libmv/libmv/multiview/two_view_kernel.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_MULTIVIEW_TWO_VIEW_KERNEL_H_ -#define LIBMV_MULTIVIEW_TWO_VIEW_KERNEL_H_ - -#include "libmv/base/vector.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/conditioning.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { -namespace two_view { -namespace kernel { - -template -struct NormalizedSolver { - enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES }; - static void Solve(const Mat &x1, const Mat &x2, vector *models) { - assert(2 == x1.rows()); - assert(MINIMUM_SAMPLES <= x1.cols()); - assert(x1.rows() == x2.rows()); - assert(x1.cols() == x2.cols()); - - // Normalize the data. - Mat3 T1, T2; - Mat x1_normalized, x2_normalized; - NormalizePoints(x1, &x1_normalized, &T1); - NormalizePoints(x2, &x2_normalized, &T2); - - Solver::Solve(x1_normalized, x2_normalized, models); - - for (int i = 0; i < models->size(); ++i) { - Unnormalizer::Unnormalize(T1, T2, &(*models)[i]); - } - } -}; - -template -struct IsotropicNormalizedSolver { - enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES }; - static void Solve(const Mat &x1, const Mat &x2, vector *models) { - assert(2 == x1.rows()); - assert(MINIMUM_SAMPLES <= x1.cols()); - assert(x1.rows() == x2.rows()); - assert(x1.cols() == x2.cols()); - - // Normalize the data. - Mat3 T1, T2; - Mat x1_normalized, x2_normalized; - NormalizeIsotropicPoints(x1, &x1_normalized, &T1); - NormalizeIsotropicPoints(x2, &x2_normalized, &T2); - - Solver::Solve(x1_normalized, x2_normalized, models); - - for (int i = 0; i < models->size(); ++i) { - Unnormalizer::Unnormalize(T1, T2, &(*models)[i]); - } - } -}; -// This is one example (targeted at solvers that operate on correspondences -// between two views) that shows the "kernel" part of a robust fitting -// problem: -// -// 1. The model; Mat3 in the case of the F or H matrix. -// 2. The minimum number of samples needed to fit; 7 or 8 (or 4). -// 3. A way to convert samples to a model. -// 4. A way to convert a sample and a model to an error. -// -// Of particular note is that the kernel does not expose what the samples are. -// All the robust fitting algorithm sees is that there is some number of -// samples; it is able to fit subsets of them (via the kernel) and check their -// error, but can never access the samples themselves. -// -// The Kernel objects must follow the following concept so that the robust -// fitting alogrithm can fit this type of relation: -// -// 1. Kernel::Model -// 2. Kernel::MINIMUM_SAMPLES -// 3. Kernel::Fit(vector, vector *) -// 4. Kernel::Error(int, Model) -> error -// -// The fit routine must not clear existing entries in the vector of models; it -// should append new solutions to the end. -template -class Kernel { - public: - Kernel(const Mat &x1, const Mat &x2) : x1_(x1), x2_(x2) {} - typedef SolverArg Solver; - typedef ModelArg Model; - enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES }; - void Fit(const vector &samples, vector *models) const { - Mat x1 = ExtractColumns(x1_, samples); - Mat x2 = ExtractColumns(x2_, samples); - Solver::Solve(x1, x2, models); - } - double Error(int sample, const Model &model) const { - return ErrorArg::Error(model, - static_cast(x1_.col(sample)), - static_cast(x2_.col(sample))); - } - int NumSamples() const { - return x1_.cols(); - } - static void Solve(const Mat &x1, const Mat &x2, vector *models) { - // By offering this, Kernel types can be passed to templates. - Solver::Solve(x1, x2, models); - } - protected: - const Mat &x1_; - const Mat &x2_; -}; - -} // namespace kernel -} // namespace two_view -} // namespace libmv - -#endif // LIBMV_MULTIVIEW_TWO_VIEW_KERNEL_H_ diff --git a/extern/libmv/libmv/numeric/dogleg.h b/extern/libmv/libmv/numeric/dogleg.h deleted file mode 100644 index bf6f996ddaf..00000000000 --- a/extern/libmv/libmv/numeric/dogleg.h +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) 2007, 2008, 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// A simple implementation of Powell's dogleg nonlinear minimization. -// -// [1] K. Madsen, H. Nielsen, O. Tingleoff. Methods for Non-linear Least -// Squares Problems. -// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf -// -// TODO(keir): Cite the Lourakis' dogleg paper. - -#ifndef LIBMV_NUMERIC_DOGLEG_H -#define LIBMV_NUMERIC_DOGLEG_H - -#include -#include - -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/function_derivative.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -template, - typename Solver = Eigen::PartialPivLU< - Matrix > > -class Dogleg { - public: - typedef typename Function::XMatrixType::RealScalar Scalar; - typedef typename Function::FMatrixType FVec; - typedef typename Function::XMatrixType Parameters; - typedef Matrix JMatrixType; - typedef Matrix AMatrixType; - - enum Status { - RUNNING, - GRADIENT_TOO_SMALL, // eps > max(J'*f(x)) - RELATIVE_STEP_SIZE_TOO_SMALL, // eps > ||dx|| / ||x|| - TRUST_REGION_TOO_SMALL, // eps > radius / ||x|| - ERROR_TOO_SMALL, // eps > ||f(x)|| - HIT_MAX_ITERATIONS, - }; - - enum Step { - DOGLEG, - GAUSS_NEWTON, - STEEPEST_DESCENT, - }; - - Dogleg(const Function &f) - : f_(f), df_(f) {} - - struct SolverParameters { - SolverParameters() - : gradient_threshold(1e-16), - relative_step_threshold(1e-16), - error_threshold(1e-16), - initial_trust_radius(1e0), - max_iterations(500) {} - Scalar gradient_threshold; // eps > max(J'*f(x)) - Scalar relative_step_threshold; // eps > ||dx|| / ||x|| - Scalar error_threshold; // eps > ||f(x)|| - Scalar initial_trust_radius; // Initial u for solving normal equations. - int max_iterations; // Maximum number of solver iterations. - }; - - struct Results { - Scalar error_magnitude; // ||f(x)|| - Scalar gradient_magnitude; // ||J'f(x)|| - int iterations; - Status status; - }; - - Status Update(const Parameters &x, const SolverParameters ¶ms, - JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) { - *J = df_(x); - // TODO(keir): In the case of m = n, avoid computing A and just do J^-1 directly. - *A = (*J).transpose() * (*J); - *error = f_(x); - *g = (*J).transpose() * *error; - if (g->array().abs().maxCoeff() < params.gradient_threshold) { - return GRADIENT_TOO_SMALL; - } else if (error->array().abs().maxCoeff() < params.error_threshold) { - return ERROR_TOO_SMALL; - } - return RUNNING; - } - - Step SolveDoglegDirection(const Parameters &dx_sd, - const Parameters &dx_gn, - Scalar radius, - Scalar alpha, - Parameters *dx_dl, - Scalar *beta) { - Parameters a, b_minus_a; - // Solve for Dogleg step dx_dl. - if (dx_gn.norm() < radius) { - *dx_dl = dx_gn; - return GAUSS_NEWTON; - - } else if (alpha * dx_sd.norm() > radius) { - *dx_dl = (radius / dx_sd.norm()) * dx_sd; - return STEEPEST_DESCENT; - - } else { - Parameters a = alpha * dx_sd; - const Parameters &b = dx_gn; - b_minus_a = a - b; - Scalar Mbma2 = b_minus_a.squaredNorm(); - Scalar Ma2 = a.squaredNorm(); - Scalar c = a.dot(b_minus_a); - Scalar radius2 = radius*radius; - if (c <= 0) { - *beta = (-c + sqrt(c*c + Mbma2*(radius2 - Ma2)))/(Mbma2); - } else { - *beta = (radius2 - Ma2) / - (c + sqrt(c*c + Mbma2*(radius2 - Ma2))); - } - *dx_dl = alpha * dx_sd + (*beta) * (dx_gn - alpha*dx_sd); - return DOGLEG; - } - } - - Results minimize(Parameters *x_and_min) { - SolverParameters params; - return minimize(params, x_and_min); - } - - Results minimize(const SolverParameters ¶ms, Parameters *x_and_min) { - Parameters &x = *x_and_min; - JMatrixType J; - AMatrixType A; - FVec error; - Parameters g; - - Results results; - results.status = Update(x, params, &J, &A, &error, &g); - - Scalar radius = params.initial_trust_radius; - bool x_updated = true; - - Parameters x_new; - Parameters dx_sd; // Steepest descent step. - Parameters dx_dl; // Dogleg step. - Parameters dx_gn; // Gauss-Newton step. - printf("iteration ||f(x)|| max(g) radius\n"); - int i = 0; - for (; results.status == RUNNING && i < params.max_iterations; ++i) { - printf("%9d %12g %12g %12g", - i, f_(x).norm(), g.array().abs().maxCoeff(), radius); - - //LG << "iteration: " << i; - //LG << "||f(x)||: " << f_(x).norm(); - //LG << "max(g): " << g.cwise().abs().maxCoeff(); - //LG << "radius: " << radius; - // Eqn 3.19 from [1] - Scalar alpha = g.squaredNorm() / (J*g).squaredNorm(); - - // Solve for steepest descent direction dx_sd. - dx_sd = -g; - - // Solve for Gauss-Newton direction dx_gn. - if (x_updated) { - // TODO(keir): See Appendix B of [1] for discussion of when A is - // singular and there are many solutions. Solving that involves the SVD - // and is slower, but should still work. - Solver solver(A); - dx_gn = solver.solve(-g); - if (!(A * dx_gn).isApprox(-g)) { - LOG(ERROR) << "Failed to solve normal eqns. TODO: Solve via SVD."; - return results; - } - x_updated = false; - } - - // Solve for dogleg direction dx_dl. - Scalar beta = 0; - Step step = SolveDoglegDirection(dx_sd, dx_gn, radius, alpha, - &dx_dl, &beta); - - Scalar e3 = params.relative_step_threshold; - if (dx_dl.norm() < e3*(x.norm() + e3)) { - results.status = RELATIVE_STEP_SIZE_TOO_SMALL; - break; - } - - x_new = x + dx_dl; - Scalar actual = f_(x).squaredNorm() - f_(x_new).squaredNorm(); - Scalar predicted = 0; - if (step == GAUSS_NEWTON) { - predicted = f_(x).squaredNorm(); - } else if (step == STEEPEST_DESCENT) { - predicted = radius * (2*alpha*g.norm() - radius) / 2 / alpha; - } else if (step == DOGLEG) { - predicted = 0.5 * alpha * (1-beta)*(1-beta)*g.squaredNorm() + - beta*(2-beta)*f_(x).squaredNorm(); - } - Scalar rho = actual / predicted; - - if (step == GAUSS_NEWTON) printf(" GAUSS"); - if (step == STEEPEST_DESCENT) printf(" STEE"); - if (step == DOGLEG) printf(" DOGL"); - - printf(" %12g %12g %12g\n", rho, actual, predicted); - - if (rho > 0) { - // Accept update because the linear model is a good fit. - x = x_new; - results.status = Update(x, params, &J, &A, &error, &g); - x_updated = true; - } - if (rho > 0.75) { - radius = std::max(radius, 3*dx_dl.norm()); - } else if (rho < 0.25) { - radius /= 2; - if (radius < e3 * (x.norm() + e3)) { - results.status = TRUST_REGION_TOO_SMALL; - } - } - } - if (results.status == RUNNING) { - results.status = HIT_MAX_ITERATIONS; - } - results.error_magnitude = error.norm(); - results.gradient_magnitude = g.norm(); - results.iterations = i; - return results; - } - - private: - const Function &f_; - Jacobian df_; -}; - -} // namespace mv - -#endif // LIBMV_NUMERIC_DOGLEG_H diff --git a/extern/libmv/libmv/numeric/dogleg_test.cc b/extern/libmv/libmv/numeric/dogleg_test.cc deleted file mode 100644 index 90c46c31672..00000000000 --- a/extern/libmv/libmv/numeric/dogleg_test.cc +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "testing/testing.h" -#include "libmv/numeric/dogleg.h" - -using namespace libmv; - -namespace { - -class F { - public: - typedef Vec4 FMatrixType; - typedef Vec3 XMatrixType; - Vec4 operator()(const Vec3 &x) const { - double x1 = x.x() - 2; - double y1 = x.y() - 5; - double z1 = x.z(); - Vec4 fx; fx << x1*x1 + z1*z1, - y1*y1 + z1*z1, - z1*z1, - x1*x1; - return fx; - } -}; - -TEST(Dogleg, SimpleCase) { - Vec3 x; x << 0.76026643, -30.01799744, 0.55192142; - F f; - Dogleg::SolverParameters params; - Dogleg lm(f); - /* TODO(sergey): Better error handling. */ - /* Dogleg::Results results = */ lm.minimize(params, &x); - Vec3 expected_min_x; expected_min_x << 2, 5, 0; - - EXPECT_MATRIX_NEAR(expected_min_x, x, 1e-5); -} - -// Example 3.2 from [1]; page 11 of the pdf, 20 of the document. This is a -// tricky problem because of the singluar Jacobian near the origin. -class F32 { - public: - typedef Vec2 FMatrixType; - typedef Vec2 XMatrixType; - Vec2 operator()(const Vec2 &x) const { - double x1 = x(0); - double x2 = 10*x(0)/(x(0) + 0.1) + 2*x(1)*x(1); - Vec2 fx; fx << x1, x2; - return fx; - } -}; - -class JF32 { - public: - JF32(const F32 &f) { (void) f; } - Mat2 operator()(const Vec2 &x) { - Mat2 J; J << 1, 0, - 1./pow(x(0) + 0.1, 2), 4*x(1)*x(1); - return J; - } -}; - -// TODO(keir): Re-enable this when the dogleg code properly handles singular -// normal equations. -/* -TEST(Dogleg, Example32) { - Vec2 x; x << 3, 1; - F32 f; - CheckJacobian(f, x); - Dogleg dogleg(f); - Dogleg::Results results = dogleg.minimize(&x); - Vec2 expected_min_x; expected_min_x << 0, 0; - - EXPECT_MATRIX_NEAR(expected_min_x, x, 1e-5); -} -*/ - -} // namespace diff --git a/extern/libmv/libmv/numeric/function_derivative.h b/extern/libmv/libmv/numeric/function_derivative.h deleted file mode 100644 index 9820885f04e..00000000000 --- a/extern/libmv/libmv/numeric/function_derivative.h +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2007, 2008, 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_NUMERIC_DERIVATIVE_H -#define LIBMV_NUMERIC_DERIVATIVE_H - -#include - -#include "libmv/numeric/numeric.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -// Numeric derivative of a function. -// TODO(keir): Consider adding a quadratic approximation. - -enum NumericJacobianMode { - CENTRAL, - FORWARD, -}; - -template -class NumericJacobian { - public: - typedef typename Function::XMatrixType Parameters; - typedef typename Function::XMatrixType::RealScalar XScalar; - typedef typename Function::FMatrixType FMatrixType; - typedef Matrix - JMatrixType; - - NumericJacobian(const Function &f) : f_(f) {} - - // TODO(keir): Perhaps passing the jacobian back by value is not a good idea. - JMatrixType operator()(const Parameters &x) { - // Empirically determined constant. - Parameters eps = x.array().abs() * XScalar(1e-5); - // To handle cases where a paremeter is exactly zero, instead use the mean - // eps for the other dimensions. - XScalar mean_eps = eps.sum() / eps.rows(); - if (mean_eps == XScalar(0)) { - // TODO(keir): Do something better here. - mean_eps = 1e-8; // ~sqrt(machine precision). - } - // TODO(keir): Elimininate this needless function evaluation for the - // central difference case. - FMatrixType fx = f_(x); - const int rows = fx.rows(); - const int cols = x.rows(); - JMatrixType jacobian(rows, cols); - Parameters x_plus_delta = x; - for (int c = 0; c < cols; ++c) { - if (eps(c) == XScalar(0)) { - eps(c) = mean_eps; - } - x_plus_delta(c) = x(c) + eps(c); - jacobian.col(c) = f_(x_plus_delta); - - XScalar one_over_h = 1 / eps(c); - if (mode == CENTRAL) { - x_plus_delta(c) = x(c) - eps(c); - jacobian.col(c) -= f_(x_plus_delta); - one_over_h /= 2; - } else { - jacobian.col(c) -= fx; - } - x_plus_delta(c) = x(c); - jacobian.col(c) = jacobian.col(c) * one_over_h; - } - return jacobian; - } - private: - const Function &f_; -}; - -template -bool CheckJacobian(const Function &f, const typename Function::XMatrixType &x) { - Jacobian j_analytic(f); - NumericJacobian j_numeric(f); - - typename NumericJacobian::JMatrixType J_numeric = j_numeric(x); - typename NumericJacobian::JMatrixType J_analytic = j_analytic(x); - LG << J_numeric - J_analytic; - return true; -} - -} // namespace libmv - -#endif // LIBMV_NUMERIC_DERIVATIVE_H diff --git a/extern/libmv/libmv/numeric/function_derivative_test.cc b/extern/libmv/libmv/numeric/function_derivative_test.cc deleted file mode 100644 index 8d976d3e9a0..00000000000 --- a/extern/libmv/libmv/numeric/function_derivative_test.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2007, 2008, 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "testing/testing.h" -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/function_derivative.h" - -using namespace libmv; - -namespace { - -class F { - public: - typedef Vec2 FMatrixType; - typedef Vec3 XMatrixType; - Vec2 operator()(const Vec3 &x) const { - Vec2 fx; - fx << 0.19*x(0) + 0.19*x(1)*x(1) + x(2), - 3*sin(x(0)) + 2*cos(x(1)); - return fx; - } - Mat23 J(const Vec3 &x) const { - Mat23 jacobian; - jacobian << 0.19, 2*0.19*x(1), 1.0, - 3*cos(x(0)), -2*sin(x(1)), 0; - return jacobian; - } -}; - -TEST(FunctionDerivative, SimpleCase) { - Vec3 x; x << 0.76026643, 0.01799744, 0.55192142; - F f; - NumericJacobian J(f); - EXPECT_MATRIX_NEAR(f.J(x), J(x), 1e-8); - NumericJacobian J_forward(f); - // Forward difference is very inaccurate. - EXPECT_MATRIX_NEAR(f.J(x), J_forward(x), 1e-5); -} - -} // namespace diff --git a/extern/libmv/libmv/numeric/levenberg_marquardt.h b/extern/libmv/libmv/numeric/levenberg_marquardt.h deleted file mode 100644 index 2af9a62cf7b..00000000000 --- a/extern/libmv/libmv/numeric/levenberg_marquardt.h +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) 2007, 2008, 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// A simple implementation of levenberg marquardt. -// -// [1] K. Madsen, H. Nielsen, O. Tingleoff. Methods for Non-linear Least -// Squares Problems. -// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf -// -// TODO(keir): Cite the Lourakis' dogleg paper. - -#ifndef LIBMV_NUMERIC_LEVENBERG_MARQUARDT_H -#define LIBMV_NUMERIC_LEVENBERG_MARQUARDT_H - -#include - -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/function_derivative.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -template, - typename Solver = Eigen::PartialPivLU< - Matrix > > -class LevenbergMarquardt { - public: - typedef typename Function::XMatrixType::RealScalar Scalar; - typedef typename Function::FMatrixType FVec; - typedef typename Function::XMatrixType Parameters; - typedef Matrix JMatrixType; - typedef Matrix AMatrixType; - - // TODO(keir): Some of these knobs can be derived from each other and - // removed, instead of requiring the user to set them. - enum Status { - RUNNING, - GRADIENT_TOO_SMALL, // eps > max(J'*f(x)) - RELATIVE_STEP_SIZE_TOO_SMALL, // eps > ||dx|| / ||x|| - ERROR_TOO_SMALL, // eps > ||f(x)|| - HIT_MAX_ITERATIONS, - }; - - LevenbergMarquardt(const Function &f) - : f_(f), df_(f) {} - - struct SolverParameters { - SolverParameters() - : gradient_threshold(1e-16), - relative_step_threshold(1e-16), - error_threshold(1e-16), - initial_scale_factor(1e-3), - max_iterations(100) {} - Scalar gradient_threshold; // eps > max(J'*f(x)) - Scalar relative_step_threshold; // eps > ||dx|| / ||x|| - Scalar error_threshold; // eps > ||f(x)|| - Scalar initial_scale_factor; // Initial u for solving normal equations. - int max_iterations; // Maximum number of solver iterations. - }; - - struct Results { - Scalar error_magnitude; // ||f(x)|| - Scalar gradient_magnitude; // ||J'f(x)|| - int iterations; - Status status; - }; - - Status Update(const Parameters &x, const SolverParameters ¶ms, - JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) { - *J = df_(x); - *A = (*J).transpose() * (*J); - *error = -f_(x); - *g = (*J).transpose() * *error; - if (g->array().abs().maxCoeff() < params.gradient_threshold) { - return GRADIENT_TOO_SMALL; - } else if (error->norm() < params.error_threshold) { - return ERROR_TOO_SMALL; - } - return RUNNING; - } - - Results minimize(Parameters *x_and_min) { - SolverParameters params; - minimize(params, x_and_min); - } - - Results minimize(const SolverParameters ¶ms, Parameters *x_and_min) { - Parameters &x = *x_and_min; - JMatrixType J; - AMatrixType A; - FVec error; - Parameters g; - - Results results; - results.status = Update(x, params, &J, &A, &error, &g); - - Scalar u = Scalar(params.initial_scale_factor*A.diagonal().maxCoeff()); - Scalar v = 2; - - Parameters dx, x_new; - int i; - for (i = 0; results.status == RUNNING && i < params.max_iterations; ++i) { - VLOG(3) << "iteration: " << i; - VLOG(3) << "||f(x)||: " << f_(x).norm(); - VLOG(3) << "max(g): " << g.array().abs().maxCoeff(); - VLOG(3) << "u: " << u; - VLOG(3) << "v: " << v; - - AMatrixType A_augmented = A + u*AMatrixType::Identity(J.cols(), J.cols()); - Solver solver(A_augmented); - dx = solver.solve(g); - bool solved = (A_augmented * dx).isApprox(g); - if (!solved) { - LOG(ERROR) << "Failed to solve"; - } - if (solved && dx.norm() <= params.relative_step_threshold * x.norm()) { - results.status = RELATIVE_STEP_SIZE_TOO_SMALL; - break; - } - if (solved) { - x_new = x + dx; - // Rho is the ratio of the actual reduction in error to the reduction - // in error that would be obtained if the problem was linear. - // See [1] for details. - Scalar rho((error.squaredNorm() - f_(x_new).squaredNorm()) - / dx.dot(u*dx + g)); - if (rho > 0) { - // Accept the Gauss-Newton step because the linear model fits well. - x = x_new; - results.status = Update(x, params, &J, &A, &error, &g); - Scalar tmp = Scalar(2*rho-1); - u = u*std::max(1/3., 1 - (tmp*tmp*tmp)); - v = 2; - continue; - } - } - // Reject the update because either the normal equations failed to solve - // or the local linear model was not good (rho < 0). Instead, increase u - // to move closer to gradient descent. - u *= v; - v *= 2; - } - if (results.status == RUNNING) { - results.status = HIT_MAX_ITERATIONS; - } - results.error_magnitude = error.norm(); - results.gradient_magnitude = g.norm(); - results.iterations = i; - return results; - } - - private: - const Function &f_; - Jacobian df_; -}; - -} // namespace mv - -#endif // LIBMV_NUMERIC_LEVENBERG_MARQUARDT_H diff --git a/extern/libmv/libmv/numeric/levenberg_marquardt_test.cc b/extern/libmv/libmv/numeric/levenberg_marquardt_test.cc deleted file mode 100644 index fc3f9ebbb29..00000000000 --- a/extern/libmv/libmv/numeric/levenberg_marquardt_test.cc +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2007, 2008, 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "testing/testing.h" -#include "libmv/numeric/levenberg_marquardt.h" - -using namespace libmv; - -namespace { - -class F { - public: - typedef Vec4 FMatrixType; - typedef Vec3 XMatrixType; - Vec4 operator()(const Vec3 &x) const { - double x1 = x.x() - 2; - double y1 = x.y() - 5; - double z1 = x.z(); - Vec4 fx; fx << x1*x1 + z1*z1, - y1*y1 + z1*z1, - z1*z1, - x1*x1; - return fx; - } -}; - -TEST(LevenbergMarquardt, SimpleCase) { - Vec3 x(0.76026643, -30.01799744, 0.55192142); - F f; - LevenbergMarquardt::SolverParameters params; - LevenbergMarquardt lm(f); - /* TODO(sergey): Better error handling. */ - /* LevenbergMarquardt::Results results = */ lm.minimize(params, &x); - Vec3 expected_min_x(2, 5, 0); - - EXPECT_MATRIX_NEAR(expected_min_x, x, 1e-5); -} - -} // namespace diff --git a/extern/libmv/libmv/numeric/numeric.cc b/extern/libmv/libmv/numeric/numeric.cc deleted file mode 100644 index 9007663c8e2..00000000000 --- a/extern/libmv/libmv/numeric/numeric.cc +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - - -#include "libmv/numeric/numeric.h" - -namespace libmv { - -Mat3 RotationAroundX(double angle) { - double c, s; - sincos(angle, &s, &c); - Mat3 R; - R << 1, 0, 0, - 0, c, -s, - 0, s, c; - return R; -} - -Mat3 RotationAroundY(double angle) { - double c, s; - sincos(angle, &s, &c); - Mat3 R; - R << c, 0, s, - 0, 1, 0, - -s, 0, c; - return R; -} - -Mat3 RotationAroundZ(double angle) { - double c, s; - sincos(angle, &s, &c); - Mat3 R; - R << c, -s, 0, - s, c, 0, - 0, 0, 1; - return R; -} - - -Mat3 RotationRodrigues(const Vec3 &axis) { - double theta = axis.norm(); - Vec3 w = axis / theta; - Mat3 W = CrossProductMatrix(w); - - return Mat3::Identity() + sin(theta) * W + (1 - cos(theta)) * W * W; -} - - -Mat3 LookAt(Vec3 center) { - Vec3 zc = center.normalized(); - Vec3 xc = Vec3::UnitY().cross(zc).normalized(); - Vec3 yc = zc.cross(xc); - Mat3 R; - R.row(0) = xc; - R.row(1) = yc; - R.row(2) = zc; - return R; -} - -Mat3 CrossProductMatrix(const Vec3 &x) { - Mat3 X; - X << 0, -x(2), x(1), - x(2), 0, -x(0), - -x(1), x(0), 0; - return X; -} - -void MeanAndVarianceAlongRows(const Mat &A, - Vec *mean_pointer, - Vec *variance_pointer) { - Vec &mean = *mean_pointer; - Vec &variance = *variance_pointer; - int n = A.rows(); - int m = A.cols(); - mean.resize(n); - variance.resize(n); - - for (int i = 0; i < n; ++i) { - mean(i) = 0; - variance(i) = 0; - for (int j = 0; j < m; ++j) { - double x = A(i, j); - mean(i) += x; - variance(i) += x * x; - } - } - - mean /= m; - for (int i = 0; i < n; ++i) { - variance(i) = variance(i) / m - Square(mean(i)); - } -} - -void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked) { - assert(left.rows() == left.rows()); - int n = left.rows(); - int m1 = left.cols(); - int m2 = right.cols(); - - stacked->resize(n, m1 + m2); - stacked->block(0, 0, n, m1) = left; - stacked->block(0, m1, n, m2) = right; -} - -void MatrixColumn(const Mat &A, int i, Vec2 *v) { - assert(A.rows() == 2); - *v << A(0, i), A(1, i); -} -void MatrixColumn(const Mat &A, int i, Vec3 *v) { - assert(A.rows() == 3); - *v << A(0, i), A(1, i), A(2, i); -} -void MatrixColumn(const Mat &A, int i, Vec4 *v) { - assert(A.rows() == 4); - *v << A(0, i), A(1, i), A(2, i), A(3, i); -} - -} // namespace libmv - diff --git a/extern/libmv/libmv/numeric/numeric.h b/extern/libmv/libmv/numeric/numeric.h deleted file mode 100644 index 55d4c7d4651..00000000000 --- a/extern/libmv/libmv/numeric/numeric.h +++ /dev/null @@ -1,502 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Matrix and vector classes, based on Eigen2. -// -// Avoid using Eigen2 classes directly; instead typedef them here. - -#ifndef LIBMV_NUMERIC_NUMERIC_H -#define LIBMV_NUMERIC_NUMERIC_H - -#include -#include -#include -#include -#include -#include -#include - -#if !defined(__MINGW64__) -# if defined(_WIN32) || defined(__APPLE__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) -static void sincos(double x, double *sinx, double *cosx) { - *sinx = sin(x); - *cosx = cos(x); -} -# endif -#endif // !__MINGW64__ - -#if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__) -inline long lround(double d) { - return (long)(d>0 ? d+0.5 : ceil(d-0.5)); -} -# if _MSC_VER < 1800 -inline int round(double d) { - return (d>0) ? int(d+0.5) : int(d-0.5); -} -# endif // _MSC_VER < 1800 -typedef unsigned int uint; -#endif // _WIN32 - -namespace libmv { - -typedef Eigen::MatrixXd Mat; -typedef Eigen::VectorXd Vec; - -typedef Eigen::MatrixXf Matf; -typedef Eigen::VectorXf Vecf; - -typedef Eigen::Matrix Matu; -typedef Eigen::Matrix Vecu; -typedef Eigen::Matrix Vec2u; - -typedef Eigen::Matrix Mat2; -typedef Eigen::Matrix Mat23; -typedef Eigen::Matrix Mat3; -typedef Eigen::Matrix Mat34; -typedef Eigen::Matrix Mat35; -typedef Eigen::Matrix Mat41; -typedef Eigen::Matrix Mat43; -typedef Eigen::Matrix Mat4; -typedef Eigen::Matrix Mat46; -typedef Eigen::Matrix Mat2f; -typedef Eigen::Matrix Mat23f; -typedef Eigen::Matrix Mat3f; -typedef Eigen::Matrix Mat34f; -typedef Eigen::Matrix Mat35f; -typedef Eigen::Matrix Mat43f; -typedef Eigen::Matrix Mat4f; -typedef Eigen::Matrix Mat46f; - -typedef Eigen::Matrix RMat3; -typedef Eigen::Matrix RMat4; - -typedef Eigen::Matrix Mat2X; -typedef Eigen::Matrix Mat3X; -typedef Eigen::Matrix Mat4X; -typedef Eigen::Matrix MatX2; -typedef Eigen::Matrix MatX3; -typedef Eigen::Matrix MatX4; -typedef Eigen::Matrix MatX5; -typedef Eigen::Matrix MatX6; -typedef Eigen::Matrix MatX7; -typedef Eigen::Matrix MatX8; -typedef Eigen::Matrix MatX9; -typedef Eigen::Matrix MatX15; -typedef Eigen::Matrix MatX16; - -typedef Eigen::Vector2d Vec2; -typedef Eigen::Vector3d Vec3; -typedef Eigen::Vector4d Vec4; -typedef Eigen::Matrix Vec5; -typedef Eigen::Matrix Vec6; -typedef Eigen::Matrix Vec7; -typedef Eigen::Matrix Vec8; -typedef Eigen::Matrix Vec9; -typedef Eigen::Matrix Vec10; -typedef Eigen::Matrix Vec11; -typedef Eigen::Matrix Vec12; -typedef Eigen::Matrix Vec13; -typedef Eigen::Matrix Vec14; -typedef Eigen::Matrix Vec15; -typedef Eigen::Matrix Vec16; -typedef Eigen::Matrix Vec17; -typedef Eigen::Matrix Vec18; -typedef Eigen::Matrix Vec19; -typedef Eigen::Matrix Vec20; - -typedef Eigen::Vector2f Vec2f; -typedef Eigen::Vector3f Vec3f; -typedef Eigen::Vector4f Vec4f; - -typedef Eigen::VectorXi VecXi; - -typedef Eigen::Vector2i Vec2i; -typedef Eigen::Vector3i Vec3i; -typedef Eigen::Vector4i Vec4i; - -typedef Eigen::Matrix RMatf; - -typedef Eigen::NumTraits EigenDouble; - -using Eigen::Map; -using Eigen::Dynamic; -using Eigen::Matrix; - -// Find U, s, and VT such that -// -// A = U * diag(s) * VT -// -template -inline void SVD(TMat *A, Vec *s, Mat *U, Mat *VT) { - assert(0); -} - -// Solve the linear system Ax = 0 via SVD. Store the solution in x, such that -// ||x|| = 1.0. Return the singluar value corresponding to the solution. -// Destroys A and resizes x if necessary. -// TODO(maclean): Take the SVD of the transpose instead of this zero padding. -template -double Nullspace(TMat *A, TVec *nullspace) { - Eigen::JacobiSVD svd(*A, Eigen::ComputeFullV); - (*nullspace) = svd.matrixV().col(A->cols()-1); - if (A->rows() >= A->cols()) - return svd.singularValues()(A->cols()-1); - else - return 0.0; -} - -// Solve the linear system Ax = 0 via SVD. Finds two solutions, x1 and x2, such -// that x1 is the best solution and x2 is the next best solution (in the L2 -// norm sense). Store the solution in x1 and x2, such that ||x|| = 1.0. Return -// the singluar value corresponding to the solution x1. Destroys A and resizes -// x if necessary. -template -double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2) { - Eigen::JacobiSVD svd(*A, Eigen::ComputeFullV); - *x1 = svd.matrixV().col(A->cols() - 1); - *x2 = svd.matrixV().col(A->cols() - 2); - if (A->rows() >= A->cols()) - return svd.singularValues()(A->cols()-1); - else - return 0.0; -} - -// In place transpose for square matrices. -template -inline void TransposeInPlace(TA *A) { - *A = A->transpose().eval(); -} - -template -inline double NormL1(const TVec &x) { - return x.array().abs().sum(); -} - -template -inline double NormL2(const TVec &x) { - return x.norm(); -} - -template -inline double NormLInfinity(const TVec &x) { - return x.array().abs().maxCoeff(); -} - -template -inline double DistanceL1(const TVec &x, const TVec &y) { - return (x - y).array().abs().sum(); -} - -template -inline double DistanceL2(const TVec &x, const TVec &y) { - return (x - y).norm(); -} -template -inline double DistanceLInfinity(const TVec &x, const TVec &y) { - return (x - y).array().abs().maxCoeff(); -} - -// Normalize a vector with the L1 norm, and return the norm before it was -// normalized. -template -inline double NormalizeL1(TVec *x) { - double norm = NormL1(*x); - *x /= norm; - return norm; -} - -// Normalize a vector with the L2 norm, and return the norm before it was -// normalized. -template -inline double NormalizeL2(TVec *x) { - double norm = NormL2(*x); - *x /= norm; - return norm; -} - -// Normalize a vector with the L^Infinity norm, and return the norm before it -// was normalized. -template -inline double NormalizeLInfinity(TVec *x) { - double norm = NormLInfinity(*x); - *x /= norm; - return norm; -} - -// Return the square of a number. -template -inline T Square(T x) { - return x * x; -} - -Mat3 RotationAroundX(double angle); -Mat3 RotationAroundY(double angle); -Mat3 RotationAroundZ(double angle); - -// Returns the rotation matrix of a rotation of angle |axis| around axis. -// This is computed using the Rodrigues formula, see: -// http://mathworld.wolfram.com/RodriguesRotationFormula.html -Mat3 RotationRodrigues(const Vec3 &axis); - -// Make a rotation matrix such that center becomes the direction of the -// positive z-axis, and y is oriented close to up. -Mat3 LookAt(Vec3 center); - -// Return a diagonal matrix from a vector containg the diagonal values. -template -inline Mat Diag(const TVec &x) { - return x.asDiagonal(); -} - -template -inline double FrobeniusNorm(const TMat &A) { - return sqrt(A.array().abs2().sum()); -} - -template -inline double FrobeniusDistance(const TMat &A, const TMat &B) { - return FrobeniusNorm(A - B); -} - -inline Vec3 CrossProduct(const Vec3 &x, const Vec3 &y) { - return x.cross(y); -} - -Mat3 CrossProductMatrix(const Vec3 &x); - -void MeanAndVarianceAlongRows(const Mat &A, - Vec *mean_pointer, - Vec *variance_pointer); - -#if _WIN32 - // TODO(bomboze): un-#if this for both platforms once tested under Windows - /* This solution was extensively discussed here - http://forum.kde.org/viewtopic.php?f=74&t=61940 */ - #define SUM_OR_DYNAMIC(x, y) (x == Eigen::Dynamic || y == Eigen::Dynamic) ? Eigen::Dynamic : (x+y) - - template - struct hstack_return { - typedef typename Derived1::Scalar Scalar; - enum { - RowsAtCompileTime = Derived1::RowsAtCompileTime, - ColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::ColsAtCompileTime, - Derived2::ColsAtCompileTime), - Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0, - MaxRowsAtCompileTime = Derived1::MaxRowsAtCompileTime, - MaxColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxColsAtCompileTime, - Derived2::MaxColsAtCompileTime) - }; - typedef Eigen::Matrix type; - }; - - template - typename hstack_return::type - HStack(const Eigen::MatrixBase& lhs, - const Eigen::MatrixBase& rhs) { - typename hstack_return::type res; - res.resize(lhs.rows(), lhs.cols()+rhs.cols()); - res << lhs, rhs; - return res; - }; - - - template - struct vstack_return { - typedef typename Derived1::Scalar Scalar; - enum { - RowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::RowsAtCompileTime, - Derived2::RowsAtCompileTime), - ColsAtCompileTime = Derived1::ColsAtCompileTime, - Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0, - MaxRowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxRowsAtCompileTime, - Derived2::MaxRowsAtCompileTime), - MaxColsAtCompileTime = Derived1::MaxColsAtCompileTime - }; - typedef Eigen::Matrix type; - }; - - template - typename vstack_return::type - VStack(const Eigen::MatrixBase& lhs, - const Eigen::MatrixBase& rhs) { - typename vstack_return::type res; - res.resize(lhs.rows()+rhs.rows(), lhs.cols()); - res << lhs, rhs; - return res; - }; - - -#else // _WIN32 - - // Since it is not possible to typedef privately here, use a macro. - // Always take dynamic columns if either side is dynamic. - #define COLS \ - ((ColsLeft == Eigen::Dynamic || ColsRight == Eigen::Dynamic) \ - ? Eigen::Dynamic : (ColsLeft + ColsRight)) - - // Same as above, except that prefer fixed size if either is fixed. - #define ROWS \ - ((RowsLeft == Eigen::Dynamic && RowsRight == Eigen::Dynamic) \ - ? Eigen::Dynamic \ - : ((RowsLeft == Eigen::Dynamic) \ - ? RowsRight \ - : RowsLeft \ - ) \ - ) - - // TODO(keir): Add a static assert if both rows are at compiletime. - template - Eigen::Matrix - HStack(const Eigen::Matrix &left, - const Eigen::Matrix &right) { - assert(left.rows() == right.rows()); - int n = left.rows(); - int m1 = left.cols(); - int m2 = right.cols(); - - Eigen::Matrix stacked(n, m1 + m2); - stacked.block(0, 0, n, m1) = left; - stacked.block(0, m1, n, m2) = right; - return stacked; - } - - // Reuse the above macros by swapping the order of Rows and Cols. Nasty, but - // the duplication is worse. - // TODO(keir): Add a static assert if both rows are at compiletime. - // TODO(keir): Mail eigen list about making this work for general expressions - // rather than only matrix types. - template - Eigen::Matrix - VStack(const Eigen::Matrix &top, - const Eigen::Matrix &bottom) { - assert(top.cols() == bottom.cols()); - int n1 = top.rows(); - int n2 = bottom.rows(); - int m = top.cols(); - - Eigen::Matrix stacked(n1 + n2, m); - stacked.block(0, 0, n1, m) = top; - stacked.block(n1, 0, n2, m) = bottom; - return stacked; - } - #undef COLS - #undef ROWS -#endif // _WIN32 - - - -void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked); - -template -void VerticalStack(const TTop &top, const TBot &bottom, TStacked *stacked) { - assert(top.cols() == bottom.cols()); - int n1 = top.rows(); - int n2 = bottom.rows(); - int m = top.cols(); - - stacked->resize(n1 + n2, m); - stacked->block(0, 0, n1, m) = top; - stacked->block(n1, 0, n2, m) = bottom; -} - -void MatrixColumn(const Mat &A, int i, Vec2 *v); -void MatrixColumn(const Mat &A, int i, Vec3 *v); -void MatrixColumn(const Mat &A, int i, Vec4 *v); - -template -TMat ExtractColumns(const TMat &A, const TCols &columns) { - TMat compressed(A.rows(), columns.size()); - for (int i = 0; i < columns.size(); ++i) { - compressed.col(i) = A.col(columns[i]); - } - return compressed; -} - -template -void reshape(const TMat &a, int rows, int cols, TDest *b) { - assert(a.rows()*a.cols() == rows*cols); - b->resize(rows, cols); - for (int i = 0; i < rows; i++) { - for (int j = 0; j < cols; j++) { - (*b)(i, j) = a[cols*i + j]; - } - } -} - -inline bool isnan(double i) { -#ifdef WIN32 - return _isnan(i) > 0; -#else - return std::isnan(i); -#endif -} - -/// Ceil function that has the same behaviour for positive -/// and negative values -template -FloatType ceil0(const FloatType& value) { - FloatType result = std::ceil(std::fabs(value)); - return (value < 0.0) ? -result : result; -} - -/// Returns the skew anti-symmetric matrix of a vector -inline Mat3 SkewMat(const Vec3 &x) { - Mat3 skew; - skew << 0 , -x(2), x(1), - x(2), 0 , -x(0), - -x(1), x(0), 0; - return skew; -} -/// Returns the skew anti-symmetric matrix of a vector with only -/// the first two (independent) lines -inline Mat23 SkewMatMinimal(const Vec2 &x) { - Mat23 skew; - skew << 0, -1, x(1), - 1, 0, -x(0); - return skew; -} - -/// Returns the rotaiton matrix built from given vector of euler angles -inline Mat3 RotationFromEulerVector(Vec3 euler_vector) { - double theta = euler_vector.norm(); - if (theta == 0.0) { - return Mat3::Identity(); - } - Vec3 w = euler_vector / theta; - Mat3 w_hat = CrossProductMatrix(w); - return Mat3::Identity() + w_hat*sin(theta) + w_hat*w_hat*(1 - cos(theta)); -} -} // namespace libmv - -#endif // LIBMV_NUMERIC_NUMERIC_H diff --git a/extern/libmv/libmv/numeric/numeric_test.cc b/extern/libmv/libmv/numeric/numeric_test.cc deleted file mode 100644 index 0cdfaf33ab2..00000000000 --- a/extern/libmv/libmv/numeric/numeric_test.cc +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/numeric/numeric.h" -#include "testing/testing.h" - -using namespace libmv; - -namespace { - -TEST(Numeric, DynamicSizedNullspace) { - Mat A(3, 4); - A << 0.76026643, 0.01799744, 0.55192142, 0.8699745, - 0.42016166, 0.97863392, 0.33711682, 0.14479271, - 0.51016811, 0.66528302, 0.54395496, 0.57794893; - Vec x; - double s = Nullspace(&A, &x); - EXPECT_NEAR(0.0, s, 1e-15); - EXPECT_NEAR(0.0, (A * x).norm(), 1e-15); - EXPECT_NEAR(1.0, x.norm(), 1e-15); -} - -TEST(Numeric, FixedSizeMatrixNullspace) { - Mat34 A; - A << 0.76026643, 0.01799744, 0.55192142, 0.8699745, - 0.42016166, 0.97863392, 0.33711682, 0.14479271, - 0.51016811, 0.66528302, 0.54395496, 0.57794893; - Vec x; - double s = Nullspace(&A, &x); - EXPECT_NEAR(0.0, s, 1e-15); - EXPECT_NEAR(0.0, (A * x).norm(), 1e-15); - EXPECT_NEAR(1.0, x.norm(), 1e-15); -} - -TEST(Numeric, NullspaceMatchesLapackSVD) { - Mat43 A; - A << 0.76026643, 0.01799744, 0.55192142, - 0.8699745, 0.42016166, 0.97863392, - 0.33711682, 0.14479271, 0.51016811, - 0.66528302, 0.54395496, 0.57794893; - Vec x; - double s = Nullspace(&A, &x); - EXPECT_NEAR(1.0, x.norm(), 1e-15); - EXPECT_NEAR(0.206694992663, s, 1e-9); - EXPECT_NEAR(0.206694992663, (A * x).norm(), 1e-9); - - EXPECT_NEAR(-0.64999717, x(0), 1e-8); - EXPECT_NEAR(-0.18452646, x(1), 1e-8); - EXPECT_NEAR(0.7371931, x(2), 1e-8); -} - -TEST(Numeric, Nullspace2) { - Mat43 A; - A << 0.76026643, 0.01799744, 0.55192142, - 0.8699745, 0.42016166, 0.97863392, - 0.33711682, 0.14479271, 0.51016811, - 0.66528302, 0.54395496, 0.57794893; - Vec3 x1, x2; - double s = Nullspace2(&A, &x1, &x2); - EXPECT_NEAR(1.0, x1.norm(), 1e-15); - EXPECT_NEAR(0.206694992663, s, 1e-9); - EXPECT_NEAR(0.206694992663, (A * x1).norm(), 1e-9); - - EXPECT_NEAR(-0.64999717, x1(0), 1e-8); - EXPECT_NEAR(-0.18452646, x1(1), 1e-8); - EXPECT_NEAR( 0.7371931, x1(2), 1e-8); - - if (x2(0) < 0) { - x2 *= -1; - } - EXPECT_NEAR( 0.34679618, x2(0), 1e-8); - EXPECT_NEAR(-0.93519689, x2(1), 1e-8); - EXPECT_NEAR( 0.07168809, x2(2), 1e-8); -} - -TEST(Numeric, TinyMatrixSquareTranspose) { - Mat2 A; - A << 1.0, 2.0, 3.0, 4.0; - libmv::TransposeInPlace(&A); - EXPECT_EQ(1.0, A(0, 0)); - EXPECT_EQ(3.0, A(0, 1)); - EXPECT_EQ(2.0, A(1, 0)); - EXPECT_EQ(4.0, A(1, 1)); -} - -TEST(Numeric, NormalizeL1) { - Vec2 x; - x << 1, 2; - double l1 = NormalizeL1(&x); - EXPECT_DOUBLE_EQ(3., l1); - EXPECT_DOUBLE_EQ(1./3., x(0)); - EXPECT_DOUBLE_EQ(2./3., x(1)); -} - -TEST(Numeric, NormalizeL2) { - Vec2 x; - x << 1, 2; - double l2 = NormalizeL2(&x); - EXPECT_DOUBLE_EQ(sqrt(5.0), l2); - EXPECT_DOUBLE_EQ(1./sqrt(5.), x(0)); - EXPECT_DOUBLE_EQ(2./sqrt(5.), x(1)); -} - -TEST(Numeric, Diag) { - Vec x(2); - x << 1, 2; - Mat D = Diag(x); - EXPECT_EQ(1, D(0, 0)); - EXPECT_EQ(0, D(0, 1)); - EXPECT_EQ(0, D(1, 0)); - EXPECT_EQ(2, D(1, 1)); -} - -TEST(Numeric, Determinant) { - Mat A(2, 2); - A << 1, 2, - -1, 3; - double detA = A.determinant(); - EXPECT_NEAR(5, detA, 1e-8); - - Mat B(4, 4); - B << 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15; - double detB = B.determinant(); - EXPECT_NEAR(0, detB, 1e-8); - - Mat3 C; - C << 0, 1, 2, - 3, 4, 5, - 6, 7, 1; - double detC = C.determinant(); - EXPECT_NEAR(21, detC, 1e-8); -} - -TEST(Numeric, Inverse) { - Mat A(2, 2), A1; - A << 1, 2, - -1, 3; - Mat I = A * A.inverse(); - - EXPECT_NEAR(1, I(0, 0), 1e-8); - EXPECT_NEAR(0, I(0, 1), 1e-8); - EXPECT_NEAR(0, I(1, 0), 1e-8); - EXPECT_NEAR(1, I(1, 1), 1e-8); - - Mat B(4, 4), B1; - B << 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 2, 11, - 12, 13, 14, 4; - Mat I2 = B * B.inverse(); - EXPECT_NEAR(1, I2(0, 0), 1e-8); - EXPECT_NEAR(0, I2(0, 1), 1e-8); - EXPECT_NEAR(0, I2(0, 2), 1e-8); - EXPECT_NEAR(0, I2(1, 0), 1e-8); - EXPECT_NEAR(1, I2(1, 1), 1e-8); - EXPECT_NEAR(0, I2(1, 2), 1e-8); - EXPECT_NEAR(0, I2(2, 0), 1e-8); - EXPECT_NEAR(0, I2(2, 1), 1e-8); - EXPECT_NEAR(1, I2(2, 2), 1e-8); -} - -TEST(Numeric, MeanAndVarianceAlongRows) { - int n = 4; - Mat points(2, n); - points << 0, 0, 1, 1, - 0, 2, 1, 3; - - Vec mean, variance; - MeanAndVarianceAlongRows(points, &mean, &variance); - - EXPECT_NEAR(0.5, mean(0), 1e-8); - EXPECT_NEAR(1.5, mean(1), 1e-8); - EXPECT_NEAR(0.25, variance(0), 1e-8); - EXPECT_NEAR(1.25, variance(1), 1e-8); -} - -TEST(Numeric, HorizontalStack) { - Mat x(2, 1), y(2, 1), z; - x << 1, 2; - y << 3, 4; - - HorizontalStack(x, y, &z); - - EXPECT_EQ(2, z.cols()); - EXPECT_EQ(2, z.rows()); - EXPECT_EQ(1, z(0, 0)); - EXPECT_EQ(2, z(1, 0)); - EXPECT_EQ(3, z(0, 1)); - EXPECT_EQ(4, z(1, 1)); -} - -TEST(Numeric, HStack) { - Mat x(2, 1), y(2, 1), z(2, 2); - x << 1, 2; - y << 3, 4; - z << 1, 3, - 2, 4; - Vec2 xC = x, yC = y; - - Mat2 xy = HStack(x, y); - EXPECT_MATRIX_EQ(z, xy); - - EXPECT_MATRIX_EQ(z, HStack(x, y)); - EXPECT_MATRIX_EQ(z, HStack(x, yC)); - EXPECT_MATRIX_EQ(z, HStack(xC, y)); - EXPECT_MATRIX_EQ(z, HStack(xC, yC)); -} - -// TODO(keir): Need some way of verifying that the compile time types of the -// resulting stacked matrices properly propagate the fixed dimensions. -TEST(Numeric, VStack) { - Mat x(2, 2), y(2, 2), z(4, 2); - x << 1, 2, - 3, 4; - y << 10, 20, - 30, 40; - z << 1, 2, - 3, 4, - 10, 20, - 30, 40; - Mat2 xC = x, yC = y; - - Mat xy = VStack(x, y); - EXPECT_MATRIX_EQ(z, xy); - - EXPECT_MATRIX_EQ(z, VStack(x, y)); - EXPECT_MATRIX_EQ(z, VStack(x, yC)); - EXPECT_MATRIX_EQ(z, VStack(xC, y)); - EXPECT_MATRIX_EQ(z, VStack(xC, yC)); -} - -TEST(Numeric, VerticalStack) { - Mat x(1, 2), y(1, 2), z; - x << 1, 2; - y << 3, 4; - VerticalStack(x, y, &z); - - EXPECT_EQ(2, z.cols()); - EXPECT_EQ(2, z.rows()); - EXPECT_EQ(1, z(0, 0)); - EXPECT_EQ(2, z(0, 1)); - EXPECT_EQ(3, z(1, 0)); - EXPECT_EQ(4, z(1, 1)); -} - -TEST(Numeric, CrossProduct) { - Vec3 x, y, z; - x << 1, 0, 0; - y << 0, 1, 0; - z << 0, 0, 1; - Vec3 xy = CrossProduct(x, y); - Vec3 yz = CrossProduct(y, z); - Vec3 zx = CrossProduct(z, x); - EXPECT_NEAR(0, DistanceLInfinity(xy, z), 1e-8); - EXPECT_NEAR(0, DistanceLInfinity(yz, x), 1e-8); - EXPECT_NEAR(0, DistanceLInfinity(zx, y), 1e-8); -} - -TEST(Numeric, CrossProductMatrix) { - Vec3 x, y; - x << 1, 2, 3; - y << 2, 3, 4; - Vec3 xy = CrossProduct(x, y); - Vec3 yx = CrossProduct(y, x); - Mat3 X = CrossProductMatrix(x); - Vec3 Xy, Xty; - Xy = X * y; - Xty = X.transpose() * y; - EXPECT_NEAR(0, DistanceLInfinity(xy, Xy), 1e-8); - EXPECT_NEAR(0, DistanceLInfinity(yx, Xty), 1e-8); -} - -TEST(Numeric, MatrixColumn) { - Mat A2(2, 3); - Vec2 v2; - A2 << 1, 2, 3, - 4, 5, 6; - MatrixColumn(A2, 1, &v2); - EXPECT_EQ(2, v2(0)); - EXPECT_EQ(5, v2(1)); - - Mat A3(3, 3); - Vec3 v3; - A3 << 1, 2, 3, - 4, 5, 6, - 7, 8, 9; - MatrixColumn(A3, 1, &v3); - EXPECT_EQ(2, v3(0)); - EXPECT_EQ(5, v3(1)); - EXPECT_EQ(8, v3(2)); - - Mat A4(4, 3); - Vec4 v4; - A4 << 1, 2, 3, - 4, 5, 6, - 7, 8, 9, - 10, 11, 12; - MatrixColumn(A4, 1, &v4); - EXPECT_EQ( 2, v4(0)); - EXPECT_EQ( 5, v4(1)); - EXPECT_EQ( 8, v4(2)); - EXPECT_EQ(11, v4(3)); -} - -// This used to give a compile error with FLENS. -TEST(Numeric, TinyMatrixView) { - Mat34 P; - Mat K = P.block(0, 0, 3, 3); -} - -// This gives a compile error. -TEST(Numeric, Mat3MatProduct) { - Mat3 A; - Mat3 B; - Mat C = A * B; -} - -// This gives a compile error. -TEST(Numeric, Vec3Negative) { - Vec3 y; y << 1, 2, 3; - Vec3 x = -y; - EXPECT_EQ(-1, x(0)); - EXPECT_EQ(-2, x(1)); - EXPECT_EQ(-3, x(2)); -} - -// This gives a compile error. -TEST(Numeric, Vec3VecInteroperability) { - Vec y(3); - y << 1, 2, 3; - Vec3 x = y + y; - EXPECT_EQ(2, x(0)); - EXPECT_EQ(4, x(1)); - EXPECT_EQ(6, x(2)); -} - -// This segfaults inside lapack. -TEST(Numeric, DeterminantLU7) { - Mat A(5, 5); - A << 1, 0, 0, 0, 0, - 0, 1, 0, 0, 0, - 0, 0, 1, 0, 0, - 0, 0, 0, 1, 0, - 0, 0, 0, 0, 1; - EXPECT_NEAR(1, A.determinant(), 1e-8); -} - -// This segfaults inside lapack. -TEST(Numeric, DeterminantLU) { - Mat A(2, 2); - A << 1, 2, - -1, 3; - EXPECT_NEAR(5, A.determinant(), 1e-8); -} - -// This does unexpected things. -// Keir: Not with eigen2! -TEST(Numeric, InplaceProduct) { - Mat2 K, S; - K << 1, 0, - 0, 1; - S << 1, 0, - 0, 1; - K = K * S; - EXPECT_MATRIX_NEAR(Mat2::Identity(), K, 1e-8); -} - -TEST(Numeric, ExtractColumns) { - Mat2X A(2, 5); - A << 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10; - Vec2i columns; columns << 0, 2; - Mat2X extracted = ExtractColumns(A, columns); - EXPECT_NEAR(1, extracted(0, 0), 1e-15); - EXPECT_NEAR(3, extracted(0, 1), 1e-15); - EXPECT_NEAR(6, extracted(1, 0), 1e-15); - EXPECT_NEAR(8, extracted(1, 1), 1e-15); -} - -TEST(Numeric, RotationRodrigues) { - Vec3 x, y, z; - x << 1, 0, 0; - y << 0, 1, 0; - z << 0, 0, 1; - - Mat3 rodrigues_x = RotationRodrigues(x); - Mat3 rodrigues_y = RotationRodrigues(y); - Mat3 rodrigues_z = RotationRodrigues(z); - - Mat3 Rx = RotationAroundX(1); - Mat3 Ry = RotationAroundY(1); - Mat3 Rz = RotationAroundZ(1); - - EXPECT_MATRIX_NEAR(Rx, rodrigues_x, 1e-15); - EXPECT_MATRIX_NEAR(Ry, rodrigues_y, 1e-15); - EXPECT_MATRIX_NEAR(Rz, rodrigues_z, 1e-15); -} - -TEST(Numeric, LookAt) { - // Simple orthogonality check. - Vec3 e; e << 1, 2, 3; - Mat3 R = LookAt(e), I = Mat3::Identity(); - Mat3 RRT = R*R.transpose(); - Mat3 RTR = R.transpose()*R; - - EXPECT_MATRIX_NEAR(I, RRT, 1e-15); - EXPECT_MATRIX_NEAR(I, RTR, 1e-15); -} - -TEST(Numeric, Reshape) { - Vec4 x; x << 1, 2, 3, 4; - Mat2 M, M_expected; - reshape(x, 2, 2, &M); - M_expected << 1, 2, - 3, 4; - EXPECT_MATRIX_NEAR(M_expected, M, 1e-15); -} - -} // namespace diff --git a/extern/libmv/libmv/numeric/poly.cc b/extern/libmv/libmv/numeric/poly.cc deleted file mode 100644 index 376403616c3..00000000000 --- a/extern/libmv/libmv/numeric/poly.cc +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Routines for solving polynomials. - -// TODO(keir): Add a solver for degree > 3 polynomials. diff --git a/extern/libmv/libmv/numeric/poly.h b/extern/libmv/libmv/numeric/poly.h deleted file mode 100644 index 76ba062d475..00000000000 --- a/extern/libmv/libmv/numeric/poly.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_NUMERIC_POLY_H_ -#define LIBMV_NUMERIC_POLY_H_ - -#include -#include - -namespace libmv { - -// Solve the cubic polynomial -// -// x^3 + a*x^2 + b*x + c = 0 -// -// The number of roots (from zero to three) is returned. If the number of roots -// is less than three, then higher numbered x's are not changed. For example, -// if there are 2 roots, only x0 and x1 are set. -// -// The GSL cubic solver was used as a reference for this routine. -template -int SolveCubicPolynomial(Real a, Real b, Real c, - Real *x0, Real *x1, Real *x2) { - Real q = a * a - 3 * b; - Real r = 2 * a * a * a - 9 * a * b + 27 * c; - - Real Q = q / 9; - Real R = r / 54; - - Real Q3 = Q * Q * Q; - Real R2 = R * R; - - Real CR2 = 729 * r * r; - Real CQ3 = 2916 * q * q * q; - - if (R == 0 && Q == 0) { - // Tripple root in one place. - *x0 = *x1 = *x2 = -a / 3; - return 3; - - } else if (CR2 == CQ3) { - // This test is actually R2 == Q3, written in a form suitable for exact - // computation with integers. - // - // Due to finite precision some double roots may be missed, and considered - // to be a pair of complex roots z = x +/- epsilon i close to the real - // axis. - Real sqrtQ = sqrt(Q); - if (R > 0) { - *x0 = -2 * sqrtQ - a / 3; - *x1 = sqrtQ - a / 3; - *x2 = sqrtQ - a / 3; - } else { - *x0 = -sqrtQ - a / 3; - *x1 = -sqrtQ - a / 3; - *x2 = 2 * sqrtQ - a / 3; - } - return 3; - - } else if (CR2 < CQ3) { - // This case is equivalent to R2 < Q3. - Real sqrtQ = sqrt(Q); - Real sqrtQ3 = sqrtQ * sqrtQ * sqrtQ; - Real theta = acos(R / sqrtQ3); - Real norm = -2 * sqrtQ; - *x0 = norm * cos(theta / 3) - a / 3; - *x1 = norm * cos((theta + 2.0 * M_PI) / 3) - a / 3; - *x2 = norm * cos((theta - 2.0 * M_PI) / 3) - a / 3; - - // Put the roots in ascending order. - if (*x0 > *x1) { - std::swap(*x0, *x1); - } - if (*x1 > *x2) { - std::swap(*x1, *x2); - if (*x0 > *x1) { - std::swap(*x0, *x1); - } - } - return 3; - } - Real sgnR = (R >= 0 ? 1 : -1); - Real A = -sgnR * pow(fabs(R) + sqrt(R2 - Q3), 1.0/3.0); - Real B = Q / A; - *x0 = A + B - a / 3; - return 1; -} - -// The coefficients are in ascending powers, i.e. coeffs[N]*x^N. -template -int SolveCubicPolynomial(const Real *coeffs, Real *solutions) { - if (coeffs[0] == 0.0) { - // TODO(keir): This is a quadratic not a cubic. Implement a quadratic - // solver! - return 0; - } - Real a = coeffs[2] / coeffs[3]; - Real b = coeffs[1] / coeffs[3]; - Real c = coeffs[0] / coeffs[3]; - return SolveCubicPolynomial(a, b, c, - solutions + 0, - solutions + 1, - solutions + 2); -} -} // namespace libmv -#endif // LIBMV_NUMERIC_POLY_H_ diff --git a/extern/libmv/libmv/numeric/poly_test.cc b/extern/libmv/libmv/numeric/poly_test.cc deleted file mode 100644 index ea50383190f..00000000000 --- a/extern/libmv/libmv/numeric/poly_test.cc +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/poly.h" -#include "testing/testing.h" - -using namespace libmv; - -namespace { - -// Find the polynomial coefficients of x in the equation -// -// (x - a)(x - b)(x - c) == 0 -// -// by expanding to -// -// x^3 - (c+b+a) * x^2 + (a*b+(b+a)*c) * x - a*b*c = 0. -// = p = q = r -void CoeffsForCubicZeros(double a, double b, double c, - double *p, double *q, double *r) { - *p = -(c + b + a); - *q = (a * b + (b + a) * c); - *r = -a * b * c; -} -// Find the polynomial coefficients of x in the equation -// -// (x - a)(x - b)(x - c)(x - d) == 0 -// -// by expanding to -// -// x^4 - (d+c+b+a) * x^3 + (d*(c+b+a) + a*b+(b+a)*c) * x^2 -// - (d*(a*b+(b+a)*c)+a*b*c) * x + a*b*c*d = 0. -void CoeffsForQuarticZeros(double a, double b, double c, double d, - double *p, double *q, double *r, double *s) { - *p = -(d + c + b + a); - *q = (d * (c + b + a) + a * b + (b + a) * c); - *r = -(d * (a * b + (b + a) * c) + a * b * c); - *s = a * b * c *d; -} - -TEST(Poly, SolveCubicPolynomial) { - double a, b, c, aa, bb, cc; - double p, q, r; - - a = 1; b = 2; c = 3; - CoeffsForCubicZeros(a, b, c, &p, &q, &r); - ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); - EXPECT_NEAR(a, aa, 1e-10); - EXPECT_NEAR(b, bb, 1e-10); - EXPECT_NEAR(c, cc, 1e-10); - - a = 0; b = 1; c = 3; - CoeffsForCubicZeros(a, b, c, &p, &q, &r); - ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); - EXPECT_NEAR(a, aa, 1e-10); - EXPECT_NEAR(b, bb, 1e-10); - EXPECT_NEAR(c, cc, 1e-10); - - a = -10; b = 0; c = 1; - CoeffsForCubicZeros(a, b, c, &p, &q, &r); - ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); - EXPECT_NEAR(a, aa, 1e-10); - EXPECT_NEAR(b, bb, 1e-10); - EXPECT_NEAR(c, cc, 1e-10); - - a = -8; b = 1; c = 3; - CoeffsForCubicZeros(a, b, c, &p, &q, &r); - ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); - EXPECT_NEAR(a, aa, 1e-10); - EXPECT_NEAR(b, bb, 1e-10); - EXPECT_NEAR(c, cc, 1e-10); - - a = 28; b = 28; c = 105; - CoeffsForCubicZeros(a, b, c, &p, &q, &r); - ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); - EXPECT_NEAR(a, aa, 1e-10); - EXPECT_NEAR(b, bb, 1e-10); - EXPECT_NEAR(c, cc, 1e-10); -} -} // namespace diff --git a/extern/libmv/libmv/simple_pipeline/bundle.cc b/extern/libmv/libmv/simple_pipeline/bundle.cc deleted file mode 100644 index e61650fb371..00000000000 --- a/extern/libmv/libmv/simple_pipeline/bundle.cc +++ /dev/null @@ -1,658 +0,0 @@ -// Copyright (c) 2011, 2012, 2013 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/bundle.h" - -#include - -#include "ceres/ceres.h" -#include "ceres/rotation.h" -#include "libmv/base/vector.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/fundamental.h" -#include "libmv/multiview/projection.h" -#include "libmv/numeric/numeric.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" -#include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/distortion_models.h" - -#ifdef _OPENMP -# include -#endif - -namespace libmv { - -// The intrinsics need to get combined into a single parameter block; use these -// enums to index instead of numeric constants. -enum { - // Camera calibration values. - OFFSET_FOCAL_LENGTH, - OFFSET_PRINCIPAL_POINT_X, - OFFSET_PRINCIPAL_POINT_Y, - - // Distortion model coefficients. - OFFSET_K1, - OFFSET_K2, - OFFSET_K3, - OFFSET_P1, - OFFSET_P2, - - // Maximal possible offset. - OFFSET_MAX, -}; - -#define FIRST_DISTORTION_COEFFICIENT OFFSET_K1 -#define LAST_DISTORTION_COEFFICIENT OFFSET_P2 -#define NUM_DISTORTION_COEFFICIENTS \ - (LAST_DISTORTION_COEFFICIENT - FIRST_DISTORTION_COEFFICIENT + 1) - -namespace { - -// Cost functor which computes reprojection error of 3D point X -// on camera defined by angle-axis rotation and it's translation -// (which are in the same block due to optimization reasons). -// -// This functor uses a radial distortion model. -struct OpenCVReprojectionError { - OpenCVReprojectionError(const DistortionModelType distortion_model, - const double observed_x, - const double observed_y, - const double weight) - : distortion_model_(distortion_model), - observed_x_(observed_x), observed_y_(observed_y), - weight_(weight) {} - - template - bool operator()(const T* const intrinsics, - const T* const R_t, // Rotation denoted by angle axis - // followed with translation - const T* const X, // Point coordinates 3x1. - T* residuals) const { - // Unpack the intrinsics. - const T& focal_length = intrinsics[OFFSET_FOCAL_LENGTH]; - const T& principal_point_x = intrinsics[OFFSET_PRINCIPAL_POINT_X]; - const T& principal_point_y = intrinsics[OFFSET_PRINCIPAL_POINT_Y]; - - // Compute projective coordinates: x = RX + t. - T x[3]; - - ceres::AngleAxisRotatePoint(R_t, X, x); - x[0] += R_t[3]; - x[1] += R_t[4]; - x[2] += R_t[5]; - - // Prevent points from going behind the camera. - if (x[2] < T(0)) { - return false; - } - - // Compute normalized coordinates: x /= x[2]. - T xn = x[0] / x[2]; - T yn = x[1] / x[2]; - - T predicted_x, predicted_y; - - // Apply distortion to the normalized points to get (xd, yd). - // TODO(keir): Do early bailouts for zero distortion; these are expensive - // jet operations. - switch (distortion_model_) { - case DISTORTION_MODEL_POLYNOMIAL: - { - const T& k1 = intrinsics[OFFSET_K1]; - const T& k2 = intrinsics[OFFSET_K2]; - const T& k3 = intrinsics[OFFSET_K3]; - const T& p1 = intrinsics[OFFSET_P1]; - const T& p2 = intrinsics[OFFSET_P2]; - - ApplyPolynomialDistortionModel(focal_length, - focal_length, - principal_point_x, - principal_point_y, - k1, k2, k3, - p1, p2, - xn, yn, - &predicted_x, - &predicted_y); - break; - } - case DISTORTION_MODEL_DIVISION: - { - const T& k1 = intrinsics[OFFSET_K1]; - const T& k2 = intrinsics[OFFSET_K2]; - - ApplyDivisionDistortionModel(focal_length, - focal_length, - principal_point_x, - principal_point_y, - k1, k2, - xn, yn, - &predicted_x, - &predicted_y); - break; - } - default: - LOG(FATAL) << "Unknown distortion model"; - } - - // The error is the difference between the predicted and observed position. - residuals[0] = (predicted_x - T(observed_x_)) * weight_; - residuals[1] = (predicted_y - T(observed_y_)) * weight_; - return true; - } - - const DistortionModelType distortion_model_; - const double observed_x_; - const double observed_y_; - const double weight_; -}; - -// Print a message to the log which camera intrinsics are gonna to be optimixed. -void BundleIntrinsicsLogMessage(const int bundle_intrinsics) { - if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) { - LOG(INFO) << "Bundling only camera positions."; - } else { - std::string bundling_message = ""; - -#define APPEND_BUNDLING_INTRINSICS(name, flag) \ - if (bundle_intrinsics & flag) { \ - if (!bundling_message.empty()) { \ - bundling_message += ", "; \ - } \ - bundling_message += name; \ - } (void)0 - - APPEND_BUNDLING_INTRINSICS("f", BUNDLE_FOCAL_LENGTH); - APPEND_BUNDLING_INTRINSICS("px, py", BUNDLE_PRINCIPAL_POINT); - APPEND_BUNDLING_INTRINSICS("k1", BUNDLE_RADIAL_K1); - APPEND_BUNDLING_INTRINSICS("k2", BUNDLE_RADIAL_K2); - APPEND_BUNDLING_INTRINSICS("p1", BUNDLE_TANGENTIAL_P1); - APPEND_BUNDLING_INTRINSICS("p2", BUNDLE_TANGENTIAL_P2); - - LOG(INFO) << "Bundling " << bundling_message << "."; - } -} - -// Pack intrinsics from object to an array for easier -// and faster minimization. -void PackIntrinisicsIntoArray(const CameraIntrinsics &intrinsics, - double ceres_intrinsics[OFFSET_MAX]) { - ceres_intrinsics[OFFSET_FOCAL_LENGTH] = intrinsics.focal_length(); - ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X] = intrinsics.principal_point_x(); - ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y] = intrinsics.principal_point_y(); - - int num_distortion_parameters = intrinsics.num_distortion_parameters(); - assert(num_distortion_parameters <= NUM_DISTORTION_COEFFICIENTS); - - const double *distortion_parameters = intrinsics.distortion_parameters(); - for (int i = 0; i < num_distortion_parameters; ++i) { - ceres_intrinsics[FIRST_DISTORTION_COEFFICIENT + i] = - distortion_parameters[i]; - } -} - -// Unpack intrinsics back from an array to an object. -void UnpackIntrinsicsFromArray(const double ceres_intrinsics[OFFSET_MAX], - CameraIntrinsics *intrinsics) { - intrinsics->SetFocalLength(ceres_intrinsics[OFFSET_FOCAL_LENGTH], - ceres_intrinsics[OFFSET_FOCAL_LENGTH]); - - intrinsics->SetPrincipalPoint(ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X], - ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y]); - - int num_distortion_parameters = intrinsics->num_distortion_parameters(); - assert(num_distortion_parameters <= NUM_DISTORTION_COEFFICIENTS); - - double *distortion_parameters = intrinsics->distortion_parameters(); - for (int i = 0; i < num_distortion_parameters; ++i) { - distortion_parameters[i] = - ceres_intrinsics[FIRST_DISTORTION_COEFFICIENT + i]; - } -} - -// Get a vector of camera's rotations denoted by angle axis -// conjuncted with translations into single block -// -// Element with index i matches to a rotation+translation for -// camera at image i. -vector PackCamerasRotationAndTranslation( - const Tracks &tracks, - const EuclideanReconstruction &reconstruction) { - vector all_cameras_R_t; - int max_image = tracks.MaxImage(); - - all_cameras_R_t.resize(max_image + 1); - - for (int i = 0; i <= max_image; i++) { - const EuclideanCamera *camera = reconstruction.CameraForImage(i); - - if (!camera) { - continue; - } - - ceres::RotationMatrixToAngleAxis(&camera->R(0, 0), - &all_cameras_R_t[i](0)); - all_cameras_R_t[i].tail<3>() = camera->t; - } - return all_cameras_R_t; -} - -// Convert cameras rotations fro mangle axis back to rotation matrix. -void UnpackCamerasRotationAndTranslation( - const Tracks &tracks, - const vector &all_cameras_R_t, - EuclideanReconstruction *reconstruction) { - int max_image = tracks.MaxImage(); - - for (int i = 0; i <= max_image; i++) { - EuclideanCamera *camera = reconstruction->CameraForImage(i); - - if (!camera) { - continue; - } - - ceres::AngleAxisToRotationMatrix(&all_cameras_R_t[i](0), - &camera->R(0, 0)); - camera->t = all_cameras_R_t[i].tail<3>(); - } -} - -// Converts sparse CRSMatrix to Eigen matrix, so it could be used -// all over in the pipeline. -// -// TODO(sergey): currently uses dense Eigen matrices, best would -// be to use sparse Eigen matrices -void CRSMatrixToEigenMatrix(const ceres::CRSMatrix &crs_matrix, - Mat *eigen_matrix) { - eigen_matrix->resize(crs_matrix.num_rows, crs_matrix.num_cols); - eigen_matrix->setZero(); - - for (int row = 0; row < crs_matrix.num_rows; ++row) { - int start = crs_matrix.rows[row]; - int end = crs_matrix.rows[row + 1] - 1; - - for (int i = start; i <= end; i++) { - int col = crs_matrix.cols[i]; - double value = crs_matrix.values[i]; - - (*eigen_matrix)(row, col) = value; - } - } -} - -void EuclideanBundlerPerformEvaluation(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - vector *all_cameras_R_t, - ceres::Problem *problem, - BundleEvaluation *evaluation) { - int max_track = tracks.MaxTrack(); - // Number of camera rotations equals to number of translation, - int num_cameras = all_cameras_R_t->size(); - int num_points = 0; - - vector minimized_points; - for (int i = 0; i <= max_track; i++) { - EuclideanPoint *point = reconstruction->PointForTrack(i); - if (point) { - // We need to know whether the track is constant zero weight, - // and it so it wouldn't have parameter block in the problem. - // - // Getting all markers for track is not so bac currently since - // this code is only used by keyframe selection when there are - // not so much tracks and only 2 frames anyway. - vector markera_of_track = tracks.MarkersForTrack(i); - for (int j = 0; j < markera_of_track.size(); j++) { - if (markera_of_track.at(j).weight != 0.0) { - minimized_points.push_back(point); - num_points++; - break; - } - } - } - } - - LG << "Number of cameras " << num_cameras; - LG << "Number of points " << num_points; - - evaluation->num_cameras = num_cameras; - evaluation->num_points = num_points; - - if (evaluation->evaluate_jacobian) { // Evaluate jacobian matrix. - ceres::CRSMatrix evaluated_jacobian; - ceres::Problem::EvaluateOptions eval_options; - - // Cameras goes first in the ordering. - int max_image = tracks.MaxImage(); - for (int i = 0; i <= max_image; i++) { - const EuclideanCamera *camera = reconstruction->CameraForImage(i); - if (camera) { - double *current_camera_R_t = &(*all_cameras_R_t)[i](0); - - // All cameras are variable now. - problem->SetParameterBlockVariable(current_camera_R_t); - - eval_options.parameter_blocks.push_back(current_camera_R_t); - } - } - - // Points goes at the end of ordering, - for (int i = 0; i < minimized_points.size(); i++) { - EuclideanPoint *point = minimized_points.at(i); - eval_options.parameter_blocks.push_back(&point->X(0)); - } - - problem->Evaluate(eval_options, - NULL, NULL, NULL, - &evaluated_jacobian); - - CRSMatrixToEigenMatrix(evaluated_jacobian, &evaluation->jacobian); - } -} - -// This is an utility function to only bundle 3D position of -// given markers list. -// -// Main purpose of this function is to adjust positions of tracks -// which does have constant zero weight and so far only were using -// algebraic intersection to obtain their 3D positions. -// -// At this point we only need to bundle points positions, cameras -// are to be totally still here. -void EuclideanBundlePointsOnly(const DistortionModelType distortion_model, - const vector &markers, - vector &all_cameras_R_t, - double ceres_intrinsics[OFFSET_MAX], - EuclideanReconstruction *reconstruction) { - ceres::Problem::Options problem_options; - ceres::Problem problem(problem_options); - int num_residuals = 0; - for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; - EuclideanCamera *camera = reconstruction->CameraForImage(marker.image); - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); - if (camera == NULL || point == NULL) { - continue; - } - - // Rotation of camera denoted in angle axis followed with - // camera translaiton. - double *current_camera_R_t = &all_cameras_R_t[camera->image](0); - - problem.AddResidualBlock(new ceres::AutoDiffCostFunction< - OpenCVReprojectionError, 2, OFFSET_MAX, 6, 3>( - new OpenCVReprojectionError( - distortion_model, - marker.x, - marker.y, - 1.0)), - NULL, - ceres_intrinsics, - current_camera_R_t, - &point->X(0)); - - problem.SetParameterBlockConstant(current_camera_R_t); - num_residuals++; - } - - LG << "Number of residuals: " << num_residuals; - if (!num_residuals) { - LG << "Skipping running minimizer with zero residuals"; - return; - } - - problem.SetParameterBlockConstant(ceres_intrinsics); - - // Configure the solver. - ceres::Solver::Options options; - options.use_nonmonotonic_steps = true; - options.preconditioner_type = ceres::SCHUR_JACOBI; - options.linear_solver_type = ceres::ITERATIVE_SCHUR; - options.use_explicit_schur_complement = true; - options.use_inner_iterations = true; - options.max_num_iterations = 100; - -#ifdef _OPENMP - options.num_threads = omp_get_max_threads(); - options.num_linear_solver_threads = omp_get_max_threads(); -#endif - - // Solve! - ceres::Solver::Summary summary; - ceres::Solve(options, &problem, &summary); - - LG << "Final report:\n" << summary.FullReport(); - -} - -} // namespace - -void EuclideanBundle(const Tracks &tracks, - EuclideanReconstruction *reconstruction) { - PolynomialCameraIntrinsics empty_intrinsics; - EuclideanBundleCommonIntrinsics(tracks, - BUNDLE_NO_INTRINSICS, - BUNDLE_NO_CONSTRAINTS, - reconstruction, - &empty_intrinsics, - NULL); -} - -void EuclideanBundleCommonIntrinsics( - const Tracks &tracks, - const int bundle_intrinsics, - const int bundle_constraints, - EuclideanReconstruction *reconstruction, - CameraIntrinsics *intrinsics, - BundleEvaluation *evaluation) { - LG << "Original intrinsics: " << *intrinsics; - vector markers = tracks.AllMarkers(); - - // N-th element denotes whether track N is a constant zero-weigthed track. - vector zero_weight_tracks_flags(tracks.MaxTrack() + 1, true); - - // Residual blocks with 10 parameters are unwieldly with Ceres, so pack the - // intrinsics into a single block and rely on local parameterizations to - // control which intrinsics are allowed to vary. - double ceres_intrinsics[OFFSET_MAX]; - PackIntrinisicsIntoArray(*intrinsics, ceres_intrinsics); - - // Convert cameras rotations to angle axis and merge with translation - // into single parameter block for maximal minimization speed. - // - // Block for minimization has got the following structure: - // <3 elements for angle-axis> <3 elements for translation> - vector all_cameras_R_t = - PackCamerasRotationAndTranslation(tracks, *reconstruction); - - // Parameterization used to restrict camera motion for modal solvers. - ceres::SubsetParameterization *constant_translation_parameterization = NULL; - if (bundle_constraints & BUNDLE_NO_TRANSLATION) { - std::vector constant_translation; - - // First three elements are rotation, ast three are translation. - constant_translation.push_back(3); - constant_translation.push_back(4); - constant_translation.push_back(5); - - constant_translation_parameterization = - new ceres::SubsetParameterization(6, constant_translation); - } - - // Add residual blocks to the problem. - ceres::Problem::Options problem_options; - ceres::Problem problem(problem_options); - int num_residuals = 0; - bool have_locked_camera = false; - for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; - EuclideanCamera *camera = reconstruction->CameraForImage(marker.image); - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); - if (camera == NULL || point == NULL) { - continue; - } - - // Rotation of camera denoted in angle axis followed with - // camera translaiton. - double *current_camera_R_t = &all_cameras_R_t[camera->image](0); - - // Skip residual block for markers which does have absolutely - // no affect on the final solution. - // This way ceres is not gonna to go crazy. - if (marker.weight != 0.0) { - problem.AddResidualBlock(new ceres::AutoDiffCostFunction< - OpenCVReprojectionError, 2, OFFSET_MAX, 6, 3>( - new OpenCVReprojectionError( - intrinsics->GetDistortionModelType(), - marker.x, - marker.y, - marker.weight)), - NULL, - ceres_intrinsics, - current_camera_R_t, - &point->X(0)); - - // We lock the first camera to better deal with scene orientation ambiguity. - if (!have_locked_camera) { - problem.SetParameterBlockConstant(current_camera_R_t); - have_locked_camera = true; - } - - if (bundle_constraints & BUNDLE_NO_TRANSLATION) { - problem.SetParameterization(current_camera_R_t, - constant_translation_parameterization); - } - - zero_weight_tracks_flags[marker.track] = false; - num_residuals++; - } - } - LG << "Number of residuals: " << num_residuals; - - if (!num_residuals) { - LG << "Skipping running minimizer with zero residuals"; - return; - } - - if (intrinsics->GetDistortionModelType() == DISTORTION_MODEL_DIVISION && - (bundle_intrinsics & BUNDLE_TANGENTIAL) != 0) { - LOG(FATAL) << "Division model doesn't support bundling " - "of tangential distortion"; - } - - BundleIntrinsicsLogMessage(bundle_intrinsics); - - if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) { - // No camera intrinsics are being refined, - // set the whole parameter block as constant for best performance. - problem.SetParameterBlockConstant(ceres_intrinsics); - } else { - // Set the camera intrinsics that are not to be bundled as - // constant using some macro trickery. - - std::vector constant_intrinsics; -#define MAYBE_SET_CONSTANT(bundle_enum, offset) \ - if (!(bundle_intrinsics & bundle_enum)) { \ - constant_intrinsics.push_back(offset); \ - } - MAYBE_SET_CONSTANT(BUNDLE_FOCAL_LENGTH, OFFSET_FOCAL_LENGTH); - MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, OFFSET_PRINCIPAL_POINT_X); - MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, OFFSET_PRINCIPAL_POINT_Y); - MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, OFFSET_K1); - MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, OFFSET_K2); - MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, OFFSET_P1); - MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, OFFSET_P2); -#undef MAYBE_SET_CONSTANT - - // Always set K3 constant, it's not used at the moment. - constant_intrinsics.push_back(OFFSET_K3); - - ceres::SubsetParameterization *subset_parameterization = - new ceres::SubsetParameterization(OFFSET_MAX, constant_intrinsics); - - problem.SetParameterization(ceres_intrinsics, subset_parameterization); - } - - // Configure the solver. - ceres::Solver::Options options; - options.use_nonmonotonic_steps = true; - options.preconditioner_type = ceres::SCHUR_JACOBI; - options.linear_solver_type = ceres::ITERATIVE_SCHUR; - options.use_explicit_schur_complement = true; - options.use_inner_iterations = true; - options.max_num_iterations = 100; - -#ifdef _OPENMP - options.num_threads = omp_get_max_threads(); - options.num_linear_solver_threads = omp_get_max_threads(); -#endif - - // Solve! - ceres::Solver::Summary summary; - ceres::Solve(options, &problem, &summary); - - LG << "Final report:\n" << summary.FullReport(); - - // Copy rotations and translations back. - UnpackCamerasRotationAndTranslation(tracks, - all_cameras_R_t, - reconstruction); - - // Copy intrinsics back. - if (bundle_intrinsics != BUNDLE_NO_INTRINSICS) - UnpackIntrinsicsFromArray(ceres_intrinsics, intrinsics); - - LG << "Final intrinsics: " << *intrinsics; - - if (evaluation) { - EuclideanBundlerPerformEvaluation(tracks, reconstruction, &all_cameras_R_t, - &problem, evaluation); - } - - // Separate step to adjust positions of tracks which are - // constant zero-weighted. - vector zero_weight_markers; - for (int track = 0; track < tracks.MaxTrack(); ++track) { - if (zero_weight_tracks_flags[track]) { - vector current_markers = tracks.MarkersForTrack(track); - zero_weight_markers.reserve(zero_weight_markers.size() + - current_markers.size()); - for (int i = 0; i < current_markers.size(); ++i) { - zero_weight_markers.push_back(current_markers[i]); - } - } - } - - if (zero_weight_markers.size()) { - LG << "Refining position of constant zero-weighted tracks"; - EuclideanBundlePointsOnly(intrinsics->GetDistortionModelType(), - zero_weight_markers, - all_cameras_R_t, - ceres_intrinsics, - reconstruction); - } -} - -void ProjectiveBundle(const Tracks & /*tracks*/, - ProjectiveReconstruction * /*reconstruction*/) { - // TODO(keir): Implement this! This can't work until we have a better bundler - // than SSBA, since SSBA has no support for projective bundling. -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/bundle.h b/extern/libmv/libmv/simple_pipeline/bundle.h deleted file mode 100644 index 781bd8476fe..00000000000 --- a/extern/libmv/libmv/simple_pipeline/bundle.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_BUNDLE_H -#define LIBMV_SIMPLE_PIPELINE_BUNDLE_H - -#include "libmv/numeric/numeric.h" - -namespace libmv { - -class CameraIntrinsics; -class EuclideanReconstruction; -class ProjectiveReconstruction; -class Tracks; - -struct BundleEvaluation { - BundleEvaluation() : - num_cameras(0), - num_points(0), - evaluate_jacobian(false) { - } - - // Number of cameras appeared in bundle adjustment problem - int num_cameras; - - // Number of points appeared in bundle adjustment problem - int num_points; - - // When set to truth, jacobian of the problem after optimization - // will be evaluated and stored in \parameter jacobian - bool evaluate_jacobian; - - // Contains evaluated jacobian of the problem. - // Parameters are ordered in the following way: - // - Intrinsics block - // - Cameras (for each camera rotation goes first, then translation) - // - Points - Mat jacobian; -}; - -/*! - Refine camera poses and 3D coordinates using bundle adjustment. - - This routine adjusts all cameras and points in \a *reconstruction. This - assumes a full observation for reconstructed tracks; this implies that if - there is a reconstructed 3D point (a bundle) for a track, then all markers - for that track will be included in the minimization. \a tracks should - contain markers used in the initial reconstruction. - - The cameras and bundles (3D points) are refined in-place. - - \note This assumes an outlier-free set of markers. - \note This assumes a calibrated reconstruction, e.g. the markers are - already corrected for camera intrinsics and radial distortion. - - \sa EuclideanResect, EuclideanIntersect, EuclideanReconstructTwoFrames -*/ -void EuclideanBundle(const Tracks &tracks, - EuclideanReconstruction *reconstruction); - -/*! - Refine camera poses and 3D coordinates using bundle adjustment. - - This routine adjusts all cameras positions, points, and the camera - intrinsics (assumed common across all images) in \a *reconstruction. This - assumes a full observation for reconstructed tracks; this implies that if - there is a reconstructed 3D point (a bundle) for a track, then all markers - for that track will be included in the minimization. \a tracks should - contain markers used in the initial reconstruction. - - The cameras, bundles, and intrinsics are refined in-place. - - Constraints denotes which blocks to keep constant during bundling. - For example it is useful to keep camera translations constant - when bundling tripod motions. - - If evaluaiton is not null, different evaluation statistics is filled in - there, plus all the requested additional information (like jacobian) is - also calculating there. Also see comments for BundleEvaluation. - - \note This assumes an outlier-free set of markers. - - \sa EuclideanResect, EuclideanIntersect, EuclideanReconstructTwoFrames -*/ -enum BundleIntrinsics { - BUNDLE_NO_INTRINSICS = 0, - BUNDLE_FOCAL_LENGTH = 1, - BUNDLE_PRINCIPAL_POINT = 2, - BUNDLE_RADIAL_K1 = 4, - BUNDLE_RADIAL_K2 = 8, - BUNDLE_RADIAL = 12, - BUNDLE_TANGENTIAL_P1 = 16, - BUNDLE_TANGENTIAL_P2 = 32, - BUNDLE_TANGENTIAL = 48, -}; -enum BundleConstraints { - BUNDLE_NO_CONSTRAINTS = 0, - BUNDLE_NO_TRANSLATION = 1, -}; -void EuclideanBundleCommonIntrinsics( - const Tracks &tracks, - const int bundle_intrinsics, - const int bundle_constraints, - EuclideanReconstruction *reconstruction, - CameraIntrinsics *intrinsics, - BundleEvaluation *evaluation = NULL); - -/*! - Refine camera poses and 3D coordinates using bundle adjustment. - - This routine adjusts all cameras and points in \a *reconstruction. This - assumes a full observation for reconstructed tracks; this implies that if - there is a reconstructed 3D point (a bundle) for a track, then all markers - for that track will be included in the minimization. \a tracks should - contain markers used in the initial reconstruction. - - The cameras and bundles (homogeneous 3D points) are refined in-place. - - \note This assumes an outlier-free set of markers. - \note This assumes that radial distortion is already corrected for, but - does not assume that that other intrinsics are. - - \sa ProjectiveResect, ProjectiveIntersect, ProjectiveReconstructTwoFrames -*/ -void ProjectiveBundle(const Tracks &tracks, - ProjectiveReconstruction *reconstruction); - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_BUNDLE_H - diff --git a/extern/libmv/libmv/simple_pipeline/callbacks.h b/extern/libmv/libmv/simple_pipeline/callbacks.h deleted file mode 100644 index 58f7b0d3cc9..00000000000 --- a/extern/libmv/libmv/simple_pipeline/callbacks.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_CALLBACKS_H_ -#define LIBMV_SIMPLE_PIPELINE_CALLBACKS_H_ - -namespace libmv { - -class ProgressUpdateCallback { - public: - virtual ~ProgressUpdateCallback() {} - virtual void invoke(double progress, const char *message) = 0; -}; - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_MARKERS_H_ diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc deleted file mode 100644 index 5e4e07b3c4c..00000000000 --- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/camera_intrinsics.h" - -#include "libmv/logging/logging.h" -#include "libmv/simple_pipeline/distortion_models.h" - -namespace libmv { - -namespace internal { - -LookupWarpGrid::LookupWarpGrid() - : offset_(NULL), - width_(0), - height_(0), - overscan_(0.0), - threads_(1) {} - -LookupWarpGrid::LookupWarpGrid(const LookupWarpGrid &from) - : offset_(NULL), - width_(from.width_), - height_(from.height_), - overscan_(from.overscan_), - threads_(from.threads_) { - if (from.offset_) { - offset_ = new Offset[width_ * height_]; - memcpy(offset_, from.offset_, sizeof(Offset) * width_ * height_); - } -} - -LookupWarpGrid::~LookupWarpGrid() { - delete [] offset_; -} - -void LookupWarpGrid::Reset() { - delete [] offset_; - offset_ = NULL; -} - -// Set number of threads used for threaded buffer distortion/undistortion. -void LookupWarpGrid::SetThreads(int threads) { - threads_ = threads; -} - -} // namespace internal - -CameraIntrinsics::CameraIntrinsics() - : image_width_(0), - image_height_(0), - K_(Mat3::Identity()) {} - -CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics &from) - : image_width_(from.image_width_), - image_height_(from.image_height_), - K_(from.K_), - distort_(from.distort_), - undistort_(from.undistort_) {} - -// Set the image size in pixels. -void CameraIntrinsics::SetImageSize(int width, int height) { - image_width_ = width; - image_height_ = height; - ResetLookupGrids(); -} - -// Set the entire calibration matrix at once. -void CameraIntrinsics::SetK(const Mat3 new_k) { - K_ = new_k; - ResetLookupGrids(); -} - -// Set both x and y focal length in pixels. -void CameraIntrinsics::SetFocalLength(double focal_x, - double focal_y) { - K_(0, 0) = focal_x; - K_(1, 1) = focal_y; - ResetLookupGrids(); -} - -// Set principal point in pixels. -void CameraIntrinsics::SetPrincipalPoint(double cx, - double cy) { - K_(0, 2) = cx; - K_(1, 2) = cy; - ResetLookupGrids(); -} - -// Set number of threads used for threaded buffer distortion/undistortion. -void CameraIntrinsics::SetThreads(int threads) { - distort_.SetThreads(threads); - undistort_.SetThreads(threads); -} - -void CameraIntrinsics::ImageSpaceToNormalized(double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const { - *normalized_x = (image_x - principal_point_x()) / focal_length_x(); - *normalized_y = (image_y - principal_point_y()) / focal_length_y(); -} - -void CameraIntrinsics::NormalizedToImageSpace(double normalized_x, - double normalized_y, - double *image_x, - double *image_y) const { - *image_x = normalized_x * focal_length_x() + principal_point_x(); - *image_y = normalized_y * focal_length_y() + principal_point_y(); -} - -// Reset lookup grids after changing the distortion model. -void CameraIntrinsics::ResetLookupGrids() { - distort_.Reset(); - undistort_.Reset(); -} - -PolynomialCameraIntrinsics::PolynomialCameraIntrinsics() - : CameraIntrinsics() { - SetRadialDistortion(0.0, 0.0, 0.0); - SetTangentialDistortion(0.0, 0.0); -} - -PolynomialCameraIntrinsics::PolynomialCameraIntrinsics( - const PolynomialCameraIntrinsics &from) - : CameraIntrinsics(from) { - SetRadialDistortion(from.k1(), from.k2(), from.k3()); - SetTangentialDistortion(from.p1(), from.p2()); -} - -void PolynomialCameraIntrinsics::SetRadialDistortion(double k1, - double k2, - double k3) { - parameters_[OFFSET_K1] = k1; - parameters_[OFFSET_K2] = k2; - parameters_[OFFSET_K3] = k3; - ResetLookupGrids(); -} - -void PolynomialCameraIntrinsics::SetTangentialDistortion(double p1, - double p2) { - parameters_[OFFSET_P1] = p1; - parameters_[OFFSET_P2] = p2; - ResetLookupGrids(); -} - -void PolynomialCameraIntrinsics::ApplyIntrinsics(double normalized_x, - double normalized_y, - double *image_x, - double *image_y) const { - ApplyPolynomialDistortionModel(focal_length_x(), - focal_length_y(), - principal_point_x(), - principal_point_y(), - k1(), k2(), k3(), - p1(), p2(), - normalized_x, - normalized_y, - image_x, - image_y); -} - -void PolynomialCameraIntrinsics::InvertIntrinsics( - double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const { - InvertPolynomialDistortionModel(focal_length_x(), - focal_length_y(), - principal_point_x(), - principal_point_y(), - k1(), k2(), k3(), - p1(), p2(), - image_x, - image_y, - normalized_x, - normalized_y); -} - -DivisionCameraIntrinsics::DivisionCameraIntrinsics() - : CameraIntrinsics() { - SetDistortion(0.0, 0.0); -} - -DivisionCameraIntrinsics::DivisionCameraIntrinsics( - const DivisionCameraIntrinsics &from) - : CameraIntrinsics(from) { - SetDistortion(from.k1(), from.k1()); -} - -void DivisionCameraIntrinsics::SetDistortion(double k1, - double k2) { - parameters_[OFFSET_K1] = k1; - parameters_[OFFSET_K2] = k2; - ResetLookupGrids(); -} - -void DivisionCameraIntrinsics::ApplyIntrinsics(double normalized_x, - double normalized_y, - double *image_x, - double *image_y) const { - ApplyDivisionDistortionModel(focal_length_x(), - focal_length_y(), - principal_point_x(), - principal_point_y(), - k1(), k2(), - normalized_x, - normalized_y, - image_x, - image_y); -} - -void DivisionCameraIntrinsics::InvertIntrinsics(double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const { - InvertDivisionDistortionModel(focal_length_x(), - focal_length_y(), - principal_point_x(), - principal_point_y(), - k1(), k2(), - image_x, - image_y, - normalized_x, - normalized_y); -} - -std::ostream& operator <<(std::ostream &os, - const CameraIntrinsics &intrinsics) { - if (intrinsics.focal_length_x() == intrinsics.focal_length_x()) { - os << "f=" << intrinsics.focal_length(); - } else { - os << "fx=" << intrinsics.focal_length_x() - << " fy=" << intrinsics.focal_length_y(); - } - os << " cx=" << intrinsics.principal_point_x() - << " cy=" << intrinsics.principal_point_y() - << " w=" << intrinsics.image_width() - << " h=" << intrinsics.image_height(); - -#define PRINT_NONZERO_COEFFICIENT(intrinsics, coeff) \ - { \ - if (intrinsics->coeff() != 0.0) { \ - os << " " #coeff "=" << intrinsics->coeff(); \ - } \ - } (void) 0 - - switch (intrinsics.GetDistortionModelType()) { - case DISTORTION_MODEL_POLYNOMIAL: - { - const PolynomialCameraIntrinsics *polynomial_intrinsics = - static_cast(&intrinsics); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k1); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k2); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k3); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p1); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p2); - break; - } - case DISTORTION_MODEL_DIVISION: - { - const DivisionCameraIntrinsics *division_intrinsics = - static_cast(&intrinsics); - PRINT_NONZERO_COEFFICIENT(division_intrinsics, k1); - PRINT_NONZERO_COEFFICIENT(division_intrinsics, k2); - break; - } - default: - LOG(FATAL) << "Unknown distortion model."; - } - -#undef PRINT_NONZERO_COEFFICIENT - - return os; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h deleted file mode 100644 index 6a3ade81089..00000000000 --- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_ -#define LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_ - -#include -#include - -#include - -#include "libmv/numeric/numeric.h" -#include "libmv/simple_pipeline/distortion_models.h" - -namespace libmv { - -class CameraIntrinsics; - -namespace internal { - -// This class is responsible to store a lookup grid to perform -// image warping using this lookup grid. Such a magic is needed -// to make (un)distortion as fast as possible in cases multiple -// images are to be processed. -class LookupWarpGrid { - public: - LookupWarpGrid(); - LookupWarpGrid(const LookupWarpGrid &from); - ~LookupWarpGrid(); - - // Width and height og the image, measured in pixels. - int width() const { return width_; } - int height() const { return height_; } - - // Overscan factor of the image, so that - // - 0.0 is overscan of 0 pixels, - // - 1.0 is overscan of image weight pixels in horizontal direction - // and image height pixels in vertical direction. - double overscan() const { return overscan_; } - - // Update lookup grid in order to be sure it's calculated for - // given image width, height and overscan. - // - // See comment for CameraIntrinsics::DistortBuffer to get more - // details about what overscan is. - template - void Update(const CameraIntrinsics &intrinsics, - int width, - int height, - double overscan); - - // Apply coordinate lookup grid on a giver input buffer. - // - // See comment for CameraIntrinsics::DistortBuffer to get more - // details about template type. - template - void Apply(const PixelType *input_buffer, - int width, - int height, - int channels, - PixelType *output_buffer); - - // Reset lookup grids. - // This will tag the grid for update without re-computing it. - void Reset(); - - // Set number of threads used for threaded buffer distortion/undistortion. - void SetThreads(int threads); - - private: - // This structure contains an offset in both x,y directions - // in an optimized way sawing some bytes per pixel in the memory. - // - // TODO(sergey): This is rather questionable optimizations, memory - // is cheap nowadays and storing offset in such a way implies much - // more operations comparing to using bare floats. - struct Offset { - // Integer part of the offset. - short ix, iy; - - // Float part of an offset, to get a real float value divide this - // value by 255. - unsigned char fx, fy; - }; - - // Compute coordinate lookup grid using a giver warp functor. - // - // width and height corresponds to a size of buffer which will - // be warped later. - template - void Compute(const CameraIntrinsics &intrinsics, - int width, - int height, - double overscan); - - // This is a buffer which contains per-pixel offset of the - // pixels from input buffer to correspond the warping function. - Offset *offset_; - - // Dimensions of the image this lookup grid processes. - int width_, height_; - - // Overscan of the image being processed by this grid. - double overscan_; - - // Number of threads which will be used for buffer istortion/undistortion. - int threads_; -}; - -} // namespace internal - -class CameraIntrinsics { - public: - CameraIntrinsics(); - CameraIntrinsics(const CameraIntrinsics &from); - virtual ~CameraIntrinsics() {} - - virtual DistortionModelType GetDistortionModelType() const = 0; - - int image_width() const { return image_width_; } - int image_height() const { return image_height_; } - - const Mat3 &K() const { return K_; } - - double focal_length() const { return K_(0, 0); } - double focal_length_x() const { return K_(0, 0); } - double focal_length_y() const { return K_(1, 1); } - - double principal_point_x() const { return K_(0, 2); } - double principal_point_y() const { return K_(1, 2); } - - virtual int num_distortion_parameters() const = 0; - virtual double *distortion_parameters() = 0; - virtual const double *distortion_parameters() const = 0; - - // Set the image size in pixels. - // Image is the size of image camera intrinsics were calibrated with. - void SetImageSize(int width, int height); - - // Set the entire calibration matrix at once. - void SetK(const Mat3 new_k); - - // Set both x and y focal length in pixels. - void SetFocalLength(double focal_x, double focal_y); - - // Set principal point in pixels. - void SetPrincipalPoint(double cx, double cy); - - // Set number of threads used for threaded buffer distortion/undistortion. - void SetThreads(int threads); - - // Convert image space coordinates to normalized. - void ImageSpaceToNormalized(double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const; - - // Convert normalized coordinates to image space. - void NormalizedToImageSpace(double normalized_x, - double normalized_y, - double *image_x, - double *image_y) const; - - // Apply camera intrinsics to the normalized point to get image coordinates. - // - // This applies the lens distortion to a point which is in normalized - // camera coordinates (i.e. the principal point is at (0, 0)) to get image - // coordinates in pixels. - virtual void ApplyIntrinsics(double normalized_x, - double normalized_y, - double *image_x, - double *image_y) const = 0; - - // Invert camera intrinsics on the image point to get normalized coordinates. - // - // This reverses the effect of lens distortion on a point which is in image - // coordinates to get normalized camera coordinates. - virtual void InvertIntrinsics(double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const = 0; - - // Distort an image using the current camera instrinsics - // - // The distorted image is computed in output_buffer using samples from - // input_buffer. Both buffers should be width x height x channels sized. - // - // Overscan is a percentage value of how much overcan the image have. - // For example overscal value of 0.2 means 20% of overscan in the - // buffers. - // - // Overscan is usually used in cases when one need to distort an image - // and don't have a barrel in the distorted buffer. For example, when - // one need to render properly distorted FullHD frame without barrel - // visible. For such cases renderers usually renders bigger images and - // crops them after the distortion. - // - // This method is templated to be able to distort byte and float buffers - // without having separate methods for this two types. So basically only - // - // But in fact PixelType might be any type for which multiplication by - // a scalar and addition are implemented. For example PixelType might be - // Vec3 as well. - template - void DistortBuffer(const PixelType *input_buffer, - int width, - int height, - double overscan, - int channels, - PixelType *output_buffer); - - // Undistort an image using the current camera instrinsics - // - // The undistorted image is computed in output_buffer using samples from - // input_buffer. Both buffers should be width x height x channels sized. - // - // Overscan is a percentage value of how much overcan the image have. - // For example overscal value of 0.2 means 20% of overscan in the - // buffers. - // - // Overscan is usually used in cases when one need to distort an image - // and don't have a barrel in the distorted buffer. For example, when - // one need to render properly distorted FullHD frame without barrel - // visible. For such cases renderers usually renders bigger images and - // crops them after the distortion. - // - // This method is templated to be able to distort byte and float buffers - // without having separate methods for this two types. So basically only - // - // But in fact PixelType might be any type for which multiplication by - // a scalar and addition are implemented. For example PixelType might be - // Vec3 as well. - template - void UndistortBuffer(const PixelType *input_buffer, - int width, - int height, - double overscan, - int channels, - PixelType *output_buffer); - - private: - // This is the size of the image. This is necessary to, for example, handle - // the case of processing a scaled image. - int image_width_; - int image_height_; - - // The traditional intrinsics matrix from x = K[R|t]X. - Mat3 K_; - - // Coordinate lookup grids for distortion and undistortion. - internal::LookupWarpGrid distort_; - internal::LookupWarpGrid undistort_; - - protected: - // Reset lookup grids after changing the distortion model. - void ResetLookupGrids(); -}; - -class PolynomialCameraIntrinsics : public CameraIntrinsics { - public: - // This constants defines an offset of corresponding coefficients - // in the arameters_ array. - enum { - OFFSET_K1, - OFFSET_K2, - OFFSET_K3, - OFFSET_P1, - OFFSET_P2, - - // This defines the size of array which we need to have in order - // to store all the coefficients. - NUM_PARAMETERS, - }; - - PolynomialCameraIntrinsics(); - PolynomialCameraIntrinsics(const PolynomialCameraIntrinsics &from); - - DistortionModelType GetDistortionModelType() const { - return DISTORTION_MODEL_POLYNOMIAL; - } - - int num_distortion_parameters() const { return NUM_PARAMETERS; } - double *distortion_parameters() { return parameters_; }; - const double *distortion_parameters() const { return parameters_; }; - - double k1() const { return parameters_[OFFSET_K1]; } - double k2() const { return parameters_[OFFSET_K2]; } - double k3() const { return parameters_[OFFSET_K3]; } - double p1() const { return parameters_[OFFSET_P1]; } - double p2() const { return parameters_[OFFSET_P2]; } - - // Set radial distortion coeffcients. - void SetRadialDistortion(double k1, double k2, double k3); - - // Set tangential distortion coeffcients. - void SetTangentialDistortion(double p1, double p2); - - // Apply camera intrinsics to the normalized point to get image coordinates. - // - // This applies the lens distortion to a point which is in normalized - // camera coordinates (i.e. the principal point is at (0, 0)) to get image - // coordinates in pixels. - void ApplyIntrinsics(double normalized_x, - double normalized_y, - double *image_x, - double *image_y) const; - - // Invert camera intrinsics on the image point to get normalized coordinates. - // - // This reverses the effect of lens distortion on a point which is in image - // coordinates to get normalized camera coordinates. - void InvertIntrinsics(double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const; - - private: - // OpenCV's distortion model with third order polynomial radial distortion - // terms and second order tangential distortion. The distortion is applied to - // the normalized coordinates before the focal length, which makes them - // independent of image size. - double parameters_[NUM_PARAMETERS]; -}; - -class DivisionCameraIntrinsics : public CameraIntrinsics { - public: - // This constants defines an offset of corresponding coefficients - // in the arameters_ array. - enum { - OFFSET_K1, - OFFSET_K2, - - // This defines the size of array which we need to have in order - // to store all the coefficients. - NUM_PARAMETERS, - }; - - DivisionCameraIntrinsics(); - DivisionCameraIntrinsics(const DivisionCameraIntrinsics &from); - - DistortionModelType GetDistortionModelType() const { - return DISTORTION_MODEL_DIVISION; - } - - int num_distortion_parameters() const { return NUM_PARAMETERS; } - double *distortion_parameters() { return parameters_; }; - const double *distortion_parameters() const { return parameters_; }; - - double k1() const { return parameters_[OFFSET_K1]; } - double k2() const { return parameters_[OFFSET_K2]; } - - // Set radial distortion coeffcients. - void SetDistortion(double k1, double k2); - - // Apply camera intrinsics to the normalized point to get image coordinates. - // - // This applies the lens distortion to a point which is in normalized - // camera coordinates (i.e. the principal point is at (0, 0)) to get image - // coordinates in pixels. - void ApplyIntrinsics(double normalized_x, - double normalized_y, - double *image_x, - double *image_y) const; - - // Invert camera intrinsics on the image point to get normalized coordinates. - // - // This reverses the effect of lens distortion on a point which is in image - // coordinates to get normalized camera coordinates. - void InvertIntrinsics(double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const; - - private: - // Double-parameter division distortion model. - double parameters_[NUM_PARAMETERS]; -}; - -/// A human-readable representation of the camera intrinsic parameters. -std::ostream& operator <<(std::ostream &os, - const CameraIntrinsics &intrinsics); - -} // namespace libmv - -// Include implementation of all templated methods here, -// so they're visible to the compiler. -#include "libmv/simple_pipeline/camera_intrinsics_impl.h" - -#endif // LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_ diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h b/extern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h deleted file mode 100644 index 97abee7ab01..00000000000 --- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -namespace libmv { - -namespace { - -// FIXME: C++ templates limitations makes thing complicated, -// but maybe there is a simpler method. -struct ApplyIntrinsicsFunction { - ApplyIntrinsicsFunction(const CameraIntrinsics &intrinsics, - double x, - double y, - double *warp_x, - double *warp_y) { - double normalized_x, normalized_y; - intrinsics.ImageSpaceToNormalized(x, y, &normalized_x, &normalized_y); - intrinsics.ApplyIntrinsics(normalized_x, normalized_y, warp_x, warp_y); - } -}; - -struct InvertIntrinsicsFunction { - InvertIntrinsicsFunction(const CameraIntrinsics &intrinsics, - double x, - double y, - double *warp_x, - double *warp_y) { - double normalized_x, normalized_y; - intrinsics.InvertIntrinsics(x, y, &normalized_x, &normalized_y); - intrinsics.NormalizedToImageSpace(normalized_x, normalized_y, warp_x, warp_y); - } -}; - -} // namespace - -namespace internal { - -// TODO(MatthiasF): downsample lookup -template -void LookupWarpGrid::Compute(const CameraIntrinsics &intrinsics, - int width, - int height, - double overscan) { - double w = (double) width / (1.0 + overscan); - double h = (double) height / (1.0 + overscan); - double aspx = (double) w / intrinsics.image_width(); - double aspy = (double) h / intrinsics.image_height(); -#if defined(_OPENMP) -# pragma omp parallel for schedule(dynamic) num_threads(threads_) \ - if (threads_ > 1 && height > 100) -#endif - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - double src_x = (x - 0.5 * overscan * w) / aspx, - src_y = (y - 0.5 * overscan * h) / aspy; - double warp_x, warp_y; - WarpFunction(intrinsics, src_x, src_y, &warp_x, &warp_y); - warp_x = warp_x * aspx + 0.5 * overscan * w; - warp_y = warp_y * aspy + 0.5 * overscan * h; - int ix = int(warp_x), iy = int(warp_y); - int fx = round((warp_x - ix) * 256), fy = round((warp_y - iy) * 256); - if (fx == 256) { fx = 0; ix++; } // NOLINT - if (fy == 256) { fy = 0; iy++; } // NOLINT - // Use nearest border pixel - if (ix < 0) { ix = 0, fx = 0; } // NOLINT - if (iy < 0) { iy = 0, fy = 0; } // NOLINT - if (ix >= width - 2) ix = width - 2; - if (iy >= height - 2) iy = height - 2; - - Offset offset = { (short) (ix - x), - (short) (iy - y), - (unsigned char) fx, - (unsigned char) fy }; - offset_[y * width + x] = offset; - } - } -} - -template -void LookupWarpGrid::Update(const CameraIntrinsics &intrinsics, - int width, - int height, - double overscan) { - if (width_ != width || - height_ != height || - overscan_ != overscan) { - Reset(); - } - - if (offset_ == NULL) { - offset_ = new Offset[width * height]; - Compute(intrinsics, - width, - height, - overscan); - } - - width_ = width; - height_ = height; - overscan_ = overscan; -} - -// TODO(MatthiasF): cubic B-Spline image sampling, bilinear lookup -template -void LookupWarpGrid::Apply(const PixelType *input_buffer, - int width, - int height, - int channels, - PixelType *output_buffer) { -#if defined(_OPENMP) -# pragma omp parallel for schedule(dynamic) num_threads(threads_) \ - if (threads_ > 1 && height > 100) -#endif - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - Offset offset = offset_[y * width + x]; - const int pixel_index = ((y + offset.iy) * width + - (x + offset.ix)) * channels; - const PixelType *s = &input_buffer[pixel_index]; - for (int i = 0; i < channels; i++) { - output_buffer[(y * width + x) * channels + i] = - ((s[i] * (256 - offset.fx) + - s[channels + i] * offset.fx) * (256 - offset.fy) + - (s[width * channels + i] * (256 - offset.fx) + - s[width * channels + channels + i] * offset.fx) * offset.fy) - / (256 * 256); - } - } - } -} - -} // namespace internal - -template -void CameraIntrinsics::DistortBuffer(const PixelType *input_buffer, - int width, - int height, - double overscan, - int channels, - PixelType *output_buffer) { - assert(channels >= 1); - assert(channels <= 4); - distort_.Update(*this, - width, - height, - overscan); - distort_.Apply(input_buffer, - width, - height, - channels, - output_buffer); -} - -template -void CameraIntrinsics::UndistortBuffer(const PixelType *input_buffer, - int width, - int height, - double overscan, - int channels, - PixelType *output_buffer) { - assert(channels >= 1); - assert(channels <= 4); - undistort_.Update(*this, - width, - height, - overscan); - - undistort_.Apply(input_buffer, - width, - height, - channels, - output_buffer); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc b/extern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc deleted file mode 100644 index 96d35a29ef8..00000000000 --- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/camera_intrinsics.h" - -#include - -#include "testing/testing.h" -#include "libmv/image/image.h" -#include "libmv/image/image_drawing.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -TEST(PolynomialCameraIntrinsics2, ApplyOnFocalCenter) { - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(1300.0, 1300.0); - intrinsics.SetPrincipalPoint(640.0, 540.0); - intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05); - - double distorted_x, distorted_y; - intrinsics.ApplyIntrinsics(0.0, 0.0, &distorted_x, &distorted_y); - - EXPECT_NEAR(640.0, distorted_x, 1e-8); - EXPECT_NEAR(540.0, distorted_y, 1e-8); -} - -TEST(PolynomialCameraIntrinsics, InvertOnFocalCenter) { - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(1300.0, 1300.0); - intrinsics.SetPrincipalPoint(640.0, 540.0); - intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05); - - double normalized_x, normalized_y; - intrinsics.InvertIntrinsics(640.0, 540.0, &normalized_x, &normalized_y); - - EXPECT_NEAR(0.0, normalized_x, 1e-8); - EXPECT_NEAR(0.0, normalized_y, 1e-8); -} - -TEST(PolynomialCameraIntrinsics, ApplyIntrinsics) { - const int N = 5; - - double expected[N][N][2] = { - { {75.312500, -24.687500}, {338.982239, -62.035522}, - {640.000000, -72.929688}, {941.017761, -62.035522}, - {1204.687500, -24.687500}}, - - { {37.964478, 238.982239}, {323.664551, 223.664551}, - {640.000000, 219.193420}, {956.335449, 223.664551}, - {1242.035522, 238.982239}}, - - { {27.070312, 540.000000}, {319.193420, 540.000000}, - {640.000000, 540.000000}, {960.806580, 540.000000}, - {1252.929688, 540.000000}}, - - { {37.964478, 841.017761}, {323.664551, 856.335449}, - {640.000000, 860.806580}, {956.335449, 856.335449}, - {1242.035522, 841.017761}}, - - { {75.312500, 1104.687500}, {338.982239, 1142.035522}, - {640.000000, 1152.929688}, {941.017761, 1142.035522}, - {1204.687500, 1104.687500}} - }; - - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(1300.0, 1300.0); - intrinsics.SetPrincipalPoint(640.0, 540.0); - intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05); - - double step = 1.0 / (N - 1); - - for (int i = 0; i < N; i++) { - for (int j = 0; j < N; j++) { - double normalized_x = j * step - 0.5, - normalized_y = i * step - 0.5; - - double distorted_x, distorted_y; - intrinsics.ApplyIntrinsics(normalized_x, normalized_y, - &distorted_x, &distorted_y); - - EXPECT_NEAR(expected[i][j][0], distorted_x, 1e-6); - EXPECT_NEAR(expected[i][j][1], distorted_y, 1e-6); - } - } -} - -TEST(PolynomialCameraIntrinsics, InvertIntrinsics) { - const int N = 5; - - double expected[N][N][2] = { - { {-0.524482, -0.437069}, {-0.226237, -0.403994}, - { 0.031876, -0.398446}, { 0.293917, -0.408218}, - { 0.632438, -0.465028}}, - - { {-0.493496, -0.189173}, {-0.219052, -0.179936}, - { 0.030975, -0.178107}, { 0.283742, -0.181280}, - { 0.574557, -0.194335}}, - - { {-0.488013, 0.032534}, {-0.217537, 0.031077}, - { 0.030781, 0.030781}, { 0.281635, 0.031293}, - { 0.566344, 0.033314}}, - - { {-0.498696, 0.257660}, {-0.220424, 0.244041}, - { 0.031150, 0.241409}, { 0.285660, 0.245985}, - { 0.582670, 0.265629}}, - - { {-0.550617, 0.532263}, {-0.230399, 0.477255}, - { 0.032380, 0.469510}, { 0.299986, 0.483311}, - { 0.684740, 0.584043}} - }; - - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(1300.0, 1300.0); - intrinsics.SetPrincipalPoint(600.0, 500.0); - intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05); - - double step_x = 1280.0 / (N - 1), - step_y = 1080.0 / (N - 1); - - for (int i = 0; i < N; i++) { - for (int j = 0; j < N; j++) { - double distorted_x = j * step_x, - distorted_y = i * step_y; - - double normalized_x, normalized_y; - intrinsics.InvertIntrinsics(distorted_x, distorted_y, - &normalized_x, &normalized_y); - - EXPECT_NEAR(expected[i][j][0], normalized_x, 1e-6); - EXPECT_NEAR(expected[i][j][1], normalized_y, 1e-6); - } - } -} - -TEST(PolynomialCameraIntrinsics, ApplyIsInvertibleSimple) { - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(1300.0, 1300.0); - intrinsics.SetPrincipalPoint(640.0, 540.0); - intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05); - - // Scan over image coordinates, invert the intrinsics, then re-apply them to - // make sure the cycle gets back where it started. - for (double y = 0; y < 1000; y += 100) { - for (double x = 0; x < 1000; x += 100) { - double normalized_x, normalized_y; - intrinsics.InvertIntrinsics(x, y, &normalized_x, &normalized_y); - - double xp, yp; - intrinsics.ApplyIntrinsics(normalized_x, normalized_y, &xp, &yp); - - EXPECT_NEAR(x, xp, 1e-8) << "y: " << y; - EXPECT_NEAR(y, yp, 1e-8) << "x: " << x; - LG << "Error x: " << (x - xp); - LG << "Error y: " << (y - yp); - } - } -} - -TEST(PolynomialCameraIntrinsics, IdentityDistortBuffer) { - const int w = 101, h = 101; - FloatImage image(h, w); - image.Fill(0); - - DrawLine(0.0, h / 2.0, w - 1, h / 2.0, 1.0, &image); - DrawLine(0.0, h / 4.0, w - 1, h / 4.0, 1.0, &image); - DrawLine(0.0, h / 4.0 * 3.0, w - 1.0, h / 4.0 * 3.0, 1.0, &image); - DrawLine(w / 2.0, 0.0, w / 2.0, h - 1.0, 1.0, &image); - DrawLine(w / 4.0, 0.0, w / 4.0, h - 1.0, 1.0, &image); - DrawLine(w / 4.0 * 3.0, 0.0, w / 4.0 * 3.0, h - 1.0, 1.0, &image); - - PolynomialCameraIntrinsics intrinsics; - FloatImage distorted_image(h, w); - intrinsics.SetImageSize(w, h); - intrinsics.SetFocalLength(10.0, 10.0); - intrinsics.SetPrincipalPoint((double) w / 2.0, (double) h / 2.0); - intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); - intrinsics.DistortBuffer(image.Data(), - image.Width(), image.Height(), - 0.0, - image.Depth(), - distorted_image.Data()); - - for (int x = 0; x < image.Width(); ++x) { - for (int y = 0; y < image.Height(); ++y) { - EXPECT_EQ(image(y, x), distorted_image(y, x)); - } - } -} - -TEST(PolynomialCameraIntrinsics, IdentityUndistortBuffer) { - const int w = 101, h = 101; - FloatImage image(h, w); - image.Fill(0); - - DrawLine(0.0, h / 2.0, w - 1, h / 2.0, 1.0, &image); - DrawLine(0.0, h / 4.0, w - 1, h / 4.0, 1.0, &image); - DrawLine(0.0, h / 4.0 * 3.0, w - 1.0, h / 4.0 * 3.0, 1.0, &image); - DrawLine(w / 2.0, 0.0, w / 2.0, h - 1.0, 1.0, &image); - DrawLine(w / 4.0, 0.0, w / 4.0, h - 1.0, 1.0, &image); - DrawLine(w / 4.0 * 3.0, 0.0, w / 4.0 * 3.0, h - 1.0, 1.0, &image); - - PolynomialCameraIntrinsics intrinsics; - FloatImage distorted_image(h, w); - intrinsics.SetImageSize(w, h); - intrinsics.SetFocalLength(10.0, 10.0); - intrinsics.SetPrincipalPoint((double) w / 2.0, (double) h / 2.0); - intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); - intrinsics.UndistortBuffer(image.Data(), - image.Width(), image.Height(), - 0.0, - image.Depth(), - distorted_image.Data()); - - for (int x = 0; x < image.Width(); ++x) { - for (int y = 0; y < image.Height(); ++y) { - EXPECT_EQ(image(y, x), distorted_image(y, x)); - } - } -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/detect.cc b/extern/libmv/libmv/simple_pipeline/detect.cc deleted file mode 100644 index 46599a4c49e..00000000000 --- a/extern/libmv/libmv/simple_pipeline/detect.cc +++ /dev/null @@ -1,361 +0,0 @@ -/**************************************************************************** -** -** Copyright (c) 2011 libmv authors. -** -** Permission is hereby granted, free of charge, to any person obtaining a copy -** of this software and associated documentation files (the "Software"), to -** deal in the Software without restriction, including without limitation the -** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -** sell copies of the Software, and to permit persons to whom the Software is -** furnished to do so, subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in -** all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -** IN THE SOFTWARE. -** -****************************************************************************/ - -#include -#include -#include - -#include "libmv/base/scoped_ptr.h" -#include "libmv/image/array_nd.h" -#include "libmv/image/image_converter.h" -#include "libmv/image/convolve.h" -#include "libmv/logging/logging.h" -#include "libmv/simple_pipeline/detect.h" - -#ifndef LIBMV_NO_FAST_DETECTOR -# include -#endif - -#ifdef __SSE2__ -# include -#endif - -namespace libmv { - -namespace { - -// Default value for FAST minimal trackness in the DetectOptions structure. -// TODO(sergey): Think of a better default value here. -int kDefaultFastMinTrackness = 128; - -// Default value for Harris threshold in the DetectOptions structure. -// TODO(sergey): Think of a better default value here. -double kDefaultHarrisThreshold = 1e-5; - -class FeatureComparison { - public: - bool operator() (const Feature &left, const Feature &right) const { - return right.score > left.score; - } -}; - -// Filter the features so there are no features closer than -// minimal distance to each other. -// This is a naive implementation with O(n^2) asymptotic. -void FilterFeaturesByDistance(const vector &all_features, - int min_distance, - vector *detected_features) { - const int min_distance_squared = min_distance * min_distance; - - // Use priority queue to sort the features by their score. - // - // Do this on copy of the input features to prevent possible - // distortion in callee function behavior. - std::priority_queue, - FeatureComparison> priority_features; - - for (int i = 0; i < all_features.size(); i++) { - priority_features.push(all_features.at(i)); - } - - while (!priority_features.empty()) { - bool ok = true; - Feature a = priority_features.top(); - - for (int i = 0; i < detected_features->size(); i++) { - Feature &b = detected_features->at(i); - if (Square(a.x - b.x) + Square(a.y - b.y) < min_distance_squared) { - ok = false; - break; - } - } - - if (ok) { - detected_features->push_back(a); - } - - priority_features.pop(); - } -} - -void DetectFAST(const FloatImage &grayscale_image, - const DetectOptions &options, - vector *detected_features) { -#ifndef LIBMV_NO_FAST_DETECTOR - const int min_distance = options.min_distance; - const int min_trackness = options.fast_min_trackness; - const int margin = options.margin; - const int width = grayscale_image.Width() - 2 * margin; - const int height = grayscale_image.Width() - 2 * margin; - const int stride = grayscale_image.Width(); - - scoped_array byte_image(FloatImageToUCharArray(grayscale_image)); - const int byte_image_offset = margin * stride + margin; - - // TODO(MatthiasF): Support targetting a feature count (binary search trackness) - int num_features; - xy *all = fast9_detect(byte_image.get() + byte_image_offset, - width, - height, - stride, - min_trackness, - &num_features); - if (num_features == 0) { - free(all); - return; - } - int *scores = fast9_score(byte_image.get() + byte_image_offset, - stride, - all, - num_features, - min_trackness); - // TODO(MatthiasF): merge with close feature suppression - xy *nonmax = nonmax_suppression(all, scores, num_features, &num_features); - free(all); - // Remove too close features - // TODO(MatthiasF): A resolution independent parameter would be better than - // distance e.g. a coefficient going from 0 (no minimal distance) to 1 - // (optimal circle packing) - // FIXME(MatthiasF): this method will not necessarily give all maximum markers - if (num_features) { - vector all_features; - for (int i = 0; i < num_features; ++i) { - all_features.push_back(Feature((float)nonmax[i].x + margin, - (float)nonmax[i].y + margin, - (float)scores[i], - 9.0)); - } - FilterFeaturesByDistance(all_features, min_distance, detected_features); - } - free(scores); - free(nonmax); -#else - (void) grayscale_image; // Ignored. - (void) options; // Ignored. - (void) detected_features; // Ignored. - LOG(FATAL) << "FAST detector is disabled in this build."; -#endif -} - -#ifdef __SSE2__ -static unsigned int SAD(const ubyte* imageA, const ubyte* imageB, - int strideA, int strideB) { - __m128i a = _mm_setzero_si128(); - for (int i = 0; i < 16; i++) { - a = _mm_adds_epu16(a, - _mm_sad_epu8(_mm_loadu_si128((__m128i*)(imageA+i*strideA)), - _mm_loadu_si128((__m128i*)(imageB+i*strideB)))); - } - return _mm_extract_epi16(a, 0) + _mm_extract_epi16(a, 4); -} -#else -static unsigned int SAD(const ubyte* imageA, const ubyte* imageB, - int strideA, int strideB) { - unsigned int sad = 0; - for (int i = 0; i < 16; i++) { - for (int j = 0; j < 16; j++) { - sad += abs((int)imageA[i*strideA+j] - imageB[i*strideB+j]); - } - } - return sad; -} -#endif - -void DetectMORAVEC(const FloatImage &grayscale_image, - const DetectOptions &options, - vector *detected_features) { - const int distance = options.min_distance; - const int margin = options.margin; - const unsigned char *pattern = options.moravec_pattern; - const int count = options.moravec_max_count; - const int width = grayscale_image.Width() - 2 * margin; - const int height = grayscale_image.Width() - 2 * margin; - const int stride = grayscale_image.Width(); - - scoped_array byte_image(FloatImageToUCharArray(grayscale_image)); - - unsigned short histogram[256]; - memset(histogram, 0, sizeof(histogram)); - scoped_array scores(new ubyte[width*height]); - memset(scores.get(), 0, width*height); - const int r = 1; // radius for self similarity comparison - for (int y = distance; y < height-distance; y++) { - for (int x = distance; x < width-distance; x++) { - const ubyte* s = &byte_image[y*stride+x]; - int score = // low self-similarity with overlapping patterns - // OPTI: load pattern once - SAD(s, s-r*stride-r, stride, stride)+SAD(s, s-r*stride, stride, stride)+SAD(s, s-r*stride+r, stride, stride)+ - SAD(s, s -r, stride, stride)+ SAD(s, s +r, stride, stride)+ - SAD(s, s+r*stride-r, stride, stride)+SAD(s, s+r*stride, stride, stride)+SAD(s, s+r*stride+r, stride, stride); - score /= 256; // normalize - if (pattern) // find only features similar to pattern - score -= SAD(s, pattern, stride, 16); - if (score <= 16) continue; // filter very self-similar features - score -= 16; // translate to score/histogram values - if (score>255) score=255; // clip - ubyte* c = &scores[y*width+x]; - for (int i = -distance; i < 0; i++) { - for (int j = -distance; j < distance; j++) { - int s = c[i*width+j]; - if (s == 0) continue; - if (s >= score) goto nonmax; - c[i*width+j] = 0; - histogram[s]--; - } - } - for (int i = 0, j = -distance; j < 0; j++) { - int s = c[i*width+j]; - if (s == 0) continue; - if (s >= score) goto nonmax; - c[i*width+j] = 0; - histogram[s]--; - } - c[0] = score, histogram[score]++; - nonmax: - { } // Do nothing. - } - } - int min = 255, total = 0; - for (; min > 0; min--) { - int h = histogram[min]; - if (total + h > count) { - break; - } - total += h; - } - for (int y = 16; y < height - 16; y++) { - for (int x = 16; x < width - 16; x++) { - int s = scores[y * width + x]; - if (s > min) { - // Currently SAD works with the patterns of 16x16 pixels. - // - // Score calculation above uses top left corner of the - // patch as the origin, here we need to convert this value - // to a pattrn center by adding 8 pixels. - detected_features->push_back(Feature((float) x + 8.0f, - (float) y + 8.0f, - (float) s, - 16.0f)); - } - } - } -} - -void DetectHarris(const FloatImage &grayscale_image, - const DetectOptions &options, - vector *detected_features) { - const double alpha = 0.06; - const double sigma = 0.9; - - const int min_distance = options.min_distance; - const int margin = options.margin; - const double threshold = options.harris_threshold; - - FloatImage gradient_x, gradient_y; - ImageDerivatives(grayscale_image, sigma, &gradient_x, &gradient_y); - - FloatImage gradient_xx, gradient_yy, gradient_xy; - MultiplyElements(gradient_x, gradient_x, &gradient_xx); - MultiplyElements(gradient_y, gradient_y, &gradient_yy); - MultiplyElements(gradient_x, gradient_y, &gradient_xy); - - FloatImage gradient_xx_blurred, - gradient_yy_blurred, - gradient_xy_blurred; - ConvolveGaussian(gradient_xx, sigma, &gradient_xx_blurred); - ConvolveGaussian(gradient_yy, sigma, &gradient_yy_blurred); - ConvolveGaussian(gradient_xy, sigma, &gradient_xy_blurred); - - vector all_features; - for (int y = margin; y < gradient_xx_blurred.Height() - margin; ++y) { - for (int x = margin; x < gradient_xx_blurred.Width() - margin; ++x) { - // Construct matrix - // - // A = [ Ix^2 Ix*Iy ] - // [ Ix*Iy Iy^2 ] - Mat2 A; - A(0, 0) = gradient_xx_blurred(y, x); - A(1, 1) = gradient_yy_blurred(y, x); - A(0, 1) = A(1, 0) = gradient_xy_blurred(y, x); - - double detA = A.determinant(); - double traceA = A.trace(); - double harris_function = detA - alpha * traceA * traceA; - if (harris_function > threshold) { - all_features.push_back(Feature((float) x, - (float) y, - (float) harris_function, - 5.0f)); - } - } - } - - FilterFeaturesByDistance(all_features, min_distance, detected_features); -} - -} // namespace - -DetectOptions::DetectOptions() - : type(DetectOptions::HARRIS), - margin(0), - min_distance(120), - fast_min_trackness(kDefaultFastMinTrackness), - moravec_max_count(0), - moravec_pattern(NULL), - harris_threshold(kDefaultHarrisThreshold) {} - -void Detect(const FloatImage &image, - const DetectOptions &options, - vector *detected_features) { - // Currently all the detectors requires image to be grayscale. - // Do it here to avoid code duplication. - FloatImage grayscale_image; - if (image.Depth() != 1) { - Rgb2Gray(image, &grayscale_image); - } else { - // TODO(sergey): Find a way to avoid such image duplication/ - grayscale_image = image; - } - - if (options.type == DetectOptions::FAST) { - DetectFAST(grayscale_image, options, detected_features); - } else if (options.type == DetectOptions::MORAVEC) { - DetectMORAVEC(grayscale_image, options, detected_features); - } else if (options.type == DetectOptions::HARRIS) { - DetectHarris(grayscale_image, options, detected_features); - } else { - LOG(FATAL) << "Unknown detector has been passed to featur detection"; - } -} - -std::ostream& operator <<(std::ostream &os, - const Feature &feature) { - os << "x: " << feature.x << ", y: " << feature.y; - os << ", score: " << feature.score; - os << ", size: " << feature.size; - return os; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/detect.h b/extern/libmv/libmv/simple_pipeline/detect.h deleted file mode 100644 index 1035287bcf2..00000000000 --- a/extern/libmv/libmv/simple_pipeline/detect.h +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** -** -** Copyright (c) 2011 libmv authors. -** -** Permission is hereby granted, free of charge, to any person obtaining a copy -** of this software and associated documentation files (the "Software"), to -** deal in the Software without restriction, including without limitation the -** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -** sell copies of the Software, and to permit persons to whom the Software is -** furnished to do so, subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in -** all copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -** IN THE SOFTWARE. -** -****************************************************************************/ - -#ifndef LIBMV_SIMPLE_PIPELINE_DETECT_H_ -#define LIBMV_SIMPLE_PIPELINE_DETECT_H_ - -#include -#include - -#include "libmv/base/vector.h" -#include "libmv/image/image.h" - -namespace libmv { - -typedef unsigned char ubyte; - -// A Feature is the 2D location of a detected feature in an image. -struct Feature { - Feature(float x, float y) : x(x), y(y) {} - Feature(float x, float y, float score, float size) - : x(x), y(y), score(score), size(size) {} - - // Position of the feature in pixels from top-left corner. - // Note: Libmv detector might eventually support subpixel precision. - float x, y; - - // An estimate of how well the feature will be tracked. - // - // Absolute values totally depends on particular detector type - // used for detection. It's only guaranteed that features with - // higher score from the same Detect() result will be tracked better. - float score; - - // An approximate feature size in pixels. - // - // If the feature is approximately a 5x5 square region, then size will be 5. - // It can be used as an initial pattern size to track the feature. - float size; -}; - -struct DetectOptions { - DetectOptions(); - - // TODO(sergey): Write descriptions to each of algorithms. - enum DetectorType { - FAST, - MORAVEC, - HARRIS, - }; - DetectorType type; - - // Margin in pixels from the image boundary. - // No features will be detected within the margin. - int margin; - - // Minimal distance between detected features. - int min_distance; - - // Minimum score to add a feature. Only used by FAST detector. - // - // TODO(sergey): Write more detailed documentation about which - // units this value is measured in and so on. - int fast_min_trackness; - - // Maximum count to detect. Only used by MORAVEC detector. - int moravec_max_count; - - // Find only features similar to this pattern. Only used by MORAVEC detector. - // - // This is an image patch denoted in byte array with dimensions of 16px by 16px - // used to filter features by similarity to this patch. - unsigned char *moravec_pattern; - - // Threshold value of the Harris function to add new featrue - // to the result. - double harris_threshold; -}; - -// Detect features on a given image using given detector options. -// -// Image could have 1-4 channels, it'll be converted to a grayscale -// by the detector function if needed. -void Detect(const FloatImage &image, - const DetectOptions &options, - vector *detected_features); - -std::ostream& operator <<(std::ostream &os, - const Feature &feature); - -} // namespace libmv - -#endif diff --git a/extern/libmv/libmv/simple_pipeline/detect_test.cc b/extern/libmv/libmv/simple_pipeline/detect_test.cc deleted file mode 100644 index fe57e3d04a2..00000000000 --- a/extern/libmv/libmv/simple_pipeline/detect_test.cc +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/detect.h" - -#include "testing/testing.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -namespace { - -void PreformSinglePointTest(const DetectOptions &options) { - // Prepare the image. - FloatImage image(15, 15); - image.fill(1.0); - image(7, 7) = 0.0; - - // Run the detector. - vector detected_features; - Detect(image, options, &detected_features); - - // Check detected features matches our expectations. - EXPECT_EQ(1, detected_features.size()); - if (detected_features.size() == 1) { - Feature &feature = detected_features[0]; - EXPECT_EQ(7, feature.x); - EXPECT_EQ(7, feature.y); - } -} - -void PreformCheckerBoardTest(const DetectOptions &options) { - // Prepare the image. - FloatImage image(30, 30); - for (int y = 0; y < image.Height(); ++y) { - for (int x = 0; x < image.Width(); ++x) { - image(y, x) = (x / 10 + y / 10) % 2 ? 1.0 : 0.0; - } - } - - // Run the detector. - vector detected_features; - Detect(image, options, &detected_features); - - // Check detected features matches our expectations. - - // We expect here only corners of a center square to be - // considered a feature points. - EXPECT_EQ(4, detected_features.size()); - - // We don't know which side of the corner detector will choose, - // so what we're checking here is that detected feature is from - // any side of the corner. - // - // This doesn't check whether there're multiple features which - // are placed on different sides of the same corner. The way we - // deal with this is requiring min_distance to be greater than 2px. - for (int i = 0; i < detected_features.size(); ++i) { - Feature &feature = detected_features[i]; - int rounded_x = ((feature.x + 1) / 10) * 10, - rounded_y = ((feature.y + 1) / 10) * 10; - EXPECT_LE(1, std::abs(feature.x - rounded_x)); - EXPECT_LE(1, std::abs(feature.y - rounded_y)); - } -} - -void CheckExpectedFeatures(const vector &detected_features, - const vector &expected_features) { - EXPECT_EQ(expected_features.size(), detected_features.size()); - - // That's unsafe to iterate over vectors when their lengths - // doesn't match. And it doesn't make any sense actually since - // the test will already be considered failed here. - if (expected_features.size() != detected_features.size()) { - return; - } - - for (int i = 0; i < expected_features.size(); ++i) { - const Feature &extected_feature = expected_features[i]; - bool found = false; - for (int j = 0; j < detected_features.size(); ++j) { - const Feature &detected_feature = detected_features[j]; - if (extected_feature.x == detected_feature.x && - extected_feature.y == detected_feature.y) { - found = true; - break; - } - } - EXPECT_TRUE(found); - } -} - -void PreformSingleTriangleTest(const DetectOptions &options) { - // Prepare the image. - FloatImage image(15, 21); - image.fill(1.0); - - int vertex_x = 10, vertex_y = 5; - for (int i = 0; i < 6; ++i) { - int current_x = vertex_x - i, - current_y = vertex_y + i; - for (int j = 0; j < i * 2 + 1; ++j, ++current_x) { - image(current_y, current_x) = 0.0; - } - } - - // Run the detector. - vector detected_features; - Detect(image, options, &detected_features); - - // Check detected features matches our expectations. - vector expected_features; - expected_features.push_back(Feature(6, 10)); - expected_features.push_back(Feature(14, 10)); - expected_features.push_back(Feature(10, 6)); - - CheckExpectedFeatures(detected_features, expected_features); -} - -} // namespace - -#ifndef LIBMV_NO_FAST_DETECTOR -TEST(Detect, FASTSinglePointTest) { - DetectOptions options; - options.type = DetectOptions::FAST; - options.min_distance = 0; - options.fast_min_trackness = 1; - - PreformSinglePointTest(options); -} -#endif // LIBMV_NO_FAST_DETECTOR - -#if 0 -// TODO(sergey): FAST doesn't detect checker board corners, but should it? -TEST(Detect, FASTCheckerBoardTest) { - DetectOptions options; - options.type = DetectOptions::FAST; - options.min_distance = 0; - options.fast_min_trackness = 1; - - PreformCheckerBoardTest(options); -} -#endif - -#if 0 -// TODO(sergey): FAST doesn't detect triangle corners! -TEST(Detect, FASTSingleTriangleTest) { - DetectOptions options; - options.type = DetectOptions::FAST; - options.margin = 3; - options.min_distance = 0; - options.fast_min_trackness = 2; - - PreformSingleTriangleTest(options); -} -#endif - -#if 0 -// TODO(sergey): This doesn't actually detect single point, -// but should it or it's expected that Moravec wouldn't consider -// single point as feature? -// -// Uncomment this or remove as soon as we know answer for the -// question. -TEST(Detect, MoravecSinglePointTest) { - DetectOptions options; - options.type = DetectOptions::MORAVEC; - options.min_distance = 0; - options.moravec_max_count = 10; - - PreformSinglePointTest(options); -} - -// TODO(sergey): Moravec doesn't detect checker board corners, but should it? -TEST(Detect, MoravecCheckerBoardTest) { - DetectOptions options; - options.type = DetectOptions::MORAVEC; - options.min_distance = 0; - options.moravec_max_count = 10; - - PreformCheckerBoardTest(options); -} -#endif - -TEST(Detect, HarrisSinglePointTest) { - DetectOptions options; - options.type = DetectOptions::HARRIS; - - // Set this to non-zero so image corners are not considered - // a feature points and avoid center point neighbors to be - // considered a features as well. - options.margin = 3; - options.min_distance = 3; - - PreformSinglePointTest(options); -} - -TEST(Detect, HarrisSingleTriangleTest) { - DetectOptions options; - options.type = DetectOptions::HARRIS; - - options.margin = 3; - options.min_distance = 2; - options.harris_threshold = 1e-3; - - PreformSingleTriangleTest(options); -} - -// TODO(sergey): Add tests for margin option. - -// TODO(sergey): Add tests for min_distance option. - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/distortion_models.cc b/extern/libmv/libmv/simple_pipeline/distortion_models.cc deleted file mode 100644 index 9b6dca2678a..00000000000 --- a/extern/libmv/libmv/simple_pipeline/distortion_models.cc +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/distortion_models.h" -#include "libmv/numeric/levenberg_marquardt.h" - -namespace libmv { - -namespace { - -struct InvertPolynomialIntrinsicsCostFunction { - public: - typedef Vec2 FMatrixType; - typedef Vec2 XMatrixType; - - InvertPolynomialIntrinsicsCostFunction(const double focal_length_x, - const double focal_length_y, - const double principal_point_x, - const double principal_point_y, - const double k1, - const double k2, - const double k3, - const double p1, - const double p2, - const double image_x, - const double image_y) - : focal_length_x_(focal_length_x), - focal_length_y_(focal_length_y), - principal_point_x_(principal_point_x), - principal_point_y_(principal_point_y), - k1_(k1), k2_(k2), k3_(k3), - p1_(p1), p2_(p2), - x_(image_x), y_(image_y) {} - - Vec2 operator()(const Vec2 &u) const { - double xx, yy; - - ApplyPolynomialDistortionModel(focal_length_x_, - focal_length_y_, - principal_point_x_, - principal_point_y_, - k1_, k2_, k3_, - p1_, p2_, - u(0), u(1), - &xx, &yy); - - Vec2 fx; - fx << (xx - x_), (yy - y_); - return fx; - } - double focal_length_x_; - double focal_length_y_; - double principal_point_x_; - double principal_point_y_; - double k1_, k2_, k3_; - double p1_, p2_; - double x_, y_; -}; - -struct InvertDivisionIntrinsicsCostFunction { - public: - typedef Vec2 FMatrixType; - typedef Vec2 XMatrixType; - - InvertDivisionIntrinsicsCostFunction(const double focal_length_x, - const double focal_length_y, - const double principal_point_x, - const double principal_point_y, - const double k1, - const double k2, - const double image_x, - const double image_y) - : focal_length_x_(focal_length_x), - focal_length_y_(focal_length_y), - principal_point_x_(principal_point_x), - principal_point_y_(principal_point_y), - k1_(k1), k2_(k2), - x_(image_x), y_(image_y) {} - - Vec2 operator()(const Vec2 &u) const { - double xx, yy; - - ApplyDivisionDistortionModel(focal_length_x_, - focal_length_y_, - principal_point_x_, - principal_point_y_, - k1_, k2_, - u(0), u(1), - &xx, &yy); - - Vec2 fx; - fx << (xx - x_), (yy - y_); - return fx; - } - double focal_length_x_; - double focal_length_y_; - double principal_point_x_; - double principal_point_y_; - double k1_, k2_; - double x_, y_; -}; - -} // namespace - -void InvertPolynomialDistortionModel(const double focal_length_x, - const double focal_length_y, - const double principal_point_x, - const double principal_point_y, - const double k1, - const double k2, - const double k3, - const double p1, - const double p2, - const double image_x, - const double image_y, - double *normalized_x, - double *normalized_y) { - // Compute the initial guess. For a camera with no distortion, this will also - // be the final answer; the LM iteration will terminate immediately. - Vec2 normalized; - normalized(0) = (image_x - principal_point_x) / focal_length_x; - normalized(1) = (image_y - principal_point_y) / focal_length_y; - - typedef LevenbergMarquardt Solver; - - InvertPolynomialIntrinsicsCostFunction intrinsics_cost(focal_length_x, - focal_length_y, - principal_point_x, - principal_point_y, - k1, k2, k3, - p1, p2, - image_x, image_y); - Solver::SolverParameters params; - Solver solver(intrinsics_cost); - - /*Solver::Results results =*/ solver.minimize(params, &normalized); - - // TODO(keir): Better error handling. - - *normalized_x = normalized(0); - *normalized_y = normalized(1); -} - -void InvertDivisionDistortionModel(const double focal_length_x, - const double focal_length_y, - const double principal_point_x, - const double principal_point_y, - const double k1, - const double k2, - const double image_x, - const double image_y, - double *normalized_x, - double *normalized_y) { - // Compute the initial guess. For a camera with no distortion, this will also - // be the final answer; the LM iteration will terminate immediately. - Vec2 normalized; - normalized(0) = (image_x - principal_point_x) / focal_length_x; - normalized(1) = (image_y - principal_point_y) / focal_length_y; - - // TODO(sergey): Use Ceres minimizer instead. - typedef LevenbergMarquardt Solver; - - InvertDivisionIntrinsicsCostFunction intrinsics_cost(focal_length_x, - focal_length_y, - principal_point_x, - principal_point_y, - k1, k2, - image_x, image_y); - Solver::SolverParameters params; - Solver solver(intrinsics_cost); - - /*Solver::Results results =*/ solver.minimize(params, &normalized); - - // TODO(keir): Better error handling. - - *normalized_x = normalized(0); - *normalized_y = normalized(1); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/distortion_models.h b/extern/libmv/libmv/simple_pipeline/distortion_models.h deleted file mode 100644 index 4f8e2295a0e..00000000000 --- a/extern/libmv/libmv/simple_pipeline/distortion_models.h +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_ -#define LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_ - -namespace libmv { - -enum DistortionModelType { - DISTORTION_MODEL_POLYNOMIAL, - DISTORTION_MODEL_DIVISION -}; - -// Invert camera intrinsics on the image point to get normalized coordinates. -// This inverts the radial lens distortion to a point which is in image pixel -// coordinates to get normalized coordinates. -void InvertPolynomialDistortionModel(const double focal_length_x, - const double focal_length_y, - const double principal_point_x, - const double principal_point_y, - const double k1, - const double k2, - const double k3, - const double p1, - const double p2, - const double image_x, - const double image_y, - double *normalized_x, - double *normalized_y); - -// Apply camera intrinsics to the normalized point to get image coordinates. -// This applies the radial lens distortion to a point which is in normalized -// camera coordinates (i.e. the principal point is at (0, 0)) to get image -// coordinates in pixels. Templated for use with autodifferentiation. -template -inline void ApplyPolynomialDistortionModel(const T &focal_length_x, - const T &focal_length_y, - const T &principal_point_x, - const T &principal_point_y, - const T &k1, - const T &k2, - const T &k3, - const T &p1, - const T &p2, - const T &normalized_x, - const T &normalized_y, - T *image_x, - T *image_y) { - T x = normalized_x; - T y = normalized_y; - - // Apply distortion to the normalized points to get (xd, yd). - T r2 = x*x + y*y; - T r4 = r2 * r2; - T r6 = r4 * r2; - T r_coeff = (T(1) + k1*r2 + k2*r4 + k3*r6); - T xd = x * r_coeff + T(2)*p1*x*y + p2*(r2 + T(2)*x*x); - T yd = y * r_coeff + T(2)*p2*x*y + p1*(r2 + T(2)*y*y); - - // Apply focal length and principal point to get the final image coordinates. - *image_x = focal_length_x * xd + principal_point_x; - *image_y = focal_length_y * yd + principal_point_y; -} - -// Invert camera intrinsics on the image point to get normalized coordinates. -// This inverts the radial lens distortion to a point which is in image pixel -// coordinates to get normalized coordinates. -// -// Uses division distortion model. -void InvertDivisionDistortionModel(const double focal_length_x, - const double focal_length_y, - const double principal_point_x, - const double principal_point_y, - const double k1, - const double k2, - const double image_x, - const double image_y, - double *normalized_x, - double *normalized_y); - -// Apply camera intrinsics to the normalized point to get image coordinates. -// This applies the radial lens distortion to a point which is in normalized -// camera coordinates (i.e. the principal point is at (0, 0)) to get image -// coordinates in pixels. Templated for use with autodifferentiation. -// -// Uses division distortion model. -template -inline void ApplyDivisionDistortionModel(const T &focal_length_x, - const T &focal_length_y, - const T &principal_point_x, - const T &principal_point_y, - const T &k1, - const T &k2, - const T &normalized_x, - const T &normalized_y, - T *image_x, - T *image_y) { - - T x = normalized_x; - T y = normalized_y; - T r2 = x*x + y*y; - T r4 = r2 * r2; - - T xd = x / (T(1) + k1 * r2 + k2 * r4); - T yd = y / (T(1) + k1 * r2 + k2 * r4); - - // Apply focal length and principal point to get the final image coordinates. - *image_x = focal_length_x * xd + principal_point_x; - *image_y = focal_length_y * yd + principal_point_y; -} - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_ diff --git a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc b/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc deleted file mode 100644 index 7a086c375d5..00000000000 --- a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/initialize_reconstruction.h" - -#include "libmv/base/vector.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/fundamental.h" -#include "libmv/multiview/projection.h" -#include "libmv/numeric/levenberg_marquardt.h" -#include "libmv/numeric/numeric.h" -#include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/simple_pipeline/tracks.h" - -namespace libmv { -namespace { - -void GetImagesInMarkers(const vector &markers, - int *image1, int *image2) { - if (markers.size() < 2) { - return; - } - *image1 = markers[0].image; - for (int i = 1; i < markers.size(); ++i) { - if (markers[i].image != *image1) { - *image2 = markers[i].image; - return; - } - } - *image2 = -1; - LOG(FATAL) << "Only one image in the markers."; -} - -} // namespace - -bool EuclideanReconstructTwoFrames(const vector &markers, - EuclideanReconstruction *reconstruction) { - if (markers.size() < 16) { - LG << "Not enough markers to initialize from two frames: " << markers.size(); - return false; - } - - int image1, image2; - GetImagesInMarkers(markers, &image1, &image2); - - Mat x1, x2; - CoordinatesForMarkersInImage(markers, image1, &x1); - CoordinatesForMarkersInImage(markers, image2, &x2); - - Mat3 F; - NormalizedEightPointSolver(x1, x2, &F); - - // The F matrix should be an E matrix, but squash it just to be sure. - Mat3 E; - FundamentalToEssential(F, &E); - - // Recover motion between the two images. Since this function assumes a - // calibrated camera, use the identity for K. - Mat3 R; - Vec3 t; - Mat3 K = Mat3::Identity(); - if (!MotionFromEssentialAndCorrespondence(E, - K, x1.col(0), - K, x2.col(0), - &R, &t)) { - LG << "Failed to compute R and t from E and K."; - return false; - } - - // Image 1 gets the reference frame, image 2 gets the relative motion. - reconstruction->InsertCamera(image1, Mat3::Identity(), Vec3::Zero()); - reconstruction->InsertCamera(image2, R, t); - - LG << "From two frame reconstruction got:\nR:\n" << R - << "\nt:" << t.transpose(); - return true; -} - -namespace { - -Mat3 DecodeF(const Vec9 &encoded_F) { - // Decode F and force it to be rank 2. - Map full_rank_F(encoded_F.data(), 3, 3); - Eigen::JacobiSVD svd(full_rank_F, - Eigen::ComputeFullU | Eigen::ComputeFullV); - Vec3 diagonal = svd.singularValues(); - diagonal(2) = 0; - Mat3 F = svd.matrixU() * diagonal.asDiagonal() * svd.matrixV().transpose(); - return F; -} - -// This is the stupidest way to refine F known to mankind, since it requires -// doing a full SVD of F at each iteration. This uses sampson error. -struct FundamentalSampsonCostFunction { - public: - typedef Vec FMatrixType; - typedef Vec9 XMatrixType; - - // Assumes markers are ordered by track. - explicit FundamentalSampsonCostFunction(const vector &markers) - : markers(markers) {} - - Vec operator()(const Vec9 &encoded_F) const { - // Decode F and force it to be rank 2. - Mat3 F = DecodeF(encoded_F); - - Vec residuals(markers.size() / 2); - residuals.setZero(); - for (int i = 0; i < markers.size() / 2; ++i) { - const Marker &marker1 = markers[2*i + 0]; - const Marker &marker2 = markers[2*i + 1]; - CHECK_EQ(marker1.track, marker2.track); - Vec2 x1(marker1.x, marker1.y); - Vec2 x2(marker2.x, marker2.y); - - residuals[i] = SampsonDistance(F, x1, x2); - } - return residuals; - } - const vector &markers; -}; - -} // namespace - -bool ProjectiveReconstructTwoFrames(const vector &markers, - ProjectiveReconstruction *reconstruction) { - if (markers.size() < 16) { - return false; - } - - int image1, image2; - GetImagesInMarkers(markers, &image1, &image2); - - Mat x1, x2; - CoordinatesForMarkersInImage(markers, image1, &x1); - CoordinatesForMarkersInImage(markers, image2, &x2); - - Mat3 F; - NormalizedEightPointSolver(x1, x2, &F); - - // XXX Verify sampson distance. -#if 0 - // Refine the resulting projection fundamental matrix using Sampson's - // approximation of geometric error. This avoids having to do a full bundle - // at the cost of some accuracy. - // - // TODO(keir): After switching to a better bundling library, use a proper - // full bundle adjust here instead of this lame bundle adjustment. - typedef LevenbergMarquardt Solver; - - FundamentalSampsonCostFunction fundamental_cost(markers); - - // Pack the initial P matrix into a size-12 vector.. - Vec9 encoded_F = Map(F.data(), 3, 3); - - Solver solver(fundamental_cost); - - Solver::SolverParameters params; - Solver::Results results = solver.minimize(params, &encoded_F); - // TODO(keir): Check results to ensure clean termination. - - // Recover F from the minimization. - F = DecodeF(encoded_F); -#endif - - // Image 1 gets P = [I|0], image 2 gets arbitrary P. - Mat34 P1 = Mat34::Zero(); - P1.block<3, 3>(0, 0) = Mat3::Identity(); - Mat34 P2; - ProjectionsFromFundamental(F, &P1, &P2); - - reconstruction->InsertCamera(image1, P1); - reconstruction->InsertCamera(image2, P2); - - LG << "From two frame reconstruction got P2:\n" << P2; - return true; -} -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h b/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h deleted file mode 100644 index 744436246b0..00000000000 --- a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H -#define LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H - -#include "libmv/base/vector.h" - -namespace libmv { - -struct Marker; -class EuclideanReconstruction; -class ProjectiveReconstruction; - -/*! - Initialize the \link EuclideanReconstruction reconstruction \endlink using - two frames. - - \a markers should contain all \l Marker markers \endlink belonging to - tracks visible in both frames. The pose estimation of the camera for - these frames will be inserted into \a *reconstruction. - - \note The two frames need to have both enough parallax and enough common tracks - for accurate reconstruction. At least 8 tracks are suggested. - \note The origin of the coordinate system is defined to be the camera of - the first keyframe. - \note This assumes a calibrated reconstruction, e.g. the markers are - already corrected for camera intrinsics and radial distortion. - \note This assumes an outlier-free set of markers. - - \sa EuclideanResect, EuclideanIntersect, EuclideanBundle -*/ -bool EuclideanReconstructTwoFrames(const vector &markers, - EuclideanReconstruction *reconstruction); - -/*! - Initialize the \link ProjectiveReconstruction reconstruction \endlink using - two frames. - - \a markers should contain all \l Marker markers \endlink belonging to - tracks visible in both frames. An estimate of the projection matrices for - the two frames will get added to the reconstruction. - - \note The two frames need to have both enough parallax and enough common tracks - for accurate reconstruction. At least 8 tracks are suggested. - \note The origin of the coordinate system is defined to be the camera of - the first keyframe. - \note This assumes the markers are already corrected for radial distortion. - \note This assumes an outlier-free set of markers. - - \sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle -*/ -bool ProjectiveReconstructTwoFrames(const vector &markers, - ProjectiveReconstruction *reconstruction); -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H diff --git a/extern/libmv/libmv/simple_pipeline/intersect.cc b/extern/libmv/libmv/simple_pipeline/intersect.cc deleted file mode 100644 index ddb713684a4..00000000000 --- a/extern/libmv/libmv/simple_pipeline/intersect.cc +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/intersect.h" - -#include "libmv/base/vector.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/projection.h" -#include "libmv/multiview/triangulation.h" -#include "libmv/multiview/nviewtriangulation.h" -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/levenberg_marquardt.h" -#include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/simple_pipeline/tracks.h" - -#include "ceres/ceres.h" - -namespace libmv { - -namespace { - -class EuclideanIntersectCostFunctor { - public: - EuclideanIntersectCostFunctor(const Marker &marker, - const EuclideanCamera &camera) - : marker_(marker), camera_(camera) {} - - template - bool operator()(const T *X, T *residuals) const { - typedef Eigen::Matrix Mat3; - typedef Eigen::Matrix Vec3; - - Vec3 x(X); - Mat3 R(camera_.R.cast()); - Vec3 t(camera_.t.cast()); - - Vec3 projected = R * x + t; - projected /= projected(2); - - residuals[0] = (projected(0) - T(marker_.x)) * marker_.weight; - residuals[1] = (projected(1) - T(marker_.y)) * marker_.weight; - - return true; - } - - const Marker &marker_; - const EuclideanCamera &camera_; -}; - -} // namespace - -bool EuclideanIntersect(const vector &markers, - EuclideanReconstruction *reconstruction) { - if (markers.size() < 2) { - return false; - } - - // Compute projective camera matrices for the cameras the intersection is - // going to use. - Mat3 K = Mat3::Identity(); - vector cameras; - Mat34 P; - for (int i = 0; i < markers.size(); ++i) { - EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image); - P_From_KRt(K, camera->R, camera->t, &P); - cameras.push_back(P); - } - - // Stack the 2D coordinates together as required by NViewTriangulate. - Mat2X points(2, markers.size()); - for (int i = 0; i < markers.size(); ++i) { - points(0, i) = markers[i].x; - points(1, i) = markers[i].y; - } - - Vec4 Xp; - LG << "Intersecting with " << markers.size() << " markers."; - NViewTriangulateAlgebraic(points, cameras, &Xp); - - // Get euclidean version of the homogeneous point. - Xp /= Xp(3); - Vec3 X = Xp.head<3>(); - - ceres::Problem problem; - - // Add residual blocks to the problem. - int num_residuals = 0; - for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; - if (marker.weight != 0.0) { - const EuclideanCamera &camera = - *reconstruction->CameraForImage(marker.image); - - problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - EuclideanIntersectCostFunctor, - 2, /* num_residuals */ - 3>(new EuclideanIntersectCostFunctor(marker, camera)), - NULL, - &X(0)); - num_residuals++; - } - } - - // TODO(sergey): Once we'll update Ceres to the next version - // we wouldn't need this check anymore -- Ceres will deal with - // zero-sized problems nicely. - LG << "Number of residuals: " << num_residuals; - if (!num_residuals) { - LG << "Skipping running minimizer with zero residuals"; - - // We still add 3D point for the track regardless it was - // optimized or not. If track is a constant zero it'll use - // algebraic intersection result as a 3D coordinate. - - Vec3 point = X.head<3>(); - reconstruction->InsertPoint(markers[0].track, point); - - return true; - } - - // 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(); - - // Try projecting the point; make sure it's in front of everyone. - for (int i = 0; i < cameras.size(); ++i) { - const EuclideanCamera &camera = - *reconstruction->CameraForImage(markers[i].image); - Vec3 x = camera.R * X + camera.t; - if (x(2) < 0) { - LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image - << ": " << x.transpose(); - return false; - } - } - - Vec3 point = X.head<3>(); - reconstruction->InsertPoint(markers[0].track, point); - - // TODO(keir): Add proper error checking. - return true; -} - -namespace { - -struct ProjectiveIntersectCostFunction { - public: - typedef Vec FMatrixType; - typedef Vec4 XMatrixType; - - ProjectiveIntersectCostFunction( - const vector &markers, - const ProjectiveReconstruction &reconstruction) - : markers(markers), reconstruction(reconstruction) {} - - Vec operator()(const Vec4 &X) const { - Vec residuals(2 * markers.size()); - residuals.setZero(); - for (int i = 0; i < markers.size(); ++i) { - const ProjectiveCamera &camera = - *reconstruction.CameraForImage(markers[i].image); - Vec3 projected = camera.P * X; - projected /= projected(2); - residuals[2*i + 0] = projected(0) - markers[i].x; - residuals[2*i + 1] = projected(1) - markers[i].y; - } - return residuals; - } - const vector &markers; - const ProjectiveReconstruction &reconstruction; -}; - -} // namespace - -bool ProjectiveIntersect(const vector &markers, - ProjectiveReconstruction *reconstruction) { - if (markers.size() < 2) { - return false; - } - - // Get the cameras to use for the intersection. - vector cameras; - for (int i = 0; i < markers.size(); ++i) { - ProjectiveCamera *camera = reconstruction->CameraForImage(markers[i].image); - cameras.push_back(camera->P); - } - - // Stack the 2D coordinates together as required by NViewTriangulate. - Mat2X points(2, markers.size()); - for (int i = 0; i < markers.size(); ++i) { - points(0, i) = markers[i].x; - points(1, i) = markers[i].y; - } - - Vec4 X; - LG << "Intersecting with " << markers.size() << " markers."; - NViewTriangulateAlgebraic(points, cameras, &X); - X /= X(3); - - typedef LevenbergMarquardt Solver; - - ProjectiveIntersectCostFunction triangulate_cost(markers, *reconstruction); - Solver::SolverParameters params; - Solver solver(triangulate_cost); - - Solver::Results results = solver.minimize(params, &X); - (void) results; // TODO(keir): Ensure results are good. - - // Try projecting the point; make sure it's in front of everyone. - for (int i = 0; i < cameras.size(); ++i) { - const ProjectiveCamera &camera = - *reconstruction->CameraForImage(markers[i].image); - Vec3 x = camera.P * X; - if (x(2) < 0) { - LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image - << ": " << x.transpose(); - } - } - - reconstruction->InsertPoint(markers[0].track, X); - - // TODO(keir): Add proper error checking. - return true; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/intersect.h b/extern/libmv/libmv/simple_pipeline/intersect.h deleted file mode 100644 index 3a0ffa7418b..00000000000 --- a/extern/libmv/libmv/simple_pipeline/intersect.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_INTERSECT_H -#define LIBMV_SIMPLE_PIPELINE_INTERSECT_H - -#include "libmv/base/vector.h" -#include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/reconstruction.h" - -namespace libmv { - -/*! - Estimate the 3D coordinates of a track by intersecting rays from images. - - This takes a set of markers, where each marker is for the same track but - different images, and reconstructs the 3D position of that track. Each of - the frames for which there is a marker for that track must have a - corresponding reconstructed camera in \a *reconstruction. - - \a markers should contain all \l Marker markers \endlink belonging to - tracks visible in all frames. - \a reconstruction should contain the cameras for all frames. - The new \l Point points \endlink will be inserted in \a reconstruction. - - \note This assumes a calibrated reconstruction, e.g. the markers are - already corrected for camera intrinsics and radial distortion. - \note This assumes an outlier-free set of markers. - - \sa EuclideanResect -*/ -bool EuclideanIntersect(const vector &markers, - EuclideanReconstruction *reconstruction); - -/*! - Estimate the homogeneous coordinates of a track by intersecting rays. - - This takes a set of markers, where each marker is for the same track but - different images, and reconstructs the homogeneous 3D position of that - track. Each of the frames for which there is a marker for that track must - have a corresponding reconstructed camera in \a *reconstruction. - - \a markers should contain all \l Marker markers \endlink belonging to - tracks visible in all frames. - \a reconstruction should contain the cameras for all frames. - The new \l Point points \endlink will be inserted in \a reconstruction. - - \note This assumes that radial distortion is already corrected for, but - does not assume that e.g. focal length and principal point are - accounted for. - \note This assumes an outlier-free set of markers. - - \sa Resect -*/ -bool ProjectiveIntersect(const vector &markers, - ProjectiveReconstruction *reconstruction); - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_INTERSECT_H diff --git a/extern/libmv/libmv/simple_pipeline/intersect_test.cc b/extern/libmv/libmv/simple_pipeline/intersect_test.cc deleted file mode 100644 index dd4fdc789af..00000000000 --- a/extern/libmv/libmv/simple_pipeline/intersect_test.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2007, 2008 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/intersect.h" - -#include - -#include "testing/testing.h" -#include "libmv/multiview/projection.h" -#include "libmv/numeric/numeric.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -TEST(Intersect, EuclideanIntersect) { - Mat3 K1 = Mat3::Identity(); - // K1 << 320, 0, 160, - // 0, 320, 120, - // 0, 0, 1; - Mat3 K2 = Mat3::Identity(); - // K2 << 360, 0, 170, - // 0, 360, 110, - // 0, 0, 1; - Mat3 R1 = RotationAroundZ(-0.1); - Mat3 R2 = RotationAroundX(-0.1); - Vec3 t1; t1 << 1, 1, 10; - Vec3 t2; t2 << -2, -1, 10; - Mat34 P1, P2; - P_From_KRt(K1, R1, t1, &P1); - P_From_KRt(K2, R2, t2, &P2); - - //Mat3 F; FundamentalFromProjections(P1, P2, &F); - - Mat3X X; - X.resize(3, 30); - X.setRandom(); - - Mat2X X1, X2; - Project(P1, X, &X1); - Project(P2, X, &X2); - - for (int i = 0; i < X.cols(); ++i) { - Vec2 x1, x2; - MatrixColumn(X1, i, &x1); - MatrixColumn(X2, i, &x2); - Vec3 expected; - MatrixColumn(X, i, &expected); - - EuclideanReconstruction reconstruction; - reconstruction.InsertCamera(1, R1, t1); - reconstruction.InsertCamera(2, R2, t2); - - vector markers; - Marker a = { 1, 0, x1.x(), x1.y(), 1.0 }; - markers.push_back(a); - Marker b = { 2, 0, x2.x(), x2.y(), 1.0 }; - markers.push_back(b); - - EuclideanIntersect(markers, &reconstruction); - Vec3 estimated = reconstruction.PointForTrack(0)->X; - EXPECT_NEAR(0, DistanceLInfinity(estimated, expected), 1e-8); - } -} -} // namespace diff --git a/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc b/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc deleted file mode 100644 index 241b5600505..00000000000 --- a/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright (c) 2012 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/keyframe_selection.h" - -#include "libmv/numeric/numeric.h" -#include "ceres/ceres.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/homography.h" -#include "libmv/multiview/fundamental.h" -#include "libmv/simple_pipeline/intersect.h" -#include "libmv/simple_pipeline/bundle.h" - -#include - -namespace libmv { -namespace { - -Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics &intrinsics) { - Mat3 T = Mat3::Identity(), S = Mat3::Identity(); - - T(0, 2) = -intrinsics.principal_point_x(); - T(1, 2) = -intrinsics.principal_point_y(); - - S(0, 0) /= intrinsics.focal_length_x(); - S(1, 1) /= intrinsics.focal_length_y(); - - return S * T; -} - -// P.H.S. Torr -// Geometric Motion Segmentation and Model Selection -// -// http://reference.kfupm.edu.sa/content/g/e/geometric_motion_segmentation_and_model__126445.pdf -// -// d is the number of dimensions modeled -// (d = 3 for a fundamental matrix or 2 for a homography) -// k is the number of degrees of freedom in the model -// (k = 7 for a fundamental matrix or 8 for a homography) -// r is the dimension of the data -// (r = 4 for 2D correspondences between two frames) -double GRIC(const Vec &e, int d, int k, int r) { - int n = e.rows(); - double lambda1 = log(static_cast(r)); - double lambda2 = log(static_cast(r * n)); - - // lambda3 limits the residual error, and this paper - // http://elvera.nue.tu-berlin.de/files/0990Knorr2006.pdf - // suggests using lambda3 of 2 - // same value is used in Torr's Problem of degeneracy in structure - // and motion recovery from uncalibrated image sequences - // http://www.robots.ox.ac.uk/~vgg/publications/papers/torr99.ps.gz - double lambda3 = 2.0; - - // Variance of tracker position. Physically, this is typically about 0.1px, - // and when squared becomes 0.01 px^2. - double sigma2 = 0.01; - - // Finally, calculate the GRIC score. - double gric = 0.0; - for (int i = 0; i < n; i++) { - gric += std::min(e(i) * e(i) / sigma2, lambda3 * (r - d)); - } - gric += lambda1 * d * n; - gric += lambda2 * k; - return gric; -} - -// Compute a generalized inverse using eigen value decomposition, clamping the -// smallest eigenvalues if requested. This is needed to compute the variance of -// reconstructed 3D points. -// -// TODO(keir): Consider moving this into the numeric code, since this is not -// related to keyframe selection. -Mat PseudoInverseWithClampedEigenvalues(const Mat &matrix, - int num_eigenvalues_to_clamp) { - Eigen::EigenSolver eigen_solver(matrix); - Mat D = eigen_solver.pseudoEigenvalueMatrix(); - Mat V = eigen_solver.pseudoEigenvectors(); - - // Clamp too-small singular values to zero to prevent numeric blowup. - double epsilon = std::numeric_limits::epsilon(); - for (int i = 0; i < D.cols(); ++i) { - if (D(i, i) > epsilon) { - D(i, i) = 1.0 / D(i, i); - } else { - D(i, i) = 0.0; - } - } - - // Apply the clamp. - for (int i = D.cols() - num_eigenvalues_to_clamp; i < D.cols(); ++i) { - D(i, i) = 0.0; - } - return V * D * V.inverse(); -} - -void FilterZeroWeightMarkersFromTracks(const Tracks &tracks, - Tracks *filtered_tracks) { - vector all_markers = tracks.AllMarkers(); - - for (int i = 0; i < all_markers.size(); ++i) { - Marker &marker = all_markers[i]; - if (marker.weight != 0.0) { - filtered_tracks->Insert(marker.image, - marker.track, - marker.x, - marker.y, - marker.weight); - } - } -} - -} // namespace - -void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, - const CameraIntrinsics &intrinsics, - vector &keyframes) { - // Mirza Tahir Ahmed, Matthew N. Dailey - // Robust key frame extraction for 3D reconstruction from video streams - // - // http://www.cs.ait.ac.th/~mdailey/papers/Tahir-KeyFrame.pdf - - Tracks filtered_tracks; - FilterZeroWeightMarkersFromTracks(_tracks, &filtered_tracks); - - int max_image = filtered_tracks.MaxImage(); - int next_keyframe = 1; - int number_keyframes = 0; - - // Limit correspondence ratio from both sides. - // On the one hand if number of correspondent features is too low, - // triangulation will suffer. - // On the other hand high correspondence likely means short baseline. - // which also will affect om accuracy - const double Tmin = 0.8; - const double Tmax = 1.0; - - Mat3 N = IntrinsicsNormalizationMatrix(intrinsics); - Mat3 N_inverse = N.inverse(); - - double Sc_best = std::numeric_limits::max(); - double success_intersects_factor_best = 0.0f; - - while (next_keyframe != -1) { - int current_keyframe = next_keyframe; - double Sc_best_candidate = std::numeric_limits::max(); - - LG << "Found keyframe " << next_keyframe; - - number_keyframes++; - next_keyframe = -1; - - for (int candidate_image = current_keyframe + 1; - candidate_image <= max_image; - candidate_image++) { - // Conjunction of all markers from both keyframes - vector all_markers = - filtered_tracks.MarkersInBothImages(current_keyframe, - candidate_image); - - // Match keypoints between frames current_keyframe and candidate_image - vector tracked_markers = - filtered_tracks.MarkersForTracksInBothImages(current_keyframe, - candidate_image); - - // Correspondences in normalized space - Mat x1, x2; - CoordinatesForMarkersInImage(tracked_markers, current_keyframe, &x1); - CoordinatesForMarkersInImage(tracked_markers, candidate_image, &x2); - - LG << "Found " << x1.cols() - << " correspondences between " << current_keyframe - << " and " << candidate_image; - - // Not enough points to construct fundamental matrix - if (x1.cols() < 8 || x2.cols() < 8) - continue; - - // STEP 1: Correspondence ratio constraint - int Tc = tracked_markers.size(); - int Tf = all_markers.size(); - double Rc = static_cast(Tc) / Tf; - - LG << "Correspondence between " << current_keyframe - << " and " << candidate_image - << ": " << Rc; - - if (Rc < Tmin || Rc > Tmax) - continue; - - Mat3 H, F; - - // Estimate homography using default options. - EstimateHomographyOptions estimate_homography_options; - EstimateHomography2DFromCorrespondences(x1, - x2, - estimate_homography_options, - &H); - - // Convert homography to original pixel space. - H = N_inverse * H * N; - - EstimateFundamentalOptions estimate_fundamental_options; - EstimateFundamentalFromCorrespondences(x1, - x2, - estimate_fundamental_options, - &F); - - // Convert fundamental to original pixel space. - F = N_inverse * F * N; - - // TODO(sergey): STEP 2: Discard outlier matches - - // STEP 3: Geometric Robust Information Criteria - - // Compute error values for homography and fundamental matrices - Vec H_e, F_e; - H_e.resize(x1.cols()); - F_e.resize(x1.cols()); - for (int i = 0; i < x1.cols(); i++) { - Vec2 current_x1, current_x2; - - intrinsics.NormalizedToImageSpace(x1(0, i), x1(1, i), - ¤t_x1(0), ¤t_x1(1)); - - intrinsics.NormalizedToImageSpace(x2(0, i), x2(1, i), - ¤t_x2(0), ¤t_x2(1)); - - H_e(i) = SymmetricGeometricDistance(H, current_x1, current_x2); - F_e(i) = SymmetricEpipolarDistance(F, current_x1, current_x2); - } - - LG << "H_e: " << H_e.transpose(); - LG << "F_e: " << F_e.transpose(); - - // Degeneracy constraint - double GRIC_H = GRIC(H_e, 2, 8, 4); - double GRIC_F = GRIC(F_e, 3, 7, 4); - - LG << "GRIC values for frames " << current_keyframe - << " and " << candidate_image - << ", H-GRIC: " << GRIC_H - << ", F-GRIC: " << GRIC_F; - - if (GRIC_H <= GRIC_F) - continue; - - // TODO(sergey): STEP 4: PELC criterion - - // STEP 5: Estimation of reconstruction error - // - // Uses paper Keyframe Selection for Camera Motion and Structure - // Estimation from Multiple Views - // Uses ftp://ftp.tnt.uni-hannover.de/pub/papers/2004/ECCV2004-TTHBAW.pdf - // Basically, equation (15) - // - // TODO(sergey): separate all the constraints into functions, - // this one is getting to much cluttered already - - // Definitions in equation (15): - // - I is the number of 3D feature points - // - A is the number of essential parameters of one camera - - EuclideanReconstruction reconstruction; - - // The F matrix should be an E matrix, but squash it just to be sure - - // Reconstruction should happen using normalized fundamental matrix - Mat3 F_normal = N * F * N_inverse; - - Mat3 E; - FundamentalToEssential(F_normal, &E); - - // Recover motion between the two images. Since this function assumes a - // calibrated camera, use the identity for K - Mat3 R; - Vec3 t; - Mat3 K = Mat3::Identity(); - - if (!MotionFromEssentialAndCorrespondence(E, - K, x1.col(0), - K, x2.col(0), - &R, &t)) { - LG << "Failed to compute R and t from E and K"; - continue; - } - - LG << "Camera transform between frames " << current_keyframe - << " and " << candidate_image - << ":\nR:\n" << R - << "\nt:" << t.transpose(); - - // First camera is identity, second one is relative to it - reconstruction.InsertCamera(current_keyframe, - Mat3::Identity(), - Vec3::Zero()); - reconstruction.InsertCamera(candidate_image, R, t); - - // Reconstruct 3D points - int intersects_total = 0, intersects_success = 0; - for (int i = 0; i < tracked_markers.size(); i++) { - if (!reconstruction.PointForTrack(tracked_markers[i].track)) { - vector reconstructed_markers; - - int track = tracked_markers[i].track; - - reconstructed_markers.push_back(tracked_markers[i]); - - // We know there're always only two markers for a track - // Also, we're using brute-force search because we don't - // actually know about markers layout in a list, but - // at this moment this cycle will run just once, which - // is not so big deal - - for (int j = i + 1; j < tracked_markers.size(); j++) { - if (tracked_markers[j].track == track) { - reconstructed_markers.push_back(tracked_markers[j]); - break; - } - } - - intersects_total++; - - if (EuclideanIntersect(reconstructed_markers, &reconstruction)) { - LG << "Ran Intersect() for track " << track; - intersects_success++; - } else { - LG << "Filed to intersect track " << track; - } - } - } - - double success_intersects_factor = - (double) intersects_success / intersects_total; - - if (success_intersects_factor < success_intersects_factor_best) { - LG << "Skip keyframe candidate because of " - "lower successful intersections ratio"; - - continue; - } - - success_intersects_factor_best = success_intersects_factor; - - Tracks two_frames_tracks(tracked_markers); - PolynomialCameraIntrinsics empty_intrinsics; - BundleEvaluation evaluation; - evaluation.evaluate_jacobian = true; - - EuclideanBundleCommonIntrinsics(two_frames_tracks, - BUNDLE_NO_INTRINSICS, - BUNDLE_NO_CONSTRAINTS, - &reconstruction, - &empty_intrinsics, - &evaluation); - - Mat &jacobian = evaluation.jacobian; - - Mat JT_J = jacobian.transpose() * jacobian; - // There are 7 degrees of freedom, so clamp them out. - Mat JT_J_inv = PseudoInverseWithClampedEigenvalues(JT_J, 7); - - Mat temp_derived = JT_J * JT_J_inv * JT_J; - bool is_inversed = (temp_derived - JT_J).cwiseAbs2().sum() < - 1e-4 * std::min(temp_derived.cwiseAbs2().sum(), - JT_J.cwiseAbs2().sum()); - - LG << "Check on inversed: " << (is_inversed ? "true" : "false" ) - << ", det(JT_J): " << JT_J.determinant(); - - if (!is_inversed) { - LG << "Ignoring candidature due to poor jacobian stability"; - continue; - } - - Mat Sigma_P; - Sigma_P = JT_J_inv.bottomRightCorner(evaluation.num_points * 3, - evaluation.num_points * 3); - - int I = evaluation.num_points; - int A = 12; - - double Sc = static_cast(I + A) / Square(3 * I) * Sigma_P.trace(); - - LG << "Expected estimation error between " - << current_keyframe << " and " - << candidate_image << ": " << Sc; - - // Pairing with a lower Sc indicates a better choice - if (Sc > Sc_best_candidate) - continue; - - Sc_best_candidate = Sc; - - next_keyframe = candidate_image; - } - - // This is a bit arbitrary and main reason of having this is to deal - // better with situations when there's no keyframes were found for - // current keyframe this could happen when there's no so much parallax - // in the beginning of image sequence and then most of features are - // getting occluded. In this case there could be good keyframe pair in - // the middle of the sequence - // - // However, it's just quick hack and smarter way to do this would be nice - if (next_keyframe == -1) { - next_keyframe = current_keyframe + 10; - number_keyframes = 0; - - if (next_keyframe >= max_image) - break; - - LG << "Starting searching for keyframes starting from " << next_keyframe; - } else { - // New pair's expected reconstruction error is lower - // than existing pair's one. - // - // For now let's store just one candidate, easy to - // store more candidates but needs some thoughts - // how to choose best one automatically from them - // (or allow user to choose pair manually). - if (Sc_best > Sc_best_candidate) { - keyframes.clear(); - keyframes.push_back(current_keyframe); - keyframes.push_back(next_keyframe); - Sc_best = Sc_best_candidate; - } - } - } -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/keyframe_selection.h b/extern/libmv/libmv/simple_pipeline/keyframe_selection.h deleted file mode 100644 index aa3eeaf193d..00000000000 --- a/extern/libmv/libmv/simple_pipeline/keyframe_selection.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2010, 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_ -#define LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_ - -#include "libmv/base/vector.h" -#include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" - -namespace libmv { - -// Get list of all images which are good enough to be as keyframes from -// camera reconstruction. Based on GRIC criteria and uses Pollefeys' -// approach for correspondence ratio constraint. -// -// As an additional, additional criteria based on reconstruction -// variance is used. This means if correspondence and GRIC criteria -// are passed, two-frames reconstruction using candidate keyframes -// happens. After reconstruction variance of 3D points is calculating -// and if expected error estimation is too large, keyframe candidate -// is rejecting. -// -// \param tracks contains all tracked correspondences between frames -// expected to be undistorted and normalized -// \param intrinsics is camera intrinsics -// \param keyframes will contain all images number which are considered -// good to be used for reconstruction -void SelectKeyframesBasedOnGRICAndVariance( - const Tracks &tracks, - const CameraIntrinsics &intrinsics, - vector &keyframes); - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_ diff --git a/extern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc b/extern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc deleted file mode 100644 index 9d88362cc88..00000000000 --- a/extern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/keyframe_selection.h" - -#include "testing/testing.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -// Synthetic test, N markers with the same translation -// Should not be keyframe -TEST(KeyframeSelection, SyntheticNeighborFrame) { - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(900.0,900.0); - intrinsics.SetPrincipalPoint(640.0, 540.0); - intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); - - Tracks tracks; - const int markers_per_size = 15; - - // Fill in tracks for homography estimation - for (int x = 0; x < markers_per_size; x++) { - for (int y = 0; y < markers_per_size; y++) { - double current_x = 10 + x * 40, current_y = 10 + y * 40; - double next_x = current_x + 10, next_y = current_y + 10; - - intrinsics.InvertIntrinsics(current_x, current_y, ¤t_x, ¤t_y); - intrinsics.InvertIntrinsics(next_x, next_y, &next_x, &next_y); - - tracks.Insert(1, y * markers_per_size + x, current_x, current_y); - tracks.Insert(2, y * markers_per_size + x, next_x, next_y); - } - } - - vector keyframes; - SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes); - - // Synthetic second frame shouldn't be considered a keyframe - EXPECT_EQ(0, keyframes.size()); -} - -// Frames 1 and 2 of FabrikEingang footage -// Only one wall is tracked, should not be keyframes -TEST(KeyframeSelection, FabrikEingangNeighborFrames) { - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(1605.797, 1605.797); - intrinsics.SetPrincipalPoint(960.000, 544.000); - intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); - - Marker markers[] = { - {1, 0, 737.599983, 646.397594, 1.0}, {2, 0, 737.906628, 648.113327, 1.0}, {1, 1, 863.045425, 646.081905, 1.0}, - {2, 1, 863.339767, 647.650040, 1.0}, {1, 2, 736.959972, 574.080151, 1.0}, {2, 2, 737.217350, 575.604900, 1.0}, - {1, 3, 864.097424, 573.374908, 1.0}, {2, 3, 864.383469, 574.900307, 1.0}, {1, 4, 789.429073, 631.677521, 1.0}, - {2, 4, 789.893131, 633.124451, 1.0}, {1, 5, 791.051960, 573.442028, 1.0}, {2, 5, 791.336575, 575.088890, 1.0}, - {1, 6, 738.973961, 485.130308, 1.0}, {2, 6, 739.435501, 486.734207, 1.0}, {1, 7, 862.403240, 514.866074, 1.0}, - {2, 7, 862.660618, 516.413261, 1.0}, {1, 8, 802.240162, 485.759838, 1.0}, {2, 8, 802.602253, 487.432899, 1.0}, - {1, 9, 754.340630, 500.624559, 1.0}, {2, 9, 754.559956, 502.079920, 1.0}, {1, 10, 849.398689, 484.480545, 1.0}, - {2, 10, 849.599934, 486.079937, 1.0}, {1, 11, 788.803768, 515.924391, 1.0}, {2, 11, 789.119911, 517.439932, 1.0}, - {1, 12, 838.733940, 558.212688, 1.0}, {2, 12, 839.039898, 559.679916, 1.0}, {1, 13, 760.014782, 575.194466, 1.0}, - {2, 13, 760.319881, 576.639904, 1.0}, {1, 14, 765.321636, 616.015957, 1.0}, {2, 14, 765.759945, 617.599915, 1.0}, - {1, 15, 800.963230, 660.032082, 1.0}, {2, 15, 801.279945, 661.759876, 1.0}, {1, 16, 846.321087, 602.313053, 1.0}, - {2, 16, 846.719913, 603.839878, 1.0}, {1, 17, 864.288311, 616.790524, 1.0}, {2, 17, 864.639931, 618.239918, 1.0}, - {1, 18, 800.006790, 602.573425, 1.0}, {2, 18, 800.319958, 604.159912, 1.0}, {1, 19, 739.026890, 617.944138, 1.0}, - {2, 19, 739.199924, 619.519924, 1.0}, {1, 20, 801.987419, 544.134888, 1.0}, {2, 20, 802.239933, 545.599911, 1.0}, - {1, 21, 753.619823, 542.961300, 1.0}, {2, 21, 753.919945, 544.639874, 1.0}, {1, 22, 787.921257, 499.910206, 1.0}, - {2, 22, 788.159924, 501.439917, 1.0}, {1, 23, 839.095459, 529.287903, 1.0}, {2, 23, 839.359932, 530.879934, 1.0}, - {1, 24, 811.760330, 630.732269, 1.0}, {2, 24, 812.159901, 632.319859, 1.0} - }; - int num_markers = sizeof(markers) / sizeof(Marker); - - Tracks tracks; - for (int i = 0; i < num_markers; i++) { - double x = markers[i].x, y = markers[i].y; - intrinsics.InvertIntrinsics(x, y, &x, &y); - tracks.Insert(markers[i].image, markers[i].track, x, y); - } - - vector keyframes; - SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes); - - EXPECT_EQ(0, keyframes.size()); -} - -// Frames 120 and 200 from FabrikEingang footage -// Should be enough of parallax for keyframing -TEST(KeyframeSelection, FabrikEingangFarFrames) { - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(1605.797, 1605.797); - intrinsics.SetPrincipalPoint(960.000, 544.000); - intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); - - Marker markers[] = { - {1, 0, 369.459200, 619.315258, 1.0}, {2, 0, 279.677496, 722.086842, 1.0}, {1, 1, 376.831970, 370.278397, 1.0}, - {2, 1, 221.695247, 460.065418, 1.0}, {1, 2, 1209.139023, 567.705605, 1.0}, {2, 2, 1080.760117, 659.230083, 1.0}, - {1, 3, 1643.495750, 903.620453, 1.0}, {2, 3, 1618.405037, 1015.374908, 1.0}, {1, 4, 1494.849815, 425.302460, 1.0}, - {2, 4, 1457.467575, 514.727587, 1.0}, {1, 5, 1794.637299, 328.728609, 1.0}, {2, 5, 1742.161446, 408.988636, 1.0}, - {1, 6, 1672.822723, 102.240358, 1.0}, {2, 6, 1539.287224, 153.536892, 1.0}, {1, 7, 1550.843925, 53.424943, 1.0}, - {2, 7, 1385.579109, 96.450085, 1.0}, {1, 8, 852.953281, 465.399578, 1.0}, {2, 8, 779.404564, 560.091843, 1.0}, - {1, 9, 906.853752, 299.827040, 1.0}, {2, 9, 786.923218, 385.570770, 1.0}, {1, 10, 406.322966, 87.556041, 1.0}, - {2, 10, 140.339413, 150.877481, 1.0}, {1, 11, 254.811573, 851.296478, 1.0}, {2, 11, 94.478302, 969.350189, 1.0}, - {1, 12, 729.087868, 806.092758, 1.0}, {2, 12, 606.212139, 919.876560, 1.0}, {1, 13, 1525.719452, 920.398083, 1.0}, - {2, 13, 1495.579720, 1031.971218, 1.0} - }; - int num_markers = sizeof(markers) / sizeof(Marker); - - Tracks tracks; - for (int i = 0; i < num_markers; i++) { - double x = markers[i].x, y = markers[i].y; - intrinsics.InvertIntrinsics(x, y, &x, &y); - tracks.Insert(markers[i].image, markers[i].track, x, y); - } - - vector keyframes; - SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes); - - EXPECT_EQ(2, keyframes.size()); -} - -// Manually selected keyframes from copter footage from Sebastian -// Keyframes were 167 and 237 -TEST(KeyframeSelection, CopterManualKeyFrames) { - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(1155.043, 1155.043); - intrinsics.SetPrincipalPoint(640.000, 360.000); - intrinsics.SetRadialDistortion(-0.08590, 0.0, 0.0); - - Marker markers[] = { - {1, 0, 645.792694, 403.115931, 1.0}, {2, 0, 630.641174, 307.996409, 1.0}, {1, 1, 783.469086, 403.904328, 1.0}, - {2, 1, 766.001129, 308.998225, 1.0}, {1, 2, 650.000000, 160.000001, 1.0}, {1, 3, 785.225906, 158.619039, 1.0}, - {2, 3, 767.526474, 70.449695, 1.0}, {1, 4, 290.640526, 382.335634, 1.0}, {2, 4, 273.001728, 86.993319, 1.0}, - {1, 5, 291.162739, 410.602684, 1.0}, {2, 5, 273.287849, 111.937487, 1.0}, {1, 6, 136.919317, 349.895797, 1.0}, - {1, 7, 490.844345, 47.572222, 1.0}, {1, 8, 454.406433, 488.935761, 1.0}, {1, 9, 378.655815, 618.522248, 1.0}, - {2, 9, 357.061806, 372.265077, 1.0}, {1, 10, 496.011391, 372.668824, 1.0}, {2, 10, 477.979164, 222.986112, 1.0}, - {1, 11, 680.060272, 256.103625, 1.0}, {2, 11, 670.587540, 204.830453, 1.0}, {1, 12, 1070.817108, 218.775322, 1.0}, - {2, 12, 1046.129913, 128.969783, 1.0}, {1, 14, 242.516403, 596.048512, 1.0}, {2, 14, 224.182606, 248.272154, 1.0}, - {1, 15, 613.936272, 287.519073, 1.0}, {2, 15, 600.467644, 196.085722, 1.0}, {1, 31, 844.637451, 256.354315, 1.0}, - {2, 31, 823.200150, 165.714952, 1.0}, - }; - int num_markers = sizeof(markers) / sizeof(Marker); - - Tracks tracks; - for (int i = 0; i < num_markers; i++) { - double x = markers[i].x, y = markers[i].y; - intrinsics.InvertIntrinsics(x, y, &x, &y); - tracks.Insert(markers[i].image, markers[i].track, x, y); - } - - vector keyframes; - SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes); - - EXPECT_EQ(2, keyframes.size()); -} - -// Used old friend elevator scene MMI_2366 with automatic feature selection -// and manual outlier elimination and manual keyframe selection -// Selected keyframes were 29 and 41 -TEST(KeyframeSelection, ElevatorManualKeyframesFrames) { - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(1380.000, 1380.000); - intrinsics.SetPrincipalPoint(960.000, 540.000); - intrinsics.SetRadialDistortion(-0.034, 0.0, 0.0); - - Marker markers[] = { - {1, 2, 1139.861412, 1034.634984, 1.0}, {2, 2, 1143.512192, 1065.355718, 1.0}, {1, 3, 1760.821953, 644.658036, 1.0}, - {2, 3, 1770.901108, 697.899928, 1.0}, {1, 4, 858.071823, 1068.520746, 1.0}, {1, 6, 1633.952408, 797.050145, 1.0}, - {2, 6, 1642.508469, 849.157140, 1.0}, {1, 8, 1716.695824, 451.805491, 1.0}, {2, 8, 1726.513939, 502.095687, 1.0}, - {1, 9, 269.577627, 724.986935, 1.0}, {2, 9, 269.424820, 764.154246, 1.0}, {1, 10, 1891.321907, 706.948843, 1.0}, - {2, 10, 1903.338547, 766.068377, 1.0}, {1, 12, 1806.227074, 956.089604, 1.0}, {2, 12, 1816.619568, 1013.767376, 1.0}, - {1, 14, 269.544153, 1002.333570, 1.0}, {2, 14, 269.367542, 1043.509254, 1.0}, {1, 15, 1402.772141, 281.392962, 1.0}, - {2, 15, 1409.089165, 318.731629, 1.0}, {1, 16, 195.877233, 919.454341, 1.0}, {2, 16, 192.531109, 997.367899, 1.0}, - {1, 17, 1789.584045, 120.036661, 1.0}, {2, 17, 1800.391846, 167.822964, 1.0}, {1, 18, 999.363213, 765.004807, 1.0}, - {2, 18, 1002.345772, 790.560122, 1.0}, {1, 19, 647.342491, 1044.805727, 1.0}, {2, 19, 649.328041, 1058.682940, 1.0}, - {1, 20, 1365.486832, 440.901829, 1.0}, {2, 20, 1371.413040, 477.888730, 1.0}, {1, 21, 1787.125282, 301.431606, 1.0}, - {2, 21, 1798.527260, 355.224531, 1.0}, {1, 22, 1257.805824, 932.797258, 1.0}, {2, 22, 1263.017578, 969.376774, 1.0}, - {1, 23, 961.969528, 843.148112, 1.0}, {2, 23, 964.869461, 868.587620, 1.0}, {1, 24, 158.076110, 1052.643592, 1.0}, - {1, 25, 1072.884521, 1005.296981, 1.0}, {2, 25, 1076.091156, 1032.776856, 1.0}, {1, 26, 1107.656937, 526.577228, 1.0}, - {2, 26, 1111.618423, 555.524454, 1.0}, {1, 27, 1416.410751, 529.857581, 1.0}, {2, 27, 1422.663574, 570.025957, 1.0}, - {1, 28, 1498.673630, 1005.453086, 1.0}, {2, 28, 1505.381813, 1051.827149, 1.0}, {1, 29, 1428.647804, 652.473629, 1.0}, - {2, 29, 1434.898224, 692.715390, 1.0}, {1, 30, 1332.318764, 503.673599, 1.0}, {2, 30, 1338.000069, 540.507967, 1.0}, - {1, 32, 1358.642693, 709.837904, 1.0}, {2, 32, 1364.231529, 748.678265, 1.0}, {1, 33, 1850.911560, 460.475668, 1.0}, - {2, 33, 1862.221413, 512.797347, 1.0}, {1, 34, 1226.117821, 607.053959, 1.0}, {2, 34, 1230.736084, 641.091449, 1.0}, - {1, 35, 619.598236, 523.341744, 1.0}, {2, 35, 621.601124, 554.453287, 1.0}, {1, 36, 956.591492, 958.223183, 1.0}, - {2, 36, 959.289265, 983.289263, 1.0}, {1, 37, 1249.922218, 419.095856, 1.0}, {2, 37, 1255.005913, 452.556177, 1.0}, - {1, 39, 1300.528450, 386.251166, 1.0}, {2, 39, 1305.957413, 420.185595, 1.0}, {1, 40, 1128.689919, 972.558346, 1.0}, - {2, 40, 1132.413712, 1003.984737, 1.0}, {1, 41, 503.304749, 1053.504388, 1.0}, {2, 41, 505.019703, 1069.175613, 1.0}, - {1, 42, 1197.352982, 472.681564, 1.0}, {2, 42, 1201.910706, 503.459880, 1.0}, {1, 43, 1794.391022, 383.911400, 1.0}, - {2, 43, 1805.324135, 436.116468, 1.0}, {1, 44, 789.641418, 1058.045647, 1.0}, {1, 45, 1376.575241, 928.714979, 1.0}, - {2, 45, 1381.995850, 969.511957, 1.0}, {1, 46, 1598.023567, 93.975592, 1.0}, {2, 46, 1606.937141, 136.827035, 1.0}, - {1, 47, 1455.550232, 762.128685, 1.0}, {2, 47, 1462.014313, 805.164878, 1.0}, {1, 48, 1357.123489, 354.460326, 1.0}, - {2, 48, 1363.071899, 390.363121, 1.0}, {1, 49, 939.792652, 781.549895, 1.0}, {2, 49, 942.802620, 806.164012, 1.0}, - {1, 50, 1380.251083, 805.948620, 1.0}, {2, 50, 1385.637932, 845.592098, 1.0}, {1, 51, 1021.769943, 1049.802361, 1.0}, - {1, 52, 1065.634918, 608.099055, 1.0}, {2, 52, 1069.142189, 635.361736, 1.0}, {1, 53, 624.324188, 463.202863, 1.0}, - {2, 53, 626.395454, 494.994088, 1.0}, {1, 54, 1451.459885, 881.557624, 1.0}, {2, 54, 1457.679634, 924.345531, 1.0}, - {1, 55, 1201.885986, 1057.079022, 1.0}, {1, 56, 581.157532, 947.661438, 1.0}, {2, 56, 583.242359, 960.831449, 1.0}, - {1, 58, 513.593102, 954.175858, 1.0}, {2, 58, 515.470047, 971.309574, 1.0}, {1, 59, 928.069038, 901.774421, 1.0}, - {2, 59, 930.847950, 925.613744, 1.0}, {1, 60, 1065.860023, 740.395389, 1.0}, {2, 60, 1069.484253, 768.971086, 1.0}, - {1, 61, 990.479393, 906.264632, 1.0}, {2, 61, 993.217506, 933.088803, 1.0}, {1, 62, 1776.196747, 776.278453, 1.0}, - {2, 62, 1786.292496, 831.136880, 1.0}, {1, 63, 834.454365, 1012.449725, 1.0}, {2, 63, 836.868324, 1033.451807, 1.0}, - {1, 64, 1355.190697, 869.184809, 1.0}, {2, 64, 1360.736618, 909.773347, 1.0}, {1, 65, 702.072487, 897.519686, 1.0}, - {2, 65, 704.203377, 911.931131, 1.0}, {1, 66, 1214.022903, 856.199934, 1.0}, {2, 66, 1218.109016, 890.753052, 1.0}, - {1, 67, 327.676048, 236.814036, 1.0}, {2, 67, 328.335285, 277.251878, 1.0}, {1, 68, 289.064083, 454.793912, 1.0}, - {2, 68, 288.651924, 498.882444, 1.0}, {1, 69, 1626.240692, 278.374350, 1.0}, {2, 69, 1634.131508, 315.853672, 1.0}, - {1, 70, 1245.375710, 734.862142, 1.0}, {2, 70, 1250.047417, 769.670885, 1.0}, {1, 71, 497.015305, 510.718904, 1.0}, - {2, 71, 498.682308, 541.070201, 1.0}, {1, 72, 1280.542030, 153.939185, 1.0}, {2, 72, 1286.993637, 198.436196, 1.0}, - {1, 73, 1534.748840, 138.601043, 1.0}, {2, 73, 1542.961349, 180.170819, 1.0}, {1, 74, 1477.412682, 200.608061, 1.0}, - {2, 74, 1484.683914, 240.413260, 1.0}, {1, 76, 450.637321, 407.279642, 1.0}, {2, 76, 451.695642, 441.666291, 1.0}, - {1, 78, 246.981239, 220.786298, 1.0}, {2, 78, 244.524879, 290.016564, 1.0}, {1, 79, 36.696489, 420.023407, 1.0}, - {2, 79, 21.364746, 591.245492, 1.0}, - }; - int num_markers = sizeof(markers) / sizeof(Marker); - - Tracks tracks; - for (int i = 0; i < num_markers; i++) { - double x = markers[i].x, y = markers[i].y; - intrinsics.InvertIntrinsics(x, y, &x, &y); - tracks.Insert(markers[i].image, markers[i].track, x, y); - } - - vector keyframes; - SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes); - - EXPECT_EQ(2, keyframes.size()); -} - -// Elevator scene MMI_2366 with manual tracks, frames 1, 2, 3, 5 and 27 -TEST(KeyframeSelection, ElevatorReconstructionVarianceTest) { - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(1380.000, 1380.000); - intrinsics.SetPrincipalPoint(960.000, 540.000); - intrinsics.SetRadialDistortion(-0.034, 0.0, 0.0); - - Marker markers[] = { - {1, 0, 182.999997, 1047.000010, 1.0}, {2, 0, 181.475730, 1052.091079, 1.0}, {3, 0, 181.741562, 1057.893341, 1.0}, - {4, 0, 183.190498, 1068.310440, 1.0}, {1, 1, 271.000013, 666.000009, 1.0}, {2, 1, 270.596180, 668.665760, 1.0}, - {3, 1, 270.523510, 671.559069, 1.0}, {4, 1, 271.856518, 676.818151, 1.0}, {5, 1, 268.989000, 727.051570, 1.0}, - {1, 2, 264.999990, 1018.000031, 1.0}, {2, 2, 264.020061, 1021.157591, 1.0}, {3, 2, 264.606056, 1024.823506, 1.0}, - {4, 2, 266.200933, 1031.168690, 1.0}, {1, 3, 270.000000, 938.000014, 1.0}, {2, 3, 269.022617, 941.153390, 1.0}, - {3, 3, 269.605579, 944.454954, 1.0}, {4, 3, 271.281366, 949.452167, 1.0}, {5, 3, 268.963480, 1004.417453, 1.0}, - {1, 4, 200.999994, 799.000003, 1.0}, {2, 4, 199.841366, 803.891838, 1.0}, {3, 4, 200.262208, 809.323246, 1.0}, - {4, 4, 201.456513, 819.271195, 1.0}, {5, 4, 195.026493, 924.363234, 1.0}, {1, 5, 1775.000038, 49.999998, 1.0}, - {2, 5, 1775.255127, 53.718264, 1.0}, {3, 5, 1776.449890, 55.951670, 1.0}, {4, 5, 1778.815727, 61.923309, 1.0}, - {5, 5, 1790.274124, 123.074923, 1.0}, {1, 6, 164.000001, 927.999988, 1.0}, {2, 6, 162.665462, 933.169527, 1.0}, - {3, 6, 163.067923, 938.577182, 1.0}, {4, 6, 164.370360, 948.840945, 1.0}, {5, 6, 157.199407, 1057.762341, 1.0}, - {1, 7, 618.000011, 477.999998, 1.0}, {2, 7, 617.583504, 480.124243, 1.0}, {3, 7, 618.356495, 482.441897, 1.0}, - {4, 7, 619.792500, 486.428132, 1.0}, {5, 7, 619.546051, 525.222627, 1.0}, {1, 8, 499.999981, 1036.999984, 1.0}, - {2, 8, 499.080162, 1038.720160, 1.0}, {3, 8, 499.949398, 1039.014344, 1.0}, {4, 8, 501.828003, 1041.286647, 1.0}, - {5, 8, 502.777576, 1055.196369, 1.0}, {1, 9, 1587.000046, 31.999999, 1.0}, {2, 9, 1586.988373, 34.635853, 1.0}, - {3, 9, 1588.155899, 37.444186, 1.0}, {4, 9, 1589.973106, 42.492081, 1.0}, {5, 9, 1598.683205, 96.526332, 1.0}, - {1, 10, 622.999992, 416.999999, 1.0}, {2, 10, 622.449017, 419.233485, 1.0}, {3, 10, 623.283234, 421.500703, 1.0}, - {4, 10, 624.620132, 425.537406, 1.0}, {5, 10, 624.290829, 465.078338, 1.0}, {1, 11, 577.999992, 931.999998, 1.0}, - {2, 11, 577.042294, 932.872703, 1.0}, {3, 11, 577.832451, 934.045451, 1.0}, {4, 11, 579.729137, 935.735435, 1.0}, - {5, 11, 580.691242, 948.396256, 1.0}, {1, 12, 510.999985, 931.999998, 1.0}, {2, 12, 510.111237, 933.152146, 1.0}, - {3, 12, 510.797081, 934.454219, 1.0}, {4, 12, 512.647362, 936.595910, 1.0}, {5, 12, 513.247204, 955.144157, 1.0}, - {1, 13, 330.459995, 177.059993, 1.0}, {2, 13, 329.876347, 179.615586, 1.0}, {3, 13, 330.681696, 182.757810, 1.0}, - {4, 13, 331.345053, 187.903853, 1.0}, {5, 13, 327.824135, 239.611639, 1.0}, {1, 14, 291.813097, 388.516195, 1.0}, - {2, 14, 290.984058, 391.382725, 1.0}, {3, 14, 291.526737, 394.778595, 1.0}, {4, 14, 292.763815, 400.310973, 1.0}, - {5, 14, 288.714552, 457.548015, 1.0}, {1, 15, 496.491680, 466.534005, 1.0}, {2, 15, 495.909519, 468.518561, 1.0}, - {3, 15, 496.588383, 470.853596, 1.0}, {4, 15, 497.976780, 474.731458, 1.0}, {5, 15, 496.998882, 512.568694, 1.0}, - {1, 16, 1273.000031, 89.000000, 1.0}, {2, 16, 1272.951965, 92.003637, 1.0}, {3, 16, 1273.934784, 94.972191, 1.0}, - {4, 16, 1275.493584, 100.139952, 1.0}, {5, 16, 1281.003571, 156.880163, 1.0}, {1, 17, 1524.713173, 78.852922, 1.0}, - {2, 17, 1524.782066, 81.427142, 1.0}, {3, 17, 1525.759048, 84.057939, 1.0}, {4, 17, 1527.579689, 88.966550, 1.0}, - {5, 17, 1535.262451, 141.186054, 1.0}, {1, 18, 1509.425011, 94.371824, 1.0}, {1, 19, 451.000013, 357.000003, 1.0}, - {2, 19, 450.354881, 359.312410, 1.0}, {3, 19, 451.107473, 361.837088, 1.0}, {4, 19, 452.186537, 366.318061, 1.0}, - {5, 19, 450.507660, 409.257599, 1.0}, {1, 20, 254.004936, 114.784185, 1.0}, {2, 20, 253.291512, 119.288486, 1.0}, - {3, 20, 253.745584, 124.114957, 1.0}, {4, 20, 254.453287, 132.795120, 1.0}, {5, 20, 246.772242, 225.165337, 1.0}, - {1, 21, 65.262880, 147.889409, 1.0}, {2, 21, 63.634465, 157.656807, 1.0}, {3, 21, 63.306799, 169.067053, 1.0}, - {4, 21, 62.462311, 189.724241, 1.0}, {5, 21, 35.396615, 430.308380, 1.0}, - }; - int num_markers = sizeof(markers) / sizeof(Marker); - - Tracks tracks; - for (int i = 0; i < num_markers; i++) { - double x = markers[i].x, y = markers[i].y; - intrinsics.InvertIntrinsics(x, y, &x, &y); - tracks.Insert(markers[i].image, markers[i].track, x, y); - } - - vector keyframes; - SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes); - - EXPECT_EQ(2, keyframes.size()); - if (keyframes.size() == 2) { - EXPECT_EQ(1, keyframes[0]); - EXPECT_EQ(5, keyframes[1]); - } -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver.cc b/extern/libmv/libmv/simple_pipeline/modal_solver.cc deleted file mode 100644 index 15e185eeda7..00000000000 --- a/extern/libmv/libmv/simple_pipeline/modal_solver.cc +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright (c) 2015 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/modal_solver.h" - -#include - -#include "ceres/ceres.h" -#include "ceres/rotation.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/panography.h" - -#ifdef _MSC_VER -# define snprintf _snprintf -#endif - -namespace libmv { - -namespace { -void ProjectMarkerOnSphere(const Marker &marker, Vec3 &X) { - X(0) = marker.x; - X(1) = marker.y; - X(2) = 1.0; - - X *= 5.0 / X.norm(); -} - -void ModalSolverLogProress(ProgressUpdateCallback *update_callback, - double progress) { - if (update_callback) { - char message[256]; - - snprintf(message, sizeof(message), "Solving progress %d%%", - (int)(progress * 100)); - - update_callback->invoke(progress, message); - } -} - -struct ModalReprojectionError { - ModalReprojectionError(double observed_x, - double observed_y, - const double weight, - const Vec3 &bundle) - : observed_x_(observed_x), observed_y_(observed_y), - weight_(weight), bundle_(bundle) { } - - // TODO(keir): This should support bundling focal length as well. - template - bool operator()(const T* quaternion, T* residuals) const { - // Convert bundle position from double to T. - T X[3] = { T(bundle_(0)), T(bundle_(1)), T(bundle_(2)) }; - - // Compute the point position in camera coordinates: x = RX. - T x[3]; - - // This flips the sense of the quaternion, to adhere to Blender conventions. - T quaternion_inverse[4] = { - quaternion[0], - -quaternion[1], - -quaternion[2], - -quaternion[3], - }; - ceres::QuaternionRotatePoint(quaternion_inverse, X, x); - - // Compute normalized coordinates by dividing out the depth. - T xn = x[0] / x[2]; - T yn = x[1] / x[2]; - - // The error is the difference between reprojected and observed marker - // positions, weighted by the passed in weight. - residuals[0] = T(weight_) * (xn - T(observed_x_)); - residuals[1] = T(weight_) * (yn - T(observed_y_)); - - return true; - } - - double observed_x_; - double observed_y_; - double weight_; - Vec3 bundle_; -}; -} // namespace - -void ModalSolver(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback) { - int max_image = tracks.MaxImage(); - int max_track = tracks.MaxTrack(); - - LG << "Max image: " << max_image; - LG << "Max track: " << max_track; - - // For minimization we're using quaternions. - Vec3 zero_rotation = Vec3::Zero(); - Vec4 quaternion; - ceres::AngleAxisToQuaternion(&zero_rotation(0), &quaternion(0)); - - for (int image = 0; image <= max_image; ++image) { - vector all_markers = tracks.MarkersInImage(image); - - ModalSolverLogProress(update_callback, (float) image / max_image); - - // Skip empty images without doing anything. - if (all_markers.size() == 0) { - LG << "Skipping image: " << image; - continue; - } - - // STEP 1: Estimate rotation analytically. - Mat3 current_R; - ceres::QuaternionToRotation(&quaternion(0), ¤t_R(0, 0)); - - // Construct point cloud for current and previous images, - // using markers appear at current image for which we know - // 3D positions. - Mat x1, x2; - for (int i = 0; i < all_markers.size(); ++i) { - Marker &marker = all_markers[i]; - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); - if (point) { - Vec3 X; - ProjectMarkerOnSphere(marker, X); - - int last_column = x1.cols(); - x1.conservativeResize(3, last_column + 1); - x2.conservativeResize(3, last_column + 1); - - x1.col(last_column) = current_R * point->X; - x2.col(last_column) = X; - } - } - - if (x1.cols() >= 2) { - Mat3 delta_R; - - // Compute delta rotation matrix for two point clouds. - // Could be a bit confusing at first glance, but order - // of clouds is indeed so. - GetR_FixedCameraCenter(x2, x1, 1.0, &delta_R); - - // Convert delta rotation form matrix to final image - // rotation stored in a quaternion - Vec3 delta_angle_axis; - ceres::RotationMatrixToAngleAxis(&delta_R(0, 0), &delta_angle_axis(0)); - - Vec3 current_angle_axis; - ceres::QuaternionToAngleAxis(&quaternion(0), ¤t_angle_axis(0)); - - Vec3 angle_axis = current_angle_axis + delta_angle_axis; - - ceres::AngleAxisToQuaternion(&angle_axis(0), &quaternion(0)); - - LG << "Analytically computed quaternion " - << quaternion.transpose(); - } - - // STEP 2: Refine rotation with Ceres. - ceres::Problem problem; - - ceres::LocalParameterization* quaternion_parameterization = - new ceres::QuaternionParameterization; - - int num_residuals = 0; - for (int i = 0; i < all_markers.size(); ++i) { - Marker &marker = all_markers[i]; - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); - - if (point && marker.weight != 0.0) { - problem.AddResidualBlock(new ceres::AutoDiffCostFunction< - ModalReprojectionError, - 2, /* num_residuals */ - 4>(new ModalReprojectionError(marker.x, - marker.y, - marker.weight, - point->X)), - NULL, - &quaternion(0)); - num_residuals++; - - problem.SetParameterization(&quaternion(0), - quaternion_parameterization); - } - } - - LG << "Number of residuals: " << num_residuals; - - if (num_residuals) { - // 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.gradient_tolerance = 1e-36; - solver_options.parameter_tolerance = 1e-36; - solver_options.function_tolerance = 1e-36; - - // Run the solve. - ceres::Solver::Summary summary; - ceres::Solve(solver_options, &problem, &summary); - - LG << "Summary:\n" << summary.FullReport(); - LG << "Refined quaternion " << quaternion.transpose(); - } - - // Convert quaternion to rotation matrix. - Mat3 R; - ceres::QuaternionToRotation(&quaternion(0), &R(0, 0)); - reconstruction->InsertCamera(image, R, Vec3::Zero()); - - // STEP 3: reproject all new markers appeared at image - - // Check if there're new markers appeared on current image - // and reproject them on sphere to obtain 3D position/ - for (int track = 0; track <= max_track; ++track) { - if (!reconstruction->PointForTrack(track)) { - Marker marker = tracks.MarkerInImageForTrack(image, track); - - if (marker.image == image) { - // New track appeared on this image, - // project it's position onto sphere. - - LG << "Projecting track " << track << " at image " << image; - - Vec3 X; - ProjectMarkerOnSphere(marker, X); - reconstruction->InsertPoint(track, R.inverse() * X); - } - } - } - } -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver.h b/extern/libmv/libmv/simple_pipeline/modal_solver.h deleted file mode 100644 index 9801fd21d81..00000000000 --- a/extern/libmv/libmv/simple_pipeline/modal_solver.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2012 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_MODAL_SOLVER_H_ -#define LIBMV_SIMPLE_PIPELINE_MODAL_SOLVER_H_ - -#include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/simple_pipeline/callbacks.h" - -namespace libmv { - -/*! - This solver solves such camera motion as tripod rotation, reconstructing - only camera motion itself. Bundles are not reconstructing properly, they're - just getting projected onto sphere. - - Markers from tracks object would be used for recosntruction, and algorithm - assumes thir's positions are undistorted already and they're in nnormalized - space. - - Reconstructed cameras and projected bundles would be added to reconstruction - object. -*/ -void ModalSolver(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback = NULL); - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_MODAL_SOLVER_H_ diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver_test.cc b/extern/libmv/libmv/simple_pipeline/modal_solver_test.cc deleted file mode 100644 index 8b87acd95bb..00000000000 --- a/extern/libmv/libmv/simple_pipeline/modal_solver_test.cc +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2013 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/modal_solver.h" - -#include "testing/testing.h" -#include "libmv/logging/logging.h" -#include "libmv/simple_pipeline/bundle.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" - -#include - -namespace libmv { - -TEST(ModalSolver, SyntheticCubeSceneMotion) { - double kTolerance = 1e-8; - - PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(658.286, 658.286); - intrinsics.SetPrincipalPoint(480.0, 270.0); - intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); - - Marker markers[] = { - {1, 0, 212.172775, 354.713538, 1.0}, {2, 0, 773.468399, 358.735306, 1.0}, - {1, 1, 62.415197, 287.905354, 1.0}, {2, 1, 619.103336, 324.402537, 1.0}, - {1, 2, 206.847939, 237.567925, 1.0}, {2, 2, 737.496986, 247.881383, 1.0}, - {1, 3, 351.743889, 316.415906, 1.0}, {2, 3, 908.779621, 290.703617, 1.0}, - {1, 4, 232.941413, 54.265443, 1.0}, {2, 4, 719.444847, 63.062531, 1.0}, - {1, 5, 96.391611, 119.283537, 1.0}, {2, 5, 611.413136, 160.890715, 1.0}, - {1, 6, 363.444958, 150.838144, 1.0}, {2, 6, 876.374531, 114.916206, 1.0}, - }; - int num_markers = sizeof(markers) / sizeof(Marker); - - Tracks tracks; - for (int i = 0; i < num_markers; i++) { - double x = markers[i].x, y = markers[i].y; - intrinsics.InvertIntrinsics(x, y, &x, &y); - tracks.Insert(markers[i].image, markers[i].track, x, y); - } - - EuclideanReconstruction reconstruction; - ModalSolver(tracks, &reconstruction); - EuclideanBundleCommonIntrinsics(tracks, - BUNDLE_NO_INTRINSICS, - BUNDLE_NO_TRANSLATION, - &reconstruction, - &intrinsics, - NULL); - - Mat3 expected_rotation; - expected_rotation << 0.98215101299251, 0.17798357184544, 0.06083778292258, - -0.16875286001759, 0.97665299913606, -0.13293378620359, - -0.08307743323957, 0.12029450291547, 0.98925596922871; - - Mat3 &first_camera_R = reconstruction.CameraForImage(1)->R; - Mat3 &second_camera_R = reconstruction.CameraForImage(2)->R; - - EXPECT_TRUE(Mat3::Identity().isApprox(first_camera_R, kTolerance)); - EXPECT_TRUE(expected_rotation.isApprox(second_camera_R, kTolerance)); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.cc b/extern/libmv/libmv/simple_pipeline/pipeline.cc deleted file mode 100644 index 6c8592baa00..00000000000 --- a/extern/libmv/libmv/simple_pipeline/pipeline.cc +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/pipeline.h" - -#include - -#include "libmv/logging/logging.h" -#include "libmv/simple_pipeline/bundle.h" -#include "libmv/simple_pipeline/intersect.h" -#include "libmv/simple_pipeline/resect.h" -#include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" - -#ifdef _MSC_VER -# define snprintf _snprintf -#endif - -namespace libmv { -namespace { - -// These are "strategy" classes which make it possible to use the same code for -// both projective and euclidean reconstruction. -// FIXME(MatthiasF): OOP would achieve the same goal while avoiding -// template bloat and making interface changes much easier. -struct EuclideanPipelineRoutines { - typedef EuclideanReconstruction Reconstruction; - typedef EuclideanCamera Camera; - typedef EuclideanPoint Point; - - static void Bundle(const Tracks &tracks, - EuclideanReconstruction *reconstruction) { - EuclideanBundle(tracks, reconstruction); - } - - static bool Resect(const vector &markers, - EuclideanReconstruction *reconstruction, bool final_pass) { - return EuclideanResect(markers, reconstruction, final_pass); - } - - static bool Intersect(const vector &markers, - EuclideanReconstruction *reconstruction) { - return EuclideanIntersect(markers, reconstruction); - } - - static Marker ProjectMarker(const EuclideanPoint &point, - const EuclideanCamera &camera, - const CameraIntrinsics &intrinsics) { - Vec3 projected = camera.R * point.X + camera.t; - projected /= projected(2); - - Marker reprojected_marker; - intrinsics.ApplyIntrinsics(projected(0), - projected(1), - &reprojected_marker.x, - &reprojected_marker.y); - - reprojected_marker.image = camera.image; - reprojected_marker.track = point.track; - return reprojected_marker; - } -}; - -struct ProjectivePipelineRoutines { - typedef ProjectiveReconstruction Reconstruction; - typedef ProjectiveCamera Camera; - typedef ProjectivePoint Point; - - static void Bundle(const Tracks &tracks, - ProjectiveReconstruction *reconstruction) { - ProjectiveBundle(tracks, reconstruction); - } - - static bool Resect(const vector &markers, - ProjectiveReconstruction *reconstruction, bool final_pass) { - (void) final_pass; // Ignored. - - return ProjectiveResect(markers, reconstruction); - } - - static bool Intersect(const vector &markers, - ProjectiveReconstruction *reconstruction) { - return ProjectiveIntersect(markers, reconstruction); - } - - static Marker ProjectMarker(const ProjectivePoint &point, - const ProjectiveCamera &camera, - const CameraIntrinsics &intrinsics) { - Vec3 projected = camera.P * point.X; - projected /= projected(2); - - Marker reprojected_marker; - intrinsics.ApplyIntrinsics(projected(0), - projected(1), - &reprojected_marker.x, - &reprojected_marker.y); - - reprojected_marker.image = camera.image; - reprojected_marker.track = point.track; - return reprojected_marker; - } -}; - -} // namespace - -static void CompleteReconstructionLogProgress( - ProgressUpdateCallback *update_callback, - double progress, - const char *step = NULL) { - if (update_callback) { - char message[256]; - - if (step) - snprintf(message, sizeof(message), "Completing solution %d%% | %s", - (int)(progress*100), step); - else - snprintf(message, sizeof(message), "Completing solution %d%%", - (int)(progress*100)); - - update_callback->invoke(progress, message); - } -} - -template -void InternalCompleteReconstruction( - const Tracks &tracks, - typename PipelineRoutines::Reconstruction *reconstruction, - ProgressUpdateCallback *update_callback = NULL) { - int max_track = tracks.MaxTrack(); - int max_image = tracks.MaxImage(); - int num_resects = -1; - int num_intersects = -1; - int tot_resects = 0; - LG << "Max track: " << max_track; - LG << "Max image: " << max_image; - LG << "Number of markers: " << tracks.NumMarkers(); - while (num_resects != 0 || num_intersects != 0) { - // Do all possible intersections. - num_intersects = 0; - for (int track = 0; track <= max_track; ++track) { - if (reconstruction->PointForTrack(track)) { - LG << "Skipping point: " << track; - continue; - } - vector all_markers = tracks.MarkersForTrack(track); - LG << "Got " << all_markers.size() << " markers for track " << track; - - vector reconstructed_markers; - for (int i = 0; i < all_markers.size(); ++i) { - if (reconstruction->CameraForImage(all_markers[i].image)) { - reconstructed_markers.push_back(all_markers[i]); - } - } - LG << "Got " << reconstructed_markers.size() - << " reconstructed markers for track " << track; - if (reconstructed_markers.size() >= 2) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image)); - if (PipelineRoutines::Intersect(reconstructed_markers, - reconstruction)) { - num_intersects++; - LG << "Ran Intersect() for track " << track; - } else { - LG << "Failed Intersect() for track " << track; - } - } - } - if (num_intersects) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image), - "Bundling..."); - PipelineRoutines::Bundle(tracks, reconstruction); - LG << "Ran Bundle() after intersections."; - } - LG << "Did " << num_intersects << " intersects."; - - // Do all possible resections. - num_resects = 0; - for (int image = 0; image <= max_image; ++image) { - if (reconstruction->CameraForImage(image)) { - LG << "Skipping frame: " << image; - continue; - } - vector all_markers = tracks.MarkersInImage(image); - LG << "Got " << all_markers.size() << " markers for image " << image; - - vector reconstructed_markers; - for (int i = 0; i < all_markers.size(); ++i) { - if (reconstruction->PointForTrack(all_markers[i].track)) { - reconstructed_markers.push_back(all_markers[i]); - } - } - LG << "Got " << reconstructed_markers.size() - << " reconstructed markers for image " << image; - if (reconstructed_markers.size() >= 5) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image)); - if (PipelineRoutines::Resect(reconstructed_markers, - reconstruction, false)) { - num_resects++; - tot_resects++; - LG << "Ran Resect() for image " << image; - } else { - LG << "Failed Resect() for image " << image; - } - } - } - if (num_resects) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image), - "Bundling..."); - PipelineRoutines::Bundle(tracks, reconstruction); - } - LG << "Did " << num_resects << " resects."; - } - - // One last pass... - num_resects = 0; - for (int image = 0; image <= max_image; ++image) { - if (reconstruction->CameraForImage(image)) { - LG << "Skipping frame: " << image; - continue; - } - vector all_markers = tracks.MarkersInImage(image); - - vector reconstructed_markers; - for (int i = 0; i < all_markers.size(); ++i) { - if (reconstruction->PointForTrack(all_markers[i].track)) { - reconstructed_markers.push_back(all_markers[i]); - } - } - if (reconstructed_markers.size() >= 5) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image)); - if (PipelineRoutines::Resect(reconstructed_markers, - reconstruction, true)) { - num_resects++; - LG << "Ran final Resect() for image " << image; - } else { - LG << "Failed final Resect() for image " << image; - } - } - } - if (num_resects) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image), - "Bundling..."); - PipelineRoutines::Bundle(tracks, reconstruction); - } -} - -template -double InternalReprojectionError( - const Tracks &image_tracks, - const typename PipelineRoutines::Reconstruction &reconstruction, - const CameraIntrinsics &intrinsics) { - int num_skipped = 0; - int num_reprojected = 0; - double total_error = 0.0; - vector markers = image_tracks.AllMarkers(); - for (int i = 0; i < markers.size(); ++i) { - double weight = markers[i].weight; - const typename PipelineRoutines::Camera *camera = - reconstruction.CameraForImage(markers[i].image); - const typename PipelineRoutines::Point *point = - reconstruction.PointForTrack(markers[i].track); - if (!camera || !point || weight == 0.0) { - num_skipped++; - continue; - } - num_reprojected++; - - Marker reprojected_marker = - PipelineRoutines::ProjectMarker(*point, *camera, intrinsics); - double ex = (reprojected_marker.x - markers[i].x) * weight; - double ey = (reprojected_marker.y - markers[i].y) * weight; - - const int N = 100; - char line[N]; - snprintf(line, N, - "image %-3d track %-3d " - "x %7.1f y %7.1f " - "rx %7.1f ry %7.1f " - "ex %7.1f ey %7.1f" - " e %7.1f", - markers[i].image, - markers[i].track, - markers[i].x, - markers[i].y, - reprojected_marker.x, - reprojected_marker.y, - ex, - ey, - sqrt(ex*ex + ey*ey)); - VLOG(1) << line; - - total_error += sqrt(ex*ex + ey*ey); - } - LG << "Skipped " << num_skipped << " markers."; - LG << "Reprojected " << num_reprojected << " markers."; - LG << "Total error: " << total_error; - LG << "Average error: " << (total_error / num_reprojected) << " [pixels]."; - return total_error / num_reprojected; -} - -double EuclideanReprojectionError(const Tracks &image_tracks, - const EuclideanReconstruction &reconstruction, - const CameraIntrinsics &intrinsics) { - return InternalReprojectionError(image_tracks, - reconstruction, - intrinsics); -} - -double ProjectiveReprojectionError( - const Tracks &image_tracks, - const ProjectiveReconstruction &reconstruction, - const CameraIntrinsics &intrinsics) { - return InternalReprojectionError(image_tracks, - reconstruction, - intrinsics); -} - -void EuclideanCompleteReconstruction(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback) { - InternalCompleteReconstruction(tracks, - reconstruction, - update_callback); -} - -void ProjectiveCompleteReconstruction(const Tracks &tracks, - ProjectiveReconstruction *reconstruction) { - InternalCompleteReconstruction(tracks, - reconstruction); -} - -void InvertIntrinsicsForTracks(const Tracks &raw_tracks, - const CameraIntrinsics &camera_intrinsics, - Tracks *calibrated_tracks) { - vector markers = raw_tracks.AllMarkers(); - for (int i = 0; i < markers.size(); ++i) { - camera_intrinsics.InvertIntrinsics(markers[i].x, - markers[i].y, - &(markers[i].x), - &(markers[i].y)); - } - *calibrated_tracks = Tracks(markers); -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.h b/extern/libmv/libmv/simple_pipeline/pipeline.h deleted file mode 100644 index 4d1bd00c51f..00000000000 --- a/extern/libmv/libmv/simple_pipeline/pipeline.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_PIPELINE_H_ -#define LIBMV_SIMPLE_PIPELINE_PIPELINE_H_ - -#include "libmv/simple_pipeline/callbacks.h" -#include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/reconstruction.h" - -namespace libmv { - -/*! - Estimate camera poses and scene 3D coordinates for all frames and tracks. - - This method should be used once there is an initial reconstruction in - place, for example by reconstructing from two frames that have a sufficient - baseline and number of tracks in common. This function iteratively - triangulates points that are visible by cameras that have their pose - estimated, then resections (i.e. estimates the pose) of cameras that are - not estimated yet that can see triangulated points. This process is - repeated until all points and cameras are estimated. Periodically, bundle - adjustment is run to ensure a quality reconstruction. - - \a tracks should contain markers used in the reconstruction. - \a reconstruction should contain at least some 3D points or some estimated - cameras. The minimum number of cameras is two (with no 3D points) and the - minimum number of 3D points (with no estimated cameras) is 5. - - \sa EuclideanResect, EuclideanIntersect, EuclideanBundle -*/ -void EuclideanCompleteReconstruction( - const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback = NULL); - -/*! - Estimate camera matrices and homogeneous 3D coordinates for all frames and - tracks. - - This method should be used once there is an initial reconstruction in - place, for example by reconstructing from two frames that have a sufficient - baseline and number of tracks in common. This function iteratively - triangulates points that are visible by cameras that have their pose - estimated, then resections (i.e. estimates the pose) of cameras that are - not estimated yet that can see triangulated points. This process is - repeated until all points and cameras are estimated. Periodically, bundle - adjustment is run to ensure a quality reconstruction. - - \a tracks should contain markers used in the reconstruction. - \a reconstruction should contain at least some 3D points or some estimated - cameras. The minimum number of cameras is two (with no 3D points) and the - minimum number of 3D points (with no estimated cameras) is 5. - - \sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle -*/ -void ProjectiveCompleteReconstruction(const Tracks &tracks, - ProjectiveReconstruction *reconstruction); - - -class CameraIntrinsics; - -// TODO(keir): Decide if we want these in the public API, and if so, what the -// appropriate include file is. - -double EuclideanReprojectionError(const Tracks &image_tracks, - const EuclideanReconstruction &reconstruction, - const CameraIntrinsics &intrinsics); - -double ProjectiveReprojectionError( - const Tracks &image_tracks, - const ProjectiveReconstruction &reconstruction, - const CameraIntrinsics &intrinsics); - -void InvertIntrinsicsForTracks(const Tracks &raw_tracks, - const CameraIntrinsics &camera_intrinsics, - Tracks *calibrated_tracks); - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_PIPELINE_H_ diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction.cc b/extern/libmv/libmv/simple_pipeline/reconstruction.cc deleted file mode 100644 index 65e5dd27d5d..00000000000 --- a/extern/libmv/libmv/simple_pipeline/reconstruction.cc +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/numeric/numeric.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -EuclideanReconstruction::EuclideanReconstruction() {} -EuclideanReconstruction::EuclideanReconstruction( - const EuclideanReconstruction &other) { - cameras_ = other.cameras_; - points_ = other.points_; -} - -EuclideanReconstruction &EuclideanReconstruction::operator=( - const EuclideanReconstruction &other) { - if (&other != this) { - cameras_ = other.cameras_; - points_ = other.points_; - } - return *this; -} - -void EuclideanReconstruction::InsertCamera(int image, - const Mat3 &R, - const Vec3 &t) { - LG << "InsertCamera " << image << ":\nR:\n"<< R << "\nt:\n" << t; - if (image >= cameras_.size()) { - cameras_.resize(image + 1); - } - cameras_[image].image = image; - cameras_[image].R = R; - cameras_[image].t = t; -} - -void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) { - LG << "InsertPoint " << track << ":\n" << X; - if (track >= points_.size()) { - points_.resize(track + 1); - } - points_[track].track = track; - points_[track].X = X; -} - -EuclideanCamera *EuclideanReconstruction::CameraForImage(int image) { - return const_cast( - static_cast( - this)->CameraForImage(image)); -} - -const EuclideanCamera *EuclideanReconstruction::CameraForImage( - int image) const { - if (image < 0 || image >= cameras_.size()) { - return NULL; - } - const EuclideanCamera *camera = &cameras_[image]; - if (camera->image == -1) { - return NULL; - } - return camera; -} - -vector EuclideanReconstruction::AllCameras() const { - vector cameras; - for (int i = 0; i < cameras_.size(); ++i) { - if (cameras_[i].image != -1) { - cameras.push_back(cameras_[i]); - } - } - return cameras; -} - -EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) { - return const_cast( - static_cast(this)->PointForTrack(track)); -} - -const EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) const { - if (track < 0 || track >= points_.size()) { - return NULL; - } - const EuclideanPoint *point = &points_[track]; - if (point->track == -1) { - return NULL; - } - return point; -} - -vector EuclideanReconstruction::AllPoints() const { - vector points; - for (int i = 0; i < points_.size(); ++i) { - if (points_[i].track != -1) { - points.push_back(points_[i]); - } - } - return points; -} - -void ProjectiveReconstruction::InsertCamera(int image, - const Mat34 &P) { - LG << "InsertCamera " << image << ":\nP:\n"<< P; - if (image >= cameras_.size()) { - cameras_.resize(image + 1); - } - cameras_[image].image = image; - cameras_[image].P = P; -} - -void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) { - LG << "InsertPoint " << track << ":\n" << X; - if (track >= points_.size()) { - points_.resize(track + 1); - } - points_[track].track = track; - points_[track].X = X; -} - -ProjectiveCamera *ProjectiveReconstruction::CameraForImage(int image) { - return const_cast( - static_cast( - this)->CameraForImage(image)); -} - -const ProjectiveCamera *ProjectiveReconstruction::CameraForImage( - int image) const { - if (image < 0 || image >= cameras_.size()) { - return NULL; - } - const ProjectiveCamera *camera = &cameras_[image]; - if (camera->image == -1) { - return NULL; - } - return camera; -} - -vector ProjectiveReconstruction::AllCameras() const { - vector cameras; - for (int i = 0; i < cameras_.size(); ++i) { - if (cameras_[i].image != -1) { - cameras.push_back(cameras_[i]); - } - } - return cameras; -} - -ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) { - return const_cast( - static_cast(this)->PointForTrack(track)); -} - -const ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) const { - if (track < 0 || track >= points_.size()) { - return NULL; - } - const ProjectivePoint *point = &points_[track]; - if (point->track == -1) { - return NULL; - } - return point; -} - -vector ProjectiveReconstruction::AllPoints() const { - vector points; - for (int i = 0; i < points_.size(); ++i) { - if (points_[i].track != -1) { - points.push_back(points_[i]); - } - } - return points; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction.h b/extern/libmv/libmv/simple_pipeline/reconstruction.h deleted file mode 100644 index 947a0636476..00000000000 --- a/extern/libmv/libmv/simple_pipeline/reconstruction.h +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_ -#define LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_ - -#include "libmv/base/vector.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { - -/*! - A EuclideanCamera is the location and rotation of the camera viewing \a image. - - \a image identify which image from \l Tracks this camera represents. - \a R is a 3x3 matrix representing the rotation of the camera. - \a t is a translation vector representing its positions. - - \sa Reconstruction -*/ -struct EuclideanCamera { - EuclideanCamera() : image(-1) {} - EuclideanCamera(const EuclideanCamera &c) : image(c.image), R(c.R), t(c.t) {} - - int image; - Mat3 R; - Vec3 t; -}; - -/*! - A Point is the 3D location of a track. - - \a track identify which track from \l Tracks this point corresponds to. - \a X represents the 3D position of the track. - - \sa Reconstruction -*/ -struct EuclideanPoint { - EuclideanPoint() : track(-1) {} - EuclideanPoint(const EuclideanPoint &p) : track(p.track), X(p.X) {} - int track; - Vec3 X; -}; - -/*! - The EuclideanReconstruction class stores \link EuclideanCamera cameras - \endlink and \link EuclideanPoint points \endlink. - - The EuclideanReconstruction container is intended as the store of 3D - reconstruction data to be used with the MultiView API. - - The container has lookups to query a \a EuclideanCamera from an \a image or - a \a EuclideanPoint from a \a track. - - \sa Camera, Point -*/ -class EuclideanReconstruction { - public: - // Default constructor starts with no cameras. - EuclideanReconstruction(); - - /// Copy constructor. - EuclideanReconstruction(const EuclideanReconstruction &other); - - EuclideanReconstruction &operator=(const EuclideanReconstruction &other); - - /*! - Insert a camera into the set. If there is already a camera for the given - \a image, the existing camera is replaced. If there is no camera for the - given \a image, a new one is added. - - \a image is the key used to retrieve the cameras with the other methods - in this class. - - \note You should use the same \a image identifier as in \l Tracks. - */ - void InsertCamera(int image, const Mat3 &R, const Vec3 &t); - - /*! - Insert a point into the reconstruction. If there is already a point for - the given \a track, the existing point is replaced. If there is no point - for the given \a track, a new one is added. - - \a track is the key used to retrieve the points with the - other methods in this class. - - \note You should use the same \a track identifier as in \l Tracks. - */ - void InsertPoint(int track, const Vec3 &X); - - /// Returns a pointer to the camera corresponding to \a image. - EuclideanCamera *CameraForImage(int image); - const EuclideanCamera *CameraForImage(int image) const; - - /// Returns all cameras. - vector AllCameras() const; - - /// Returns a pointer to the point corresponding to \a track. - EuclideanPoint *PointForTrack(int track); - const EuclideanPoint *PointForTrack(int track) const; - - /// Returns all points. - vector AllPoints() const; - - private: - vector cameras_; - vector points_; -}; - -/*! - A ProjectiveCamera is the projection matrix for the camera of \a image. - - \a image identify which image from \l Tracks this camera represents. - \a P is the 3x4 projection matrix. - - \sa ProjectiveReconstruction -*/ -struct ProjectiveCamera { - ProjectiveCamera() : image(-1) {} - ProjectiveCamera(const ProjectiveCamera &c) : image(c.image), P(c.P) {} - - int image; - Mat34 P; -}; - -/*! - A Point is the 3D location of a track. - - \a track identifies which track from \l Tracks this point corresponds to. - \a X is the homogeneous 3D position of the track. - - \sa Reconstruction -*/ -struct ProjectivePoint { - ProjectivePoint() : track(-1) {} - ProjectivePoint(const ProjectivePoint &p) : track(p.track), X(p.X) {} - int track; - Vec4 X; -}; - -/*! - The ProjectiveReconstruction class stores \link ProjectiveCamera cameras - \endlink and \link ProjectivePoint points \endlink. - - The ProjectiveReconstruction container is intended as the store of 3D - reconstruction data to be used with the MultiView API. - - The container has lookups to query a \a ProjectiveCamera from an \a image or - a \a ProjectivePoint from a \a track. - - \sa Camera, Point -*/ -class ProjectiveReconstruction { - public: - /*! - Insert a camera into the set. If there is already a camera for the given - \a image, the existing camera is replaced. If there is no camera for the - given \a image, a new one is added. - - \a image is the key used to retrieve the cameras with the other methods - in this class. - - \note You should use the same \a image identifier as in \l Tracks. - */ - void InsertCamera(int image, const Mat34 &P); - - /*! - Insert a point into the reconstruction. If there is already a point for - the given \a track, the existing point is replaced. If there is no point - for the given \a track, a new one is added. - - \a track is the key used to retrieve the points with the - other methods in this class. - - \note You should use the same \a track identifier as in \l Tracks. - */ - void InsertPoint(int track, const Vec4 &X); - - /// Returns a pointer to the camera corresponding to \a image. - ProjectiveCamera *CameraForImage(int image); - const ProjectiveCamera *CameraForImage(int image) const; - - /// Returns all cameras. - vector AllCameras() const; - - /// Returns a pointer to the point corresponding to \a track. - ProjectivePoint *PointForTrack(int track); - const ProjectivePoint *PointForTrack(int track) const; - - /// Returns all points. - vector AllPoints() const; - - private: - vector cameras_; - vector points_; -}; - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_ diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc b/extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc deleted file mode 100644 index 40ac23be7a2..00000000000 --- a/extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2013 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/reconstruction_scale.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction) { - vector all_cameras = reconstruction->AllCameras(); - vector all_points = reconstruction->AllPoints(); - - // Calculate center of the mass of all cameras. - Vec3 cameras_mass_center = Vec3::Zero(); - for (int i = 0; i < all_cameras.size(); ++i) { - cameras_mass_center += all_cameras[i].t; - } - cameras_mass_center /= all_cameras.size(); - - // Find the most distant camera from the mass center. - double max_distance = 0.0; - for (int i = 0; i < all_cameras.size(); ++i) { - double distance = (all_cameras[i].t - cameras_mass_center).squaredNorm(); - if (distance > max_distance) { - max_distance = distance; - } - } - - if (max_distance == 0.0) { - LG << "Cameras position variance is too small, can not rescale"; - return; - } - - double scale_factor = 1.0 / sqrt(max_distance); - - // Rescale cameras positions. - for (int i = 0; i < all_cameras.size(); ++i) { - int image = all_cameras[i].image; - EuclideanCamera *camera = reconstruction->CameraForImage(image); - camera->t = camera->t * scale_factor; - } - - // Rescale points positions. - for (int i = 0; i < all_points.size(); ++i) { - int track = all_points[i].track; - EuclideanPoint *point = reconstruction->PointForTrack(track); - point->X = point->X * scale_factor; - } -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction_scale.h b/extern/libmv/libmv/simple_pipeline/reconstruction_scale.h deleted file mode 100644 index f2349ff5146..00000000000 --- a/extern/libmv/libmv/simple_pipeline/reconstruction_scale.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2013 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_SCALE_H_ -#define LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_SCALE_H_ - -#include "libmv/simple_pipeline/reconstruction.h" - -namespace libmv { - -/*! - Scale euclidean reconstruction in a way variance of - camera centers equals to one. - */ -void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction); - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_SCALE_H_ diff --git a/extern/libmv/libmv/simple_pipeline/resect.cc b/extern/libmv/libmv/simple_pipeline/resect.cc deleted file mode 100644 index e73fc44df2a..00000000000 --- a/extern/libmv/libmv/simple_pipeline/resect.cc +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/resect.h" - -#include - -#include "libmv/base/vector.h" -#include "libmv/logging/logging.h" -#include "libmv/multiview/euclidean_resection.h" -#include "libmv/multiview/resection.h" -#include "libmv/multiview/projection.h" -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/levenberg_marquardt.h" -#include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/simple_pipeline/tracks.h" - -namespace libmv { -namespace { - -Mat2X PointMatrixFromMarkers(const vector &markers) { - Mat2X points(2, markers.size()); - for (int i = 0; i < markers.size(); ++i) { - points(0, i) = markers[i].x; - points(1, i) = markers[i].y; - } - return points; -} - -// Uses an incremental rotation: -// -// x = R' * R * X + t; -// -// to avoid issues with the rotation representation. R' is derived from a -// euler vector encoding the rotation in 3 parameters; the direction is the -// axis to rotate around and the magnitude is the amount of the rotation. -struct EuclideanResectCostFunction { - public: - typedef Vec FMatrixType; - typedef Vec6 XMatrixType; - - EuclideanResectCostFunction(const vector &markers, - const EuclideanReconstruction &reconstruction, - const Mat3 &initial_R) - : markers(markers), - reconstruction(reconstruction), - initial_R(initial_R) {} - - // dRt has dR (delta R) encoded as a euler vector in the first 3 parameters, - // followed by t in the next 3 parameters. - Vec operator()(const Vec6 &dRt) const { - // Unpack R, t from dRt. - Mat3 R = RotationFromEulerVector(dRt.head<3>()) * initial_R; - Vec3 t = dRt.tail<3>(); - - // Compute the reprojection error for each coordinate. - Vec residuals(2 * markers.size()); - residuals.setZero(); - for (int i = 0; i < markers.size(); ++i) { - const EuclideanPoint &point = - *reconstruction.PointForTrack(markers[i].track); - Vec3 projected = R * point.X + t; - projected /= projected(2); - residuals[2*i + 0] = projected(0) - markers[i].x; - residuals[2*i + 1] = projected(1) - markers[i].y; - } - return residuals; - } - - const vector &markers; - const EuclideanReconstruction &reconstruction; - const Mat3 &initial_R; -}; - -} // namespace - -bool EuclideanResect(const vector &markers, - EuclideanReconstruction *reconstruction, bool final_pass) { - if (markers.size() < 5) { - return false; - } - Mat2X points_2d = PointMatrixFromMarkers(markers); - Mat3X points_3d(3, markers.size()); - for (int i = 0; i < markers.size(); i++) { - points_3d.col(i) = reconstruction->PointForTrack(markers[i].track)->X; - } - LG << "Points for resect:\n" << points_2d; - - Mat3 R; - Vec3 t; - - if (0 || !euclidean_resection::EuclideanResection( - points_2d, points_3d, &R, &t, - euclidean_resection::RESECTION_EPNP)) { - // printf("Resection for image %d failed\n", markers[0].image); - LG << "Resection for image " << markers[0].image << " failed;" - << " trying fallback projective resection."; - - LG << "No fallback; failing resection for " << markers[0].image; - return false; - - if (!final_pass) return false; - // Euclidean resection failed. Fall back to projective resection, which is - // less reliable but better conditioned when there are many points. - Mat34 P; - Mat4X points_3d_homogeneous(4, markers.size()); - for (int i = 0; i < markers.size(); i++) { - points_3d_homogeneous.col(i).head<3>() = points_3d.col(i); - points_3d_homogeneous(3, i) = 1.0; - } - resection::Resection(points_2d, points_3d_homogeneous, &P); - if ((P * points_3d_homogeneous.col(0))(2) < 0) { - LG << "Point behind camera; switch sign."; - P = -P; - } - - Mat3 ignored; - KRt_From_P(P, &ignored, &R, &t); - - // The R matrix should be a rotation, but don't rely on it. - Eigen::JacobiSVD svd(R, Eigen::ComputeFullU | Eigen::ComputeFullV); - - LG << "Resection rotation is: " << svd.singularValues().transpose(); - LG << "Determinant is: " << R.determinant(); - - // Correct to make R a rotation. - R = svd.matrixU() * svd.matrixV().transpose(); - - Vec3 xx = R * points_3d.col(0) + t; - if (xx(2) < 0.0) { - LG << "Final point is still behind camera..."; - } - // XXX Need to check if error is horrible and fail here too in that case. - } - - // Refine the result. - typedef LevenbergMarquardt Solver; - - // Give the cost our initial guess for R. - EuclideanResectCostFunction resect_cost(markers, *reconstruction, R); - - // Encode the initial parameters: start with zero delta rotation, and the - // guess for t obtained from resection. - Vec6 dRt = Vec6::Zero(); - dRt.tail<3>() = t; - - Solver solver(resect_cost); - - Solver::SolverParameters params; - /* Solver::Results results = */ solver.minimize(params, &dRt); - LG << "LM found incremental rotation: " << dRt.head<3>().transpose(); - // TODO(keir): Check results to ensure clean termination. - - // Unpack the rotation and translation. - R = RotationFromEulerVector(dRt.head<3>()) * R; - t = dRt.tail<3>(); - - LG << "Resection for image " << markers[0].image << " got:\n" - << "R:\n" << R << "\nt:\n" << t; - reconstruction->InsertCamera(markers[0].image, R, t); - return true; -} - -namespace { - -// Directly parameterize the projection matrix, P, which is a 12 parameter -// homogeneous entry. In theory P should be parameterized with only 11 -// parametetrs, but in practice it works fine to let the extra degree of -// freedom drift. -struct ProjectiveResectCostFunction { - public: - typedef Vec FMatrixType; - typedef Vec12 XMatrixType; - - ProjectiveResectCostFunction(const vector &markers, - const ProjectiveReconstruction &reconstruction) - : markers(markers), - reconstruction(reconstruction) {} - - Vec operator()(const Vec12 &vector_P) const { - // Unpack P from vector_P. - Map P(vector_P.data(), 3, 4); - - // Compute the reprojection error for each coordinate. - Vec residuals(2 * markers.size()); - residuals.setZero(); - for (int i = 0; i < markers.size(); ++i) { - const ProjectivePoint &point = - *reconstruction.PointForTrack(markers[i].track); - Vec3 projected = P * point.X; - projected /= projected(2); - residuals[2*i + 0] = projected(0) - markers[i].x; - residuals[2*i + 1] = projected(1) - markers[i].y; - } - return residuals; - } - - const vector &markers; - const ProjectiveReconstruction &reconstruction; -}; - -} // namespace - -bool ProjectiveResect(const vector &markers, - ProjectiveReconstruction *reconstruction) { - if (markers.size() < 5) { - return false; - } - - // Stack the homogeneous 3D points as the columns of a matrix. - Mat2X points_2d = PointMatrixFromMarkers(markers); - Mat4X points_3d_homogeneous(4, markers.size()); - for (int i = 0; i < markers.size(); i++) { - points_3d_homogeneous.col(i) = - reconstruction->PointForTrack(markers[i].track)->X; - } - LG << "Points for resect:\n" << points_2d; - - // Resection the point. - Mat34 P; - resection::Resection(points_2d, points_3d_homogeneous, &P); - - // Flip the sign of P if necessary to keep the point in front of the camera. - if ((P * points_3d_homogeneous.col(0))(2) < 0) { - LG << "Point behind camera; switch sign."; - P = -P; - } - - // TODO(keir): Check if error is horrible and fail in that case. - - // Refine the resulting projection matrix using geometric error. - typedef LevenbergMarquardt Solver; - - ProjectiveResectCostFunction resect_cost(markers, *reconstruction); - - // Pack the initial P matrix into a size-12 vector.. - Vec12 vector_P = Map(P.data()); - - Solver solver(resect_cost); - - Solver::SolverParameters params; - /* Solver::Results results = */ solver.minimize(params, &vector_P); - // TODO(keir): Check results to ensure clean termination. - - // Unpack the projection matrix. - P = Map(vector_P.data(), 3, 4); - - LG << "Resection for image " << markers[0].image << " got:\n" - << "P:\n" << P; - reconstruction->InsertCamera(markers[0].image, P); - return true; -} -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/resect.h b/extern/libmv/libmv/simple_pipeline/resect.h deleted file mode 100644 index 7ca3237437e..00000000000 --- a/extern/libmv/libmv/simple_pipeline/resect.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_RESECT_H -#define LIBMV_SIMPLE_PIPELINE_RESECT_H - -#include "libmv/base/vector.h" -#include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/reconstruction.h" - -namespace libmv { - -/*! - Estimate the Euclidean pose of a camera from 2D to 3D correspondences. - - This takes a set of markers visible in one frame (which is the one to - resection), such that the markers are also reconstructed in 3D in the - reconstruction object, and solves for the pose and orientation of the - camera for that frame. - - \a markers should contain \l Marker markers \endlink belonging to tracks - visible in the one frame to be resectioned. Each of the tracks associated - with the markers must have a corresponding reconstructed 3D position in the - \a *reconstruction object. - - \a *reconstruction should contain the 3D points associated with the tracks - for the markers present in \a markers. - - \note This assumes a calibrated reconstruction, e.g. the markers are - already corrected for camera intrinsics and radial distortion. - \note This assumes an outlier-free set of markers. - - \return True if the resection was successful, false otherwise. - - \sa EuclideanIntersect, EuclideanReconstructTwoFrames -*/ -bool EuclideanResect(const vector &markers, - EuclideanReconstruction *reconstruction, bool final_pass); - -/*! - Estimate the projective pose of a camera from 2D to 3D correspondences. - - This takes a set of markers visible in one frame (which is the one to - resection), such that the markers are also reconstructed in a projective - frame in the reconstruction object, and solves for the projective matrix of - the camera for that frame. - - \a markers should contain \l Marker markers \endlink belonging to tracks - visible in the one frame to be resectioned. Each of the tracks associated - with the markers must have a corresponding reconstructed homogeneous 3D - position in the \a *reconstruction object. - - \a *reconstruction should contain the homogeneous 3D points associated with - the tracks for the markers present in \a markers. - - \note This assumes radial distortion has already been corrected, but - otherwise works for uncalibrated sequences. - \note This assumes an outlier-free set of markers. - - \return True if the resection was successful, false otherwise. - - \sa ProjectiveIntersect, ProjectiveReconstructTwoFrames -*/ -bool ProjectiveResect(const vector &markers, - ProjectiveReconstruction *reconstruction); - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_RESECT_H diff --git a/extern/libmv/libmv/simple_pipeline/resect_test.cc b/extern/libmv/libmv/simple_pipeline/resect_test.cc deleted file mode 100644 index 811edd282d8..00000000000 --- a/extern/libmv/libmv/simple_pipeline/resect_test.cc +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (c) 2009 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/resect.h" -#include "libmv/logging/logging.h" -#include "testing/testing.h" - -#if 0 -// Generates all necessary inputs and expected outputs for EuclideanResection. -void CreateCameraSystem(const Mat3& KK, - const Mat3X& x_image, - const Vec& X_distances, - const Mat3& R_input, - const Vec3& T_input, - Mat2X *x_camera, - Mat3X *X_world, - Mat3 *R_expected, - Vec3 *T_expected) { - int num_points = x_image.cols(); - - Mat3X x_unit_cam(3, num_points); - x_unit_cam = KK.inverse() * x_image; - - // Create normalized camera coordinates to be used as an input to the PnP - // function, instead of using NormalizeColumnVectors(&x_unit_cam). - *x_camera = x_unit_cam.block(0, 0, 2, num_points); - for (int i = 0; i < num_points; ++i) { - x_unit_cam.col(i).normalize(); - } - - // Create the 3D points in the camera system. - Mat X_camera(3, num_points); - for (int i = 0; i < num_points; ++i) { - X_camera.col(i) = X_distances(i) * x_unit_cam.col(i); - } - - // Apply the transformation to the camera 3D points - Mat translation_matrix(3, num_points); - translation_matrix.row(0).setConstant(T_input(0)); - translation_matrix.row(1).setConstant(T_input(1)); - translation_matrix.row(2).setConstant(T_input(2)); - - *X_world = R_input * X_camera + translation_matrix; - - // Create the expected result for comparison. - *R_expected = R_input.transpose(); - *T_expected = *R_expected * (-T_input); -}; - -TEST(AbsoluteOrientation, QuaternionSolution) { - int num_points = 4; - Mat X; - Mat Xp; - X = 100 * Mat::Random(3, num_points); - - // Create a random translation and rotation. - Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); - - Vec3 t_input; - t_input.setRandom(); - t_input = 100 * t_input; - - Mat translation_matrix(3, num_points); - translation_matrix.row(0).setConstant(t_input(0)); - translation_matrix.row(1).setConstant(t_input(1)); - translation_matrix.row(2).setConstant(t_input(2)); - - // Create the transformed 3D points Xp as Xp = R * X + t. - Xp = R_input * X + translation_matrix; - - // Output variables. - Mat3 R; - Vec3 t; - - AbsoluteOrientation(X, Xp, &R, &t); - - EXPECT_MATRIX_NEAR(t, t_input, 1e-6); - EXPECT_MATRIX_NEAR(R, R_input, 1e-8); -} - -TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { - // In this test only the translation and rotation are random. The image - // points are selected from a real case and are well conditioned. - Vec2i image_dimensions; - image_dimensions << 1600, 1200; - - Mat3 KK; - KK << 2796, 0, 804, - 0 , 2796, 641, - 0, 0, 1; - - // The real image points. - int num_points = 4; - Mat3X x_image(3, num_points); - x_image << 1164.06, 734.948, 749.599, 430.727, - 681.386, 844.59, 496.315, 580.775, - 1, 1, 1, 1; - - - // A vector of the 4 distances to the 3D points. - Vec X_distances = 100 * Vec::Random(num_points).array().abs(); - - // Create the random camera motion R and t that resection should recover. - Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); - - Vec3 T_input; - T_input.setRandom(); - T_input = 100 * T_input; - - // Create the camera system, also getting the expected result of the - // transformation. - Mat3 R_expected; - Vec3 T_expected; - Mat3X X_world; - Mat2X x_camera; - CreateCameraSystem(KK, x_image, X_distances, R_input, T_input, - &x_camera, &X_world, &R_expected, &T_expected); - - // Finally, run the code under test. - Mat3 R_output; - Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_ANSAR_DANIILIDIS); - - EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); - EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); - - // For now, the EPnP doesn't have a non-linear optimization step and so is - // not precise enough with only 4 points. - // - // TODO(jmichot): Reenable this test when there is nonlinear refinement. -#if 0 - R_output.setIdentity(); - T_output.setZero(); - - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_EPNP); - - EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); - EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);*/ -#endif -} - -// TODO(jmichot): Reduce the code duplication here with the code above. -TEST(EuclideanResection, Points6AllRandomInput) { - Mat3 KK; - KK << 2796, 0, 804, - 0 , 2796, 641, - 0, 0, 1; - - // Create random image points for a 1600x1200 image. - int w = 1600; - int h = 1200; - int num_points = 6; - Mat3X x_image(3, num_points); - x_image.row(0) = w * Vec::Random(num_points).array().abs(); - x_image.row(1) = h * Vec::Random(num_points).array().abs(); - x_image.row(2).setOnes(); - - // Normalized camera coordinates to be used as an input to the PnP function. - Mat2X x_camera; - Vec X_distances = 100 * Vec::Random(num_points).array().abs(); - - // Create the random camera motion R and t that resection should recover. - Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); - - Vec3 T_input; - T_input.setRandom(); - T_input = 100 * T_input; - - // Create the camera system. - Mat3 R_expected; - Vec3 T_expected; - Mat3X X_world; - CreateCameraSystem(KK, x_image, X_distances, R_input, T_input, - &x_camera, &X_world, &R_expected, &T_expected); - - // Test each of the resection methods. - { - Mat3 R_output; - Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_ANSAR_DANIILIDIS); - EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); - EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); - } - { - Mat3 R_output; - Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_EPNP); - EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); - EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); - } - { - Mat3 R_output; - Vec3 T_output; - EuclideanResection(x_image, X_world, KK, - &R_output, &T_output); - EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); - EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); - } -} -#endif diff --git a/extern/libmv/libmv/simple_pipeline/tracks.cc b/extern/libmv/libmv/simple_pipeline/tracks.cc deleted file mode 100644 index d5d009708ba..00000000000 --- a/extern/libmv/libmv/simple_pipeline/tracks.cc +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/simple_pipeline/tracks.h" - -#include -#include -#include - -#include "libmv/numeric/numeric.h" - -namespace libmv { - -Tracks::Tracks(const Tracks &other) { - markers_ = other.markers_; -} - -Tracks::Tracks(const vector &markers) : markers_(markers) {} - -void Tracks::Insert(int image, int track, double x, double y, double weight) { - // TODO(keir): Wow, this is quadratic for repeated insertions. Fix this by - // adding a smarter data structure like a set<>. - for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].image == image && - markers_[i].track == track) { - markers_[i].x = x; - markers_[i].y = y; - return; - } - } - Marker marker = { image, track, x, y, weight }; - markers_.push_back(marker); -} - -vector Tracks::AllMarkers() const { - return markers_; -} - -vector Tracks::MarkersInImage(int image) const { - vector markers; - for (int i = 0; i < markers_.size(); ++i) { - if (image == markers_[i].image) { - markers.push_back(markers_[i]); - } - } - return markers; -} - -vector Tracks::MarkersForTrack(int track) const { - vector markers; - for (int i = 0; i < markers_.size(); ++i) { - if (track == markers_[i].track) { - markers.push_back(markers_[i]); - } - } - return markers; -} - -vector Tracks::MarkersInBothImages(int image1, int image2) const { - vector markers; - for (int i = 0; i < markers_.size(); ++i) { - int image = markers_[i].image; - if (image == image1 || image == image2) - markers.push_back(markers_[i]); - } - return markers; -} - -vector Tracks::MarkersForTracksInBothImages(int image1, - int image2) const { - std::vector image1_tracks; - std::vector image2_tracks; - - for (int i = 0; i < markers_.size(); ++i) { - int image = markers_[i].image; - if (image == image1) { - image1_tracks.push_back(markers_[i].track); - } else if (image == image2) { - image2_tracks.push_back(markers_[i].track); - } - } - - std::sort(image1_tracks.begin(), image1_tracks.end()); - std::sort(image2_tracks.begin(), image2_tracks.end()); - - std::vector intersection; - std::set_intersection(image1_tracks.begin(), image1_tracks.end(), - image2_tracks.begin(), image2_tracks.end(), - std::back_inserter(intersection)); - - vector markers; - for (int i = 0; i < markers_.size(); ++i) { - if ((markers_[i].image == image1 || markers_[i].image == image2) && - std::binary_search(intersection.begin(), intersection.end(), - markers_[i].track)) { - markers.push_back(markers_[i]); - } - } - return markers; -} - -Marker Tracks::MarkerInImageForTrack(int image, int track) const { - for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].image == image && markers_[i].track == track) { - return markers_[i]; - } - } - Marker null = { -1, -1, -1, -1, 0.0 }; - return null; -} - -void Tracks::RemoveMarkersForTrack(int track) { - int size = 0; - for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].track != track) { - markers_[size++] = markers_[i]; - } - } - markers_.resize(size); -} - -void Tracks::RemoveMarker(int image, int track) { - int size = 0; - for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].image != image || markers_[i].track != track) { - markers_[size++] = markers_[i]; - } - } - markers_.resize(size); -} - -int Tracks::MaxImage() const { - // TODO(MatthiasF): maintain a max_image_ member (updated on Insert) - int max_image = 0; - for (int i = 0; i < markers_.size(); ++i) { - max_image = std::max(markers_[i].image, max_image); - } - return max_image; -} - -int Tracks::MaxTrack() const { - // TODO(MatthiasF): maintain a max_track_ member (updated on Insert) - int max_track = 0; - for (int i = 0; i < markers_.size(); ++i) { - max_track = std::max(markers_[i].track, max_track); - } - return max_track; -} - -int Tracks::NumMarkers() const { - return markers_.size(); -} - -void CoordinatesForMarkersInImage(const vector &markers, - int image, - Mat *coordinates) { - vector coords; - for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; - if (markers[i].image == image) { - coords.push_back(Vec2(marker.x, marker.y)); - } - } - coordinates->resize(2, coords.size()); - for (int i = 0; i < coords.size(); i++) { - coordinates->col(i) = coords[i]; - } -} - -} // namespace libmv diff --git a/extern/libmv/libmv/simple_pipeline/tracks.h b/extern/libmv/libmv/simple_pipeline/tracks.h deleted file mode 100644 index a54a43659b7..00000000000 --- a/extern/libmv/libmv/simple_pipeline/tracks.h +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_SIMPLE_PIPELINE_TRACKS_H_ -#define LIBMV_SIMPLE_PIPELINE_TRACKS_H_ - -#include "libmv/base/vector.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { - -/*! - A Marker is the 2D location of a tracked point in an image. - - \a x, \a y is the position of the marker in pixels from the top left corner - in the image identified by \a image. All markers for to the same target - form a track identified by a common \a track number. - - \a weight is used by bundle adjustment and weight means how much the - track affects on a final solution. - - \note Markers are typically aggregated with the help of the \l Tracks class. - - \sa Tracks -*/ -// TODO(sergey): Consider using comment for every member separately -// instead of having one giantic comment block. -struct Marker { - int image; - int track; - double x, y; - double weight; -}; - -/*! - The Tracks class stores \link Marker reconstruction markers \endlink. - - The Tracks container is intended as the store of correspondences between - images, which must get created before any 3D reconstruction can take place. - - The container has several fast lookups for queries typically needed for - structure from motion algorithms, such as \l MarkersForTracksInBothImages(). - - \sa Marker -*/ -class Tracks { - public: - Tracks() { } - - // Copy constructor for a tracks object. - Tracks(const Tracks &other); - - /// Construct a new tracks object using the given markers to start. - explicit Tracks(const vector &markers); - - /*! - Inserts a marker into the set. If there is already a marker for the given - \a image and \a track, the existing marker is replaced. If there is no - marker for the given \a image and \a track, a new one is added. - - \a image and \a track are the keys used to retrieve the markers with the - other methods in this class. - - \a weight is used by bundle adjustment and weight means how much the - track affects on a final solution. - - \note To get an identifier for a new track, use \l MaxTrack() + 1. - */ - // TODO(sergey): Consider using InsetWeightedMarker istead of using - // stupid default value? - void Insert(int image, int track, double x, double y, double weight = 1.0); - - /// Returns all the markers. - vector AllMarkers() const; - - /// Returns all the markers belonging to a track. - vector MarkersForTrack(int track) const; - - /// Returns all the markers visible in \a image. - vector MarkersInImage(int image) const; - - /// Returns all the markers visible in \a image1 and \a image2. - vector MarkersInBothImages(int image1, int image2) const; - - /*! - Returns the markers in \a image1 and \a image2 which have a common track. - - This is not the same as the union of the markers in \a image1 and \a - image2; each marker is for a track that appears in both images. - */ - vector MarkersForTracksInBothImages(int image1, int image2) const; - - /// Returns the marker in \a image belonging to \a track. - Marker MarkerInImageForTrack(int image, int track) const; - - /// Removes all the markers belonging to \a track. - void RemoveMarkersForTrack(int track); - - /// Removes the marker in \a image belonging to \a track. - void RemoveMarker(int image, int track); - - /// Returns the maximum image identifier used. - int MaxImage() const; - - /// Returns the maximum track identifier used. - int MaxTrack() const; - - /// Returns the number of markers. - int NumMarkers() const; - - private: - vector markers_; -}; - -void CoordinatesForMarkersInImage(const vector &markers, - int image, - Mat *coordinates); - -} // namespace libmv - -#endif // LIBMV_SIMPLE_PIPELINE_MARKERS_H_ diff --git a/extern/libmv/libmv/tracking/brute_region_tracker.cc b/extern/libmv/libmv/tracking/brute_region_tracker.cc deleted file mode 100644 index 4a2aef63a96..00000000000 --- a/extern/libmv/libmv/tracking/brute_region_tracker.cc +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/tracking/brute_region_tracker.h" - -#ifdef __SSE2__ -# include -#endif - -#include "libmv/base/aligned_malloc.h" -#include "libmv/image/image.h" -#include "libmv/image/convolve.h" -#include "libmv/image/correlation.h" -#include "libmv/image/sample.h" -#include "libmv/logging/logging.h" - -namespace libmv { -namespace { - -bool RegionIsInBounds(const FloatImage &image1, - double x, double y, - int half_window_size) { - // Check the minimum coordinates. - int min_x = floor(x) - half_window_size - 1; - int min_y = floor(y) - half_window_size - 1; - if (min_x < 0.0 || - min_y < 0.0) { - return false; - } - - // Check the maximum coordinates. - int max_x = ceil(x) + half_window_size + 1; - int max_y = ceil(y) + half_window_size + 1; - if (max_x > image1.cols() || - max_y > image1.rows()) { - return false; - } - - // Ok, we're good. - return true; -} - -#ifdef __SSE2__ - -// Compute the sub of absolute differences between the arrays "a" and "b". -// The array "a" is assumed to be 16-byte aligned, while "b" is not. The -// result is returned as the first and third elements of __m128i if -// interpreted as a 4-element 32-bit integer array. The SAD is the sum of the -// elements. -// -// The function requires size % 16 valid extra elements at the end of both "a" -// and "b", since the SSE load instructionst will pull in memory past the end -// of the arrays if their size is not a multiple of 16. -inline static __m128i SumOfAbsoluteDifferencesContiguousSSE( - const unsigned char *a, // aligned - const unsigned char *b, // not aligned - unsigned int size, - __m128i sad) { - // Do the bulk of the work as 16-way integer operations. - for (unsigned int j = 0; j < size / 16; j++) { - sad = _mm_add_epi32(sad, _mm_sad_epu8( _mm_load_si128 ((__m128i*)(a + 16 * j)), - _mm_loadu_si128((__m128i*)(b + 16 * j)))); - } - // Handle the trailing end. - // TODO(keir): Benchmark to verify that the below SSE is a win compared to a - // hand-rolled loop. It's not clear that the hand rolled loop would be slower - // than the potential cache miss when loading the immediate table below. - // - // An alternative to this version is to take a packet of all 1's then do a - // 128-bit shift. The issue is that the shift instruction needs an immediate - // amount rather than a variable amount, so the branch instruction here must - // remain. See _mm_srli_si128 and _mm_slli_si128. - unsigned int remainder = size % 16u; - if (remainder) { - unsigned int j = size / 16; - __m128i a_trail = _mm_load_si128 ((__m128i*)(a + 16 * j)); - __m128i b_trail = _mm_loadu_si128((__m128i*)(b + 16 * j)); - __m128i mask; - switch (remainder) { -#define X 0xff - case 1: mask = _mm_setr_epi8(X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 2: mask = _mm_setr_epi8(X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 3: mask = _mm_setr_epi8(X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 4: mask = _mm_setr_epi8(X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 5: mask = _mm_setr_epi8(X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 6: mask = _mm_setr_epi8(X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 7: mask = _mm_setr_epi8(X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 8: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 9: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0); break; - case 10: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0); break; - case 11: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0); break; - case 12: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0); break; - case 13: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0); break; - case 14: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0); break; - case 15: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0); break; -#undef X - } - sad = _mm_add_epi32(sad, _mm_sad_epu8(_mm_and_si128(mask, a_trail), - _mm_and_si128(mask, b_trail))); - } - return sad; -} -#endif - -// Computes the sum of absolute differences between pattern and image. Pattern -// must be 16-byte aligned, and the stride must be a multiple of 16. The image -// does pointer does not have to be aligned. -int SumOfAbsoluteDifferencesContiguousImage( - const unsigned char *pattern, - unsigned int pattern_width, - unsigned int pattern_height, - unsigned int pattern_stride, - const unsigned char *image, - unsigned int image_stride) { -#ifdef __SSE2__ - // TODO(keir): Add interleaved accumulation, where accumulation is done into - // two or more SSE registers that then get combined at the end. This reduces - // instruction dependency; in Eigen's squared norm code, splitting the - // accumulation produces a ~2x speedup. It's not clear it will help here, - // where the number of SSE instructions in the inner loop is smaller. - __m128i sad = _mm_setzero_si128(); - for (int r = 0; r < pattern_height; ++r) { - sad = SumOfAbsoluteDifferencesContiguousSSE(&pattern[pattern_stride * r], - &image[image_stride * r], - pattern_width, - sad); - } - return _mm_cvtsi128_si32( - _mm_add_epi32(sad, - _mm_shuffle_epi32(sad, _MM_SHUFFLE(3, 0, 1, 2)))); -#else - int sad = 0; - for (int r = 0; r < pattern_height; ++r) { - for (int c = 0; c < pattern_width; ++c) { - sad += abs(pattern[pattern_stride * r + c] - image[image_stride * r + c]); - } - } - return sad; -#endif -} - -// Sample a region of size width, height centered at x,y in image, converting -// from float to byte in the process. Samples from the first channel. Puts -// result into *pattern. -void SampleRectangularPattern(const FloatImage &image, - double x, double y, - int width, - int height, - int pattern_stride, - unsigned char *pattern) { - // There are two cases for width and height: even or odd. If it's odd, then - // the bounds [-width / 2, width / 2] works as expected. However, for even, - // this results in one extra access past the end. So use < instead of <= in - // the loops below, but increase the end limit by one in the odd case. - int end_width = (width / 2) + (width % 2); - int end_height = (height / 2) + (height % 2); - for (int r = -height / 2; r < end_height; ++r) { - for (int c = -width / 2; c < end_width; ++c) { - pattern[pattern_stride * (r + height / 2) + c + width / 2] = - SampleLinear(image, y + r, x + c, 0) * 255.0; - } - } -} - -// Returns x rounded up to the nearest multiple of alignment. -inline int PadToAlignment(int x, int alignment) { - if (x % alignment != 0) { - x += alignment - (x % alignment); - } - return x; -} - -// Sample a region centered at x,y in image with size extending by half_width -// from x. Samples from the first channel. The resulting array is placed in -// *pattern, and the stride, which will be a multiple of 16 if SSE is enabled, -// is returned in *pattern_stride. -// -// NOTE: Caller must free *pattern with aligned_malloc() from above. -void SampleSquarePattern(const FloatImage &image, - double x, double y, - int half_width, - unsigned char **pattern, - int *pattern_stride) { - int width = 2 * half_width + 1; - // Allocate an aligned block with padding on the end so each row of the - // pattern starts on a 16-byte boundary. - *pattern_stride = PadToAlignment(width, 16); - int pattern_size_bytes = *pattern_stride * width; - *pattern = static_cast( - aligned_malloc(pattern_size_bytes, 16)); - SampleRectangularPattern(image, x, y, width, width, - *pattern_stride, - *pattern); -} - -// NOTE: Caller must free *image with aligned_malloc() from above. -void FloatArrayToByteArrayWithPadding(const FloatImage &float_image, - unsigned char **image, - int *image_stride) { - // Allocate enough so that accessing 16 elements past the end is fine. - *image_stride = float_image.Width() + 16; - *image = static_cast( - aligned_malloc(*image_stride * float_image.Height(), 16)); - for (int i = 0; i < float_image.Height(); ++i) { - for (int j = 0; j < float_image.Width(); ++j) { - (*image)[*image_stride * i + j] = - static_cast(255.0 * float_image(i, j, 0)); - } - } -} - -} // namespace - -// TODO(keir): Compare the "sharpness" of the peak around the best pixel. It's -// probably worth plotting a few examples to see what the histogram of SAD -// values for every hypothesis looks like. -// -// TODO(keir): Priority queue for multiple hypothesis. -bool BruteRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { - if (!RegionIsInBounds(image1, x1, y1, half_window_size)) { - LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1 - << ", hw=" << half_window_size << "."; - return false; - } - int pattern_width = 2 * half_window_size + 1; - - Array3Df image_and_gradient1; - Array3Df image_and_gradient2; - BlurredImageAndDerivativesChannels(image1, 0.9, &image_and_gradient1); - BlurredImageAndDerivativesChannels(image2, 0.9, &image_and_gradient2); - - // Sample the pattern to get it aligned to an image grid. - unsigned char *pattern; - int pattern_stride; - SampleSquarePattern(image_and_gradient1, x1, y1, half_window_size, - &pattern, - &pattern_stride); - - // Convert the search area directly to bytes without sampling. - unsigned char *search_area; - int search_area_stride; - FloatArrayToByteArrayWithPadding(image_and_gradient2, &search_area, - &search_area_stride); - - // Try all possible locations inside the search area. Yes, everywhere. - int best_i = -1, best_j = -1, best_sad = INT_MAX; - for (int i = 0; i < image2.Height() - pattern_width; ++i) { - for (int j = 0; j < image2.Width() - pattern_width; ++j) { - int sad = SumOfAbsoluteDifferencesContiguousImage(pattern, - pattern_width, - pattern_width, - pattern_stride, - search_area + search_area_stride * i + j, - search_area_stride); - if (sad < best_sad) { - best_i = i; - best_j = j; - best_sad = sad; - } - } - } - - CHECK_NE(best_i, -1); - CHECK_NE(best_j, -1); - - aligned_free(pattern); - aligned_free(search_area); - - if (best_sad == INT_MAX) { - LG << "Hit INT_MAX in SAD; failing."; - return false; - } - - *x2 = best_j + half_window_size; - *y2 = best_i + half_window_size; - - // Calculate the shift done by the fine tracker. - double dx2 = *x2 - x1; - double dy2 = *y2 - y1; - double fine_shift = sqrt(dx2 * dx2 + dy2 * dy2); - LG << "Brute shift: dx=" << dx2 << " dy=" << dy2 << ", d=" << fine_shift; - - if (minimum_correlation <= 0) { - // No correlation checking requested; nothing else to do. - LG << "No correlation checking; returning success. best_sad: " << best_sad; - return true; - } - - Array3Df image_and_gradient1_sampled, image_and_gradient2_sampled; - SamplePattern(image_and_gradient1, x1, y1, half_window_size, 3, - &image_and_gradient1_sampled); - SamplePattern(image_and_gradient2, *x2, *y2, half_window_size, 3, - &image_and_gradient2_sampled); - - // Compute the Pearson product-moment correlation coefficient to check - // for sanity. - double correlation = PearsonProductMomentCorrelation( - image_and_gradient1_sampled, - image_and_gradient2_sampled); - - LG << "Final correlation: " << correlation; - - if (correlation < minimum_correlation) { - LG << "Correlation " << correlation << " greater than " - << minimum_correlation << "; bailing."; - return false; - } - return true; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/tracking/brute_region_tracker.h b/extern/libmv/libmv/tracking/brute_region_tracker.h deleted file mode 100644 index a699c42ee92..00000000000 --- a/extern/libmv/libmv/tracking/brute_region_tracker.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_REGION_TRACKING_BRUTE_REGION_TRACKER_H_ -#define LIBMV_REGION_TRACKING_BRUTE_REGION_TRACKER_H_ - -#include "libmv/image/image.h" -#include "libmv/tracking/region_tracker.h" - -namespace libmv { - -struct BruteRegionTracker : public RegionTracker { - BruteRegionTracker() - : half_window_size(4), - minimum_correlation(0.78) {} - - virtual ~BruteRegionTracker() {} - - // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; - - // No point in creating getters or setters. - int half_window_size; - double minimum_correlation; -}; - -} // namespace libmv - -#endif // LIBMV_REGION_TRACKING_BRUTE_REGION_TRACKER_H_ diff --git a/extern/libmv/libmv/tracking/brute_region_tracker_test.cc b/extern/libmv/libmv/tracking/brute_region_tracker_test.cc deleted file mode 100644 index 9014797c7cf..00000000000 --- a/extern/libmv/libmv/tracking/brute_region_tracker_test.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/tracking/brute_region_tracker.h" -#include "libmv/image/image.h" -#include "libmv/logging/logging.h" -#include "testing/testing.h" - -namespace libmv { -namespace { - -TEST(KltRegionTracker, Track) { - Array3Df image1(51, 51); - image1.Fill(0); - - Array3Df image2(image1); - - int x0 = 25, y0 = 25; - int dx = 3, dy = 2; - image1(y0, x0) = 1.0f; - image2(y0 + dy, x0 + dx) = 1.0; - - double x1 = x0; - double y1 = y0; - - BruteRegionTracker tracker; - EXPECT_TRUE(tracker.Track(image1, image2, x0, y0, &x1, &y1)); - - EXPECT_NEAR(x1, x0 + dx, 0.001); - EXPECT_NEAR(y1, y0 + dy, 0.001); -} - -} // namespace -} // namespace libmv diff --git a/extern/libmv/libmv/tracking/hybrid_region_tracker.cc b/extern/libmv/libmv/tracking/hybrid_region_tracker.cc deleted file mode 100644 index ea3b0f5bfc0..00000000000 --- a/extern/libmv/libmv/tracking/hybrid_region_tracker.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/tracking/hybrid_region_tracker.h" - -#include "libmv/image/image.h" -#include "libmv/image/convolve.h" -#include "libmv/image/sample.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -bool HybridRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { - double x2_coarse = *x2; - double y2_coarse = *y2; - if (!coarse_tracker_->Track(image1, image2, x1, y1, &x2_coarse, &y2_coarse)) { - LG << "Coarse tracker failed."; - return false; - } - - double x2_fine = x2_coarse; - double y2_fine = y2_coarse; - if (!fine_tracker_->Track(image1, image2, x1, y1, &x2_fine, &y2_fine)) { - LG << "Fine tracker failed."; - return false; - } - - // Calculate the shift done by the fine tracker. - double dx2 = x2_coarse - x2_fine; - double dy2 = y2_coarse - y2_fine; - double fine_shift = sqrt(dx2 * dx2 + dy2 * dy2); - - LG << "Refinement: dx=" << dx2 << " dy=" << dy2 << ", d=" << fine_shift; - - // If the fine tracker shifted the window by more than a pixel, then - // something bad probably happened and we should give up tracking. - if (fine_shift < 2.0) { - LG << "Refinement small enough; success."; - *x2 = x2_fine; - *y2 = y2_fine; - return true; - } - LG << "Refinement was too big; failing."; - return false; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/tracking/hybrid_region_tracker.h b/extern/libmv/libmv/tracking/hybrid_region_tracker.h deleted file mode 100644 index 967d2afd1e5..00000000000 --- a/extern/libmv/libmv/tracking/hybrid_region_tracker.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_REGION_TRACKING_HYBRID_REGION_TRACKER_H_ -#define LIBMV_REGION_TRACKING_HYBRID_REGION_TRACKER_H_ - -#include "libmv/image/image.h" -#include "libmv/base/scoped_ptr.h" -#include "libmv/tracking/region_tracker.h" - -namespace libmv { - -// TODO(keir): Documentation! -class HybridRegionTracker : public RegionTracker { - public: - HybridRegionTracker(RegionTracker *coarse_tracker, - RegionTracker *fine_tracker) - : coarse_tracker_(coarse_tracker), - fine_tracker_(fine_tracker) {} - - virtual ~HybridRegionTracker() {} - - // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; - - scoped_ptr coarse_tracker_; - scoped_ptr fine_tracker_; -}; - -} // namespace libmv - -#endif // LIBMV_REGION_TRACKING_HYBRID_REGION_TRACKER_H_ diff --git a/extern/libmv/libmv/tracking/kalman_filter.h b/extern/libmv/libmv/tracking/kalman_filter.h deleted file mode 100644 index 9841f0e912c..00000000000 --- a/extern/libmv/libmv/tracking/kalman_filter.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2014 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_TRACKING_KALMAN_FILTER_H_ - -#include "libmv/numeric/numeric.h" - -namespace mv { - -// A Kalman filter with order N and observation size K. -template -class KalmanFilter { - public: - struct State { - Eigen::Matrix mean; - Eigen::Matrix covariance; - }; - - // Initialize from row-major data; convenient for constant initializers. - KalmanFilter(const T* state_transition_data, - const T* observation_data, - const T* process_covariance_data, - const T* default_measurement_covariance_data) - : state_transition_matrix_( - Eigen::Matrix(state_transition_data)), - observation_matrix_( - Eigen::Matrix(observation_data)), - process_covariance_( - Eigen::Matrix(process_covariance_data)), - default_measurement_covariance_( - Eigen::Matrix( - default_measurement_covariance_data)) { - } - - KalmanFilter( - const Eigen::Matrix &state_transition_matrix, - const Eigen::Matrix &observation_matrix, - const Eigen::Matrix &process_covariance, - const Eigen::Matrix &default_measurement_covariance) - : state_transition_matrix_(state_transition_matrix), - observation_matrix_(observation_matrix), - process_covariance_(process_covariance), - default_measurement_covariance_(default_measurement_covariance) { - } - - // Advances the system according to the current state estimate. - void Step(State *state) const { - state->mean = state_transition_matrix_ * state->mean; - state->covariance = state_transition_matrix_ * - state->covariance * - state_transition_matrix_.transpose() + - process_covariance_; - } - - // Updates a state with a new measurement. - void Update(const Eigen::Matrix &measurement_mean, - const Eigen::Matrix &measurement_covariance, - State *state) const { - // Calculate the innovation, which is a distribution over prediction error. - Eigen::Matrix innovation_mean = measurement_mean - - observation_matrix_ * - state->mean; - Eigen::Matrix innovation_covariance = - observation_matrix_ * - state->covariance * - observation_matrix_.transpose() + - measurement_covariance; - - // Calculate the Kalman gain. - Eigen::Matrix kalman_gain = state->covariance * - observation_matrix_.transpose() * - innovation_covariance.inverse(); - - // Update the state mean and covariance. - state->mean += kalman_gain * innovation_mean; - state->covariance = (Eigen::Matrix::Identity() - - kalman_gain * observation_matrix_) * - state->covariance; - } - - void Update(State *state, - const Eigen::Matrix &measurement_mean) const { - Update(state, measurement_mean, default_measurement_covariance_); - } - - private: - const Eigen::Matrix state_transition_matrix_; - const Eigen::Matrix observation_matrix_; - const Eigen::Matrix process_covariance_; - const Eigen::Matrix default_measurement_covariance_; -}; - -} // namespace mv - -#endif // LIBMV_TRACKING_KALMAN_FILTER_H_ diff --git a/extern/libmv/libmv/tracking/klt_region_tracker.cc b/extern/libmv/libmv/tracking/klt_region_tracker.cc deleted file mode 100644 index dbbf9f0b996..00000000000 --- a/extern/libmv/libmv/tracking/klt_region_tracker.cc +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2007, 2008, 2009, 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/tracking/klt_region_tracker.h" - -#include "libmv/logging/logging.h" -#include "libmv/image/image.h" -#include "libmv/image/convolve.h" -#include "libmv/image/sample.h" - -namespace libmv { - -// Compute the gradient matrix noted by Z and the error vector e. See Good -// Features to Track. -// -// TODO(keir): The calls to SampleLinear() do boundary checking that should -// instead happen outside the loop. Since this is the innermost loop, the extra -// bounds checking hurts performance. -static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, - const Array3Df &image_and_gradient2, - double x1, double y1, - double x2, double y2, - int half_width, - float *gxx, - float *gxy, - float *gyy, - float *ex, - float *ey) { - *gxx = *gxy = *gyy = 0; - *ex = *ey = 0; - for (int r = -half_width; r <= half_width; ++r) { - for (int c = -half_width; c <= half_width; ++c) { - float xx1 = x1 + c; - float yy1 = y1 + r; - float xx2 = x2 + c; - float yy2 = y2 + r; - float I = SampleLinear(image_and_gradient1, yy1, xx1, 0); - float J = SampleLinear(image_and_gradient2, yy2, xx2, 0); - float gx = SampleLinear(image_and_gradient2, yy2, xx2, 1); - float gy = SampleLinear(image_and_gradient2, yy2, xx2, 2); - *gxx += gx * gx; - *gxy += gx * gy; - *gyy += gy * gy; - *ex += (I - J) * gx; - *ey += (I - J) * gy; - } - } -} - -static bool RegionIsInBounds(const FloatImage &image1, - double x, double y, - int half_window_size) { - // Check the minimum coordinates. - int min_x = floor(x) - half_window_size - 1; - int min_y = floor(y) - half_window_size - 1; - if (min_x < 0.0 || - min_y < 0.0) { - return false; - } - - // Check the maximum coordinates. - int max_x = ceil(x) + half_window_size + 1; - int max_y = ceil(y) + half_window_size + 1; - if (max_x > image1.cols() || - max_y > image1.rows()) { - return false; - } - - // Ok, we're good. - return true; -} - -bool KltRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { - if (!RegionIsInBounds(image1, x1, y1, half_window_size)) { - LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1 - << ", hw=" << half_window_size << "."; - return false; - } - - Array3Df image_and_gradient1; - Array3Df image_and_gradient2; - BlurredImageAndDerivativesChannels(image1, sigma, &image_and_gradient1); - BlurredImageAndDerivativesChannels(image2, sigma, &image_and_gradient2); - - int i; - float dx = 0, dy = 0; - for (i = 0; i < max_iterations; ++i) { - // Check that the entire image patch is within the bounds of the images. - if (!RegionIsInBounds(image2, *x2, *y2, half_window_size)) { - LG << "Fell out of image2's window with x2=" << *x2 << ", y2=" << *y2 - << ", hw=" << half_window_size << "."; - return false; - } - - // Compute gradient matrix and error vector. - float gxx, gxy, gyy, ex, ey; - ComputeTrackingEquation(image_and_gradient1, - image_and_gradient2, - x1, y1, - *x2, *y2, - half_window_size, - &gxx, &gxy, &gyy, &ex, &ey); - - // Solve the tracking equation - // - // [gxx gxy] [dx] = [ex] - // [gxy gyy] [dy] = [ey] - // - // for dx and dy. Borrowed from Stan Birchfield's KLT implementation. - float determinant = gxx * gyy - gxy * gxy; - dx = (gyy * ex - gxy * ey) / determinant; - dy = (gxx * ey - gxy * ex) / determinant; - - // Update the position with the solved displacement. - *x2 += dx; - *y2 += dy; - - // Check for the quality of the solution, but not until having already - // updated the position with our best estimate. The reason to do the update - // anyway is that the user already knows the position is bad, so we may as - // well try our best. - if (determinant < min_determinant) { - // The determinant, which indicates the trackiness of the point, is too - // small, so fail out. - LG << "Determinant " << determinant << " is too small; failing tracking."; - return false; - } - LG << "x=" << *x2 << ", y=" << *y2 << ", dx=" << dx << ", dy=" << dy - << ", det=" << determinant; - - // If the update is small, then we probably found the target. - if (dx * dx + dy * dy < min_update_squared_distance) { - LG << "Successful track in " << i << " iterations."; - return true; - } - } - // Getting here means we hit max iterations, so tracking failed. - LG << "Too many iterations; max is set to " << max_iterations << "."; - return false; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/tracking/klt_region_tracker.h b/extern/libmv/libmv/tracking/klt_region_tracker.h deleted file mode 100644 index 43977757084..00000000000 --- a/extern/libmv/libmv/tracking/klt_region_tracker.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2007, 2008, 2009, 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_REGION_TRACKING_KLT_REGION_TRACKER_H_ -#define LIBMV_REGION_TRACKING_KLT_REGION_TRACKER_H_ - -#include "libmv/image/image.h" -#include "libmv/tracking/region_tracker.h" - -namespace libmv { - -struct KltRegionTracker : public RegionTracker { - KltRegionTracker() - : half_window_size(4), - max_iterations(16), - min_determinant(1e-6), - min_update_squared_distance(1e-6), - sigma(0.9) {} - - virtual ~KltRegionTracker() {} - - // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; - - // No point in creating getters or setters. - int half_window_size; - int max_iterations; - double min_determinant; - double min_update_squared_distance; - double sigma; -}; - -} // namespace libmv - -#endif // LIBMV_REGION_TRACKING_KLT_REGION_TRACKER_H_ diff --git a/extern/libmv/libmv/tracking/klt_region_tracker_test.cc b/extern/libmv/libmv/tracking/klt_region_tracker_test.cc deleted file mode 100644 index 07d5d6500e3..00000000000 --- a/extern/libmv/libmv/tracking/klt_region_tracker_test.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/tracking/klt_region_tracker.h" -#include "libmv/image/image.h" -#include "testing/testing.h" - -namespace libmv { -namespace { - -TEST(KltRegionTracker, Track) { - Array3Df image1(51, 51); - image1.Fill(0); - - Array3Df image2(image1); - - int x0 = 25, y0 = 25; - int dx = 3, dy = 2; - image1(y0, x0) = 1.0f; - image2(y0 + dy, x0 + dx) = 1.0f; - - double x1 = x0; - double y1 = y0; - - KltRegionTracker tracker; - tracker.half_window_size = 6; - EXPECT_TRUE(tracker.Track(image1, image2, x0, y0, &x1, &y1)); - - EXPECT_NEAR(x1, x0 + dx, 0.001); - EXPECT_NEAR(y1, y0 + dy, 0.001); -} - -} // namespace -} // namespace libmv diff --git a/extern/libmv/libmv/tracking/pyramid_region_tracker.cc b/extern/libmv/libmv/tracking/pyramid_region_tracker.cc deleted file mode 100644 index 4db501050f3..00000000000 --- a/extern/libmv/libmv/tracking/pyramid_region_tracker.cc +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2007, 2008, 2009, 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/tracking/pyramid_region_tracker.h" - -#include - -#include "libmv/image/convolve.h" -#include "libmv/image/image.h" -#include "libmv/image/sample.h" -#include "libmv/logging/logging.h" - -namespace libmv { - -static void MakePyramid(const FloatImage &image, int num_levels, - std::vector *pyramid) { - pyramid->resize(num_levels); - (*pyramid)[0] = image; - for (int i = 1; i < num_levels; ++i) { - DownsampleChannelsBy2((*pyramid)[i - 1], &(*pyramid)[i]); - } -} - -bool PyramidRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { - // Shrink the guessed x and y location to match the coarsest level + 1 (which - // when gets corrected in the loop). - *x2 /= pow(2., num_levels_); - *y2 /= pow(2., num_levels_); - - // Create all the levels of the pyramid, since tracking has to happen from - // the coarsest to finest levels, which means holding on to all levels of the - // pyraid at once. - std::vector pyramid1(num_levels_); - std::vector pyramid2(num_levels_); - MakePyramid(image1, num_levels_, &pyramid1); - MakePyramid(image2, num_levels_, &pyramid2); - - for (int i = num_levels_ - 1; i >= 0; --i) { - // Position in the first image at pyramid level i. - double xx = x1 / pow(2., i); - double yy = y1 / pow(2., i); - - // Guess the new tracked position is where the last level tracked to. - *x2 *= 2; - *y2 *= 2; - - // Save the previous best guess for this level, since tracking within this - // level might fail. - double x2_new = *x2; - double y2_new = *y2; - - // Track the point on this level with the base tracker. - LG << "Tracking on level " << i; - bool succeeded = tracker_->Track(pyramid1[i], pyramid2[i], xx, yy, - &x2_new, &y2_new); - - if (!succeeded) { - if (i == 0) { - // Only fail on the highest-resolution level, because a failure on a - // coarse level does not mean failure at a lower level (consider - // out-of-bounds conditions). - LG << "Finest level of pyramid tracking failed; failing."; - return false; - } - - LG << "Failed to track at level " << i << "; restoring guess."; - } else { - // Only save the update if the track for this level succeeded. This is a - // bit of a hack; the jury remains out on whether this is better than - // re-using the previous failed-attempt. - *x2 = x2_new; - *y2 = y2_new; - } - } - return true; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/tracking/pyramid_region_tracker.h b/extern/libmv/libmv/tracking/pyramid_region_tracker.h deleted file mode 100644 index 1f9675469f4..00000000000 --- a/extern/libmv/libmv/tracking/pyramid_region_tracker.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_ -#define LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_ - -#include "libmv/image/image.h" -#include "libmv/base/scoped_ptr.h" -#include "libmv/tracking/region_tracker.h" - -namespace libmv { - -class PyramidRegionTracker : public RegionTracker { - public: - PyramidRegionTracker(RegionTracker *tracker, int num_levels) - : tracker_(tracker), num_levels_(num_levels) {} - - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; - private: - scoped_ptr tracker_; - int num_levels_; -}; - -} // namespace libmv - -#endif // LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_ diff --git a/extern/libmv/libmv/tracking/pyramid_region_tracker_test.cc b/extern/libmv/libmv/tracking/pyramid_region_tracker_test.cc deleted file mode 100644 index d90a1012237..00000000000 --- a/extern/libmv/libmv/tracking/pyramid_region_tracker_test.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/tracking/pyramid_region_tracker.h" -#include "libmv/tracking/klt_region_tracker.h" -#include "libmv/image/image.h" -#include "testing/testing.h" - -namespace libmv { -namespace { - -TEST(PyramidKltRegionTracker, Track) { - Array3Df image1(100, 100); - image1.Fill(0); - - Array3Df image2(image1); - - int x1 = 25, y1 = 25; - image1(y1 + 0, x1 + 0) = 1.0f; - image1(y1 + 0, x1 + 1) = 1.0f; - image1(y1 + 1, x1 + 0) = 1.0f; - image1(y1 + 1, x1 + 1) = 1.0f; - - // Make the displacement too large for a single-level KLT. - int x2 = x1 + 6, y2 = y1 + 5; - image2(y2 + 0, x2 + 0) = 1.0f; - image2(y2 + 0, x2 + 1) = 1.0f; - image2(y2 + 1, x2 + 0) = 1.0f; - image2(y2 + 1, x2 + 1) = 1.0f; - - // Use a small 5x5 tracking region. - int half_window_size = 3; - - // Ensure that the track doesn't work with one level of KLT. - { - double x2_actual = x1; - double y2_actual = y1; - - KltRegionTracker tracker; - tracker.half_window_size = half_window_size; - EXPECT_FALSE(tracker.Track(image1, image2, x1, y1, - &x2_actual, &y2_actual)); - } - - // Verify that it works with the pyramid tracker. - { - double x2_actual = x1; - double y2_actual = y1; - - KltRegionTracker *klt_tracker = new KltRegionTracker; - klt_tracker->half_window_size = half_window_size; - - PyramidRegionTracker tracker(klt_tracker, 3); - EXPECT_TRUE(tracker.Track(image1, image2, x1, y1, - &x2_actual, &y2_actual)); - - EXPECT_NEAR(x2_actual, x2, 0.001); - EXPECT_NEAR(y2_actual, y2, 0.001); - } -} - -} // namespace -} // namespace libmv diff --git a/extern/libmv/libmv/tracking/region_tracker.h b/extern/libmv/libmv/tracking/region_tracker.h deleted file mode 100644 index 4f7574df1a3..00000000000 --- a/extern/libmv/libmv/tracking/region_tracker.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_TRACKING_TRACKER_H_ -#define LIBMV_TRACKING_TRACKER_H_ - -#include "libmv/image/image.h" - -namespace libmv { - -class RegionTracker { - public: - RegionTracker() {} - virtual ~RegionTracker() {} - - /*! - Track a point from \a image1 to \a image2. - - \a x2, \a y2 should start out as a best guess for the position in \a - image2. If no guess is available, (\a x1, \a y1) is a good start. Returns - true on success, false otherwise - */ - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const = 0; -}; - -} // namespace libmv - -#endif // LIBMV_CORRESPONDENCE_TRACKER_H_ diff --git a/extern/libmv/libmv/tracking/retrack_region_tracker.cc b/extern/libmv/libmv/tracking/retrack_region_tracker.cc deleted file mode 100644 index 4d230086d28..00000000000 --- a/extern/libmv/libmv/tracking/retrack_region_tracker.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/tracking/retrack_region_tracker.h" - -#include -#include - -namespace libmv { - -bool RetrackRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { - // Track forward, getting x2 and y2. - if (!tracker_->Track(image1, image2, x1, y1, x2, y2)) { - return false; - } - // Now track x2 and y2 backward, to get xx1 and yy1 which, if the track is - // good, should match x1 and y1 (but may not if the track is bad). - double xx1 = *x2, yy1 = *x2; - if (!tracker_->Track(image2, image1, *x2, *y2, &xx1, &yy1)) { - return false; - } - double dx = xx1 - x1; - double dy = yy1 - y1; - return sqrt(dx * dx + dy * dy) < tolerance_; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/tracking/retrack_region_tracker.h b/extern/libmv/libmv/tracking/retrack_region_tracker.h deleted file mode 100644 index ab05f320834..00000000000 --- a/extern/libmv/libmv/tracking/retrack_region_tracker.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_ -#define LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_ - -#include "libmv/image/image.h" -#include "libmv/base/scoped_ptr.h" -#include "libmv/tracking/region_tracker.h" - -namespace libmv { - -// A region tracker that tries tracking backwards and forwards, rejecting a -// track that doesn't track backwards to the starting point. -class RetrackRegionTracker : public RegionTracker { - public: - RetrackRegionTracker(RegionTracker *tracker, double tolerance) - : tracker_(tracker), tolerance_(tolerance) {} - - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; - private: - scoped_ptr tracker_; - double tolerance_; -}; - -} // namespace libmv - -#endif // LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_ diff --git a/extern/libmv/libmv/tracking/track_region.cc b/extern/libmv/libmv/tracking/track_region.cc deleted file mode 100644 index ef6dac65236..00000000000 --- a/extern/libmv/libmv/tracking/track_region.cc +++ /dev/null @@ -1,1601 +0,0 @@ -// Copyright (c) 2012 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// -// Author: mierle@gmail.com (Keir Mierle) -// -// TODO(keir): While this tracking code works rather well, it has some -// outragous inefficiencies. There is probably a 5-10x speedup to be had if a -// smart coder went through the TODO's and made the suggested performance -// enhancements. - -// Necessary for M_E when building with MSVC. -#define _USE_MATH_DEFINES - -#include "libmv/tracking/track_region.h" - -#include -#include -#include -#include "ceres/ceres.h" -#include "libmv/logging/logging.h" -#include "libmv/image/image.h" -#include "libmv/image/sample.h" -#include "libmv/image/convolve.h" -#include "libmv/multiview/homography.h" -#include "libmv/numeric/numeric.h" - -// Expand the Jet functionality of Ceres to allow mixed numeric/autodiff. -// -// TODO(keir): Push this (or something similar) into upstream Ceres. -namespace ceres { - -// A jet traits class to make it easier to work with mixed auto / numeric diff. -template -struct JetOps { - static bool IsScalar() { - return true; - } - static T GetScalar(const T& t) { - return t; - } - static void SetScalar(const T& scalar, T* t) { - *t = scalar; - } - static void ScaleDerivative(double scale_by, T *value) { - // For double, there is no derivative to scale. - (void) scale_by; // Ignored. - (void) value; // Ignored. - } -}; - -template -struct JetOps > { - static bool IsScalar() { - return false; - } - static T GetScalar(const Jet& t) { - return t.a; - } - static void SetScalar(const T& scalar, Jet* t) { - t->a = scalar; - } - static void ScaleDerivative(double scale_by, Jet *value) { - value->v *= scale_by; - } -}; - -template -struct Chain { - static ArgumentType Rule(const FunctionType &f, - const FunctionType dfdx[kNumArgs], - const ArgumentType x[kNumArgs]) { - // In the default case of scalars, there's nothing to do since there are no - // derivatives to propagate. - (void) dfdx; // Ignored. - (void) x; // Ignored. - return f; - } -}; - -// XXX Add documentation here! -template -struct Chain > { - static Jet Rule(const FunctionType &f, - const FunctionType dfdx[kNumArgs], - const Jet x[kNumArgs]) { - // x is itself a function of another variable ("z"); what this function - // needs to return is "f", but with the derivative with respect to z - // attached to the jet. So combine the derivative part of x's jets to form - // a Jacobian matrix between x and z (i.e. dx/dz). - Eigen::Matrix dxdz; - for (int i = 0; i < kNumArgs; ++i) { - dxdz.row(i) = x[i].v.transpose(); - } - - // Map the input gradient dfdx into an Eigen row vector. - Eigen::Map > - vector_dfdx(dfdx, 1, kNumArgs); - - // Now apply the chain rule to obtain df/dz. Combine the derivative with - // the scalar part to obtain f with full derivative information. - Jet jet_f; - jet_f.a = f; - jet_f.v = vector_dfdx.template cast() * dxdz; // Also known as dfdz. - return jet_f; - } -}; - -} // namespace ceres - -namespace libmv { - -using ceres::Jet; -using ceres::JetOps; -using ceres::Chain; - -TrackRegionOptions::TrackRegionOptions() - : mode(TRANSLATION), - minimum_correlation(0), - max_iterations(20), - use_esm(true), - use_brute_initialization(true), - use_normalized_intensities(false), - sigma(0.9), - num_extra_points(0), - regularization_coefficient(0.0), - minimum_corner_shift_tolerance_pixels(0.005), - image1_mask(NULL) { -} - -namespace { - -// TODO(keir): Consider adding padding. -template -bool InBounds(const FloatImage &image, - const T &x, - const T &y) { - return 0.0 <= x && x < image.Width() && - 0.0 <= y && y < image.Height(); -} - -bool AllInBounds(const FloatImage &image, - const double *x, - const double *y) { - for (int i = 0; i < 4; ++i) { - if (!InBounds(image, x[i], y[i])) { - return false; - } - } - return true; -} - -// Sample the image at position (x, y) but use the gradient, if present, to -// propagate derivatives from x and y. This is needed to integrate the numeric -// image gradients with Ceres's autodiff framework. -template -static T SampleWithDerivative(const FloatImage &image_and_gradient, - const T &x, - const T &y) { - float scalar_x = JetOps::GetScalar(x); - float scalar_y = JetOps::GetScalar(y); - - // Note that sample[1] and sample[2] will be uninitialized in the scalar - // case, but that is not an issue because the Chain::Rule below will not read - // the uninitialized values. - float sample[3]; - if (JetOps::IsScalar()) { - // For the scalar case, only sample the image. - sample[0] = SampleLinear(image_and_gradient, scalar_y, scalar_x, 0); - } else { - // For the derivative case, sample the gradient as well. - SampleLinear(image_and_gradient, scalar_y, scalar_x, sample); - } - T xy[2] = { x, y }; - return Chain::Rule(sample[0], sample + 1, xy); -} - -template -class TerminationCheckingCallback : public ceres::IterationCallback { - public: - TerminationCheckingCallback(const TrackRegionOptions &options, - const FloatImage& image2, - const Warp &warp, - const double *x1, const double *y1) - : options_(options), image2_(image2), warp_(warp), x1_(x1), y1_(y1), - have_last_successful_step_(false) {} - - virtual ceres::CallbackReturnType operator()( - const ceres::IterationSummary& summary) { - // If the step wasn't successful, there's nothing to do. - if (!summary.step_is_successful) { - return ceres::SOLVER_CONTINUE; - } - // Warp the original 4 points with the current warp into image2. - double x2[4]; - double y2[4]; - for (int i = 0; i < 4; ++i) { - warp_.Forward(warp_.parameters, x1_[i], y1_[i], x2 + i, y2 + i); - } - // Ensure the corners are all in bounds. - if (!AllInBounds(image2_, x2, y2)) { - LG << "Successful step fell outside of the pattern bounds; aborting."; - return ceres::SOLVER_ABORT; - } - - // Ensure the minimizer is making large enough shifts to bother continuing. - // Ideally, this check would happen on the parameters themselves which - // Ceres supports directly; however, the mapping from parameter change - // magnitude to corner movement in pixels is not a simple norm. Hence, the - // need for a stateful callback which tracks the last successful set of - // parameters (and the position of the projected patch corners). - if (have_last_successful_step_) { - // Compute the maximum shift of any corner in pixels since the last - // successful iteration. - double max_change_pixels = 0; - for (int i = 0; i < 4; ++i) { - double dx = x2[i] - x2_last_successful_[i]; - double dy = y2[i] - y2_last_successful_[i]; - double change_pixels = dx*dx + dy*dy; - if (change_pixels > max_change_pixels) { - max_change_pixels = change_pixels; - } - } - max_change_pixels = sqrt(max_change_pixels); - LG << "Max patch corner shift is " << max_change_pixels; - - // Bail if the shift is too small. - if (max_change_pixels < options_.minimum_corner_shift_tolerance_pixels) { - LG << "Max patch corner shift is " << max_change_pixels - << " from the last iteration; returning success."; - return ceres::SOLVER_TERMINATE_SUCCESSFULLY; - } - } - - // Save the projected corners for checking on the next successful iteration. - for (int i = 0; i < 4; ++i) { - x2_last_successful_[i] = x2[i]; - y2_last_successful_[i] = y2[i]; - } - have_last_successful_step_ = true; - return ceres::SOLVER_CONTINUE; - } - - private: - const TrackRegionOptions &options_; - const FloatImage &image2_; - const Warp &warp_; - const double *x1_; - const double *y1_; - - bool have_last_successful_step_; - double x2_last_successful_[4]; - double y2_last_successful_[4]; -}; - -template -class PixelDifferenceCostFunctor { - public: - PixelDifferenceCostFunctor(const TrackRegionOptions &options, - const FloatImage &image_and_gradient1, - const FloatImage &image_and_gradient2, - const Mat3 &canonical_to_image1, - int num_samples_x, - int num_samples_y, - const Warp &warp) - : options_(options), - image_and_gradient1_(image_and_gradient1), - image_and_gradient2_(image_and_gradient2), - canonical_to_image1_(canonical_to_image1), - num_samples_x_(num_samples_x), - num_samples_y_(num_samples_y), - warp_(warp), - pattern_and_gradient_(num_samples_y_, num_samples_x_, 3), - pattern_positions_(num_samples_y_, num_samples_x_, 2), - pattern_mask_(num_samples_y_, num_samples_x_, 1) { - ComputeCanonicalPatchAndNormalizer(); - } - - void ComputeCanonicalPatchAndNormalizer() { - src_mean_ = 0.0; - double num_samples = 0.0; - for (int r = 0; r < num_samples_y_; ++r) { - for (int c = 0; c < num_samples_x_; ++c) { - // Compute the position; cache it. - Vec3 image_position = canonical_to_image1_ * Vec3(c, r, 1); - image_position /= image_position(2); - pattern_positions_(r, c, 0) = image_position(0); - pattern_positions_(r, c, 1) = image_position(1); - - // Sample the pattern and gradients. - SampleLinear(image_and_gradient1_, - image_position(1), // SampleLinear is r, c. - image_position(0), - &pattern_and_gradient_(r, c, 0)); - - // Sample sample the mask. - double mask_value = 1.0; - if (options_.image1_mask != NULL) { - SampleLinear(*options_.image1_mask, - image_position(1), // SampleLinear is r, c. - image_position(0), - &pattern_mask_(r, c, 0)); - mask_value = pattern_mask_(r, c); - } - src_mean_ += pattern_and_gradient_(r, c, 0) * mask_value; - num_samples += mask_value; - } - } - src_mean_ /= num_samples; - } - - template - bool operator()(const T *warp_parameters, T *residuals) const { - if (options_.image1_mask != NULL) { - VLOG(2) << "Using a mask."; - } - for (int i = 0; i < Warp::NUM_PARAMETERS; ++i) { - VLOG(2) << "warp_parameters[" << i << "]: " << warp_parameters[i]; - } - - T dst_mean = T(1.0); - if (options_.use_normalized_intensities) { - ComputeNormalizingCoefficient(warp_parameters, - &dst_mean); - } - - int cursor = 0; - for (int r = 0; r < num_samples_y_; ++r) { - for (int c = 0; c < num_samples_x_; ++c) { - // Use the pre-computed image1 position. - Vec2 image1_position(pattern_positions_(r, c, 0), - pattern_positions_(r, c, 1)); - - // Sample the mask early; if it's zero, this pixel has no effect. This - // allows early bailout from the expensive sampling that happens below. - // - // Note that partial masks are not short circuited. To see why short - // circuiting produces bitwise-exact same results, consider that the - // residual for each pixel is - // - // residual = mask * (src - dst) , - // - // and for jets, multiplying by a scalar multiplies the derivative - // components by the scalar as well. Therefore, if the mask is exactly - // zero, then so too will the final residual and derivatives. - double mask_value = 1.0; - if (options_.image1_mask != NULL) { - mask_value = pattern_mask_(r, c); - if (mask_value == 0.0) { - residuals[cursor++] = T(0.0); - continue; - } - } - - // Compute the location of the destination pixel. - T image2_position[2]; - warp_.Forward(warp_parameters, - T(image1_position[0]), - T(image1_position[1]), - &image2_position[0], - &image2_position[1]); - - // Sample the destination, propagating derivatives. - T dst_sample = SampleWithDerivative(image_and_gradient2_, - image2_position[0], - image2_position[1]); - - // Sample the source. This is made complicated by ESM mode. - T src_sample; - if (options_.use_esm && !JetOps::IsScalar()) { - // In ESM mode, the derivative of the source is also taken into - // account. This changes the linearization in a way that causes - // better convergence. Copy the derivative of the warp parameters - // onto the jets for the image1 position. This is the ESM hack. - T image1_position_jet[2] = { - image2_position[0], // Order is x, y. This matches the - image2_position[1] // derivative order in the patch. - }; - JetOps::SetScalar(image1_position[0], image1_position_jet + 0); - JetOps::SetScalar(image1_position[1], image1_position_jet + 1); - - // Now that the image1 positions have the jets applied from the - // image2 position (the ESM hack), chain the image gradients to - // obtain a sample with the derivative with respect to the warp - // parameters attached. - src_sample = Chain::Rule(pattern_and_gradient_(r, c), - &pattern_and_gradient_(r, c, 1), - image1_position_jet); - - // The jacobians for these should be averaged. Due to the subtraction - // below, flip the sign of the src derivative so that the effect - // after subtraction of the jets is that they are averaged. - JetOps::ScaleDerivative(-0.5, &src_sample); - JetOps::ScaleDerivative(0.5, &dst_sample); - } else { - // This is the traditional, forward-mode KLT solution. - src_sample = T(pattern_and_gradient_(r, c)); - } - - // Normalize the samples by the mean values of each signal. The typical - // light model assumes multiplicative intensity changes with changing - // light, so this is a reasonable choice. Note that dst_mean has - // derivative information attached thanks to autodiff. - if (options_.use_normalized_intensities) { - src_sample /= T(src_mean_); - dst_sample /= dst_mean; - } - - // The difference is the error. - T error = src_sample - dst_sample; - - // Weight the error by the mask, if one is present. - if (options_.image1_mask != NULL) { - error *= T(mask_value); - } - residuals[cursor++] = error; - } - } - return true; - } - - // For normalized matching, the average and - template - void ComputeNormalizingCoefficient(const T *warp_parameters, - T *dst_mean) const { - *dst_mean = T(0.0); - double num_samples = 0.0; - for (int r = 0; r < num_samples_y_; ++r) { - for (int c = 0; c < num_samples_x_; ++c) { - // Use the pre-computed image1 position. - Vec2 image1_position(pattern_positions_(r, c, 0), - pattern_positions_(r, c, 1)); - - // Sample the mask early; if it's zero, this pixel has no effect. This - // allows early bailout from the expensive sampling that happens below. - double mask_value = 1.0; - if (options_.image1_mask != NULL) { - mask_value = pattern_mask_(r, c); - if (mask_value == 0.0) { - continue; - } - } - - // Compute the location of the destination pixel. - T image2_position[2]; - warp_.Forward(warp_parameters, - T(image1_position[0]), - T(image1_position[1]), - &image2_position[0], - &image2_position[1]); - - - // Sample the destination, propagating derivatives. - // TODO(keir): This accumulation can, surprisingly, be done as a - // pre-pass by using integral images. This is complicated by the need - // to store the jets in the integral image, but it is possible. - T dst_sample = SampleWithDerivative(image_and_gradient2_, - image2_position[0], - image2_position[1]); - - // Weight the sample by the mask, if one is present. - if (options_.image1_mask != NULL) { - dst_sample *= T(mask_value); - } - - *dst_mean += dst_sample; - num_samples += mask_value; - } - } - *dst_mean /= T(num_samples); - LG << "Normalization for dst:" << *dst_mean; - } - - // TODO(keir): Consider also computing the cost here. - double PearsonProductMomentCorrelationCoefficient( - const double *warp_parameters) const { - for (int i = 0; i < Warp::NUM_PARAMETERS; ++i) { - VLOG(2) << "Correlation warp_parameters[" << i << "]: " - << warp_parameters[i]; - } - - // The single-pass PMCC computation is somewhat numerically unstable, but - // it's sufficient for the tracker. - double sX = 0, sY = 0, sXX = 0, sYY = 0, sXY = 0; - - // Due to masking, it's important to account for fractional samples. - // For example, samples with a 50% mask are counted as a half sample. - double num_samples = 0; - - for (int r = 0; r < num_samples_y_; ++r) { - for (int c = 0; c < num_samples_x_; ++c) { - // Use the pre-computed image1 position. - Vec2 image1_position(pattern_positions_(r, c, 0), - pattern_positions_(r, c, 1)); - - double mask_value = 1.0; - if (options_.image1_mask != NULL) { - mask_value = pattern_mask_(r, c); - if (mask_value == 0.0) { - continue; - } - } - - // Compute the location of the destination pixel. - double image2_position[2]; - warp_.Forward(warp_parameters, - image1_position[0], - image1_position[1], - &image2_position[0], - &image2_position[1]); - - double x = pattern_and_gradient_(r, c); - double y = SampleLinear(image_and_gradient2_, - image2_position[1], // SampleLinear is r, c. - image2_position[0]); - - // Weight the signals by the mask, if one is present. - if (options_.image1_mask != NULL) { - x *= mask_value; - y *= mask_value; - num_samples += mask_value; - } else { - num_samples++; - } - sX += x; - sY += y; - sXX += x*x; - sYY += y*y; - sXY += x*y; - } - } - // Normalize. - sX /= num_samples; - sY /= num_samples; - sXX /= num_samples; - sYY /= num_samples; - sXY /= num_samples; - - double var_x = sXX - sX*sX; - double var_y = sYY - sY*sY; - double covariance_xy = sXY - sX*sY; - - double correlation = covariance_xy / sqrt(var_x * var_y); - LG << "Covariance xy: " << covariance_xy - << ", var 1: " << var_x << ", var 2: " << var_y - << ", correlation: " << correlation; - return correlation; - } - - private: - const TrackRegionOptions &options_; - const FloatImage &image_and_gradient1_; - const FloatImage &image_and_gradient2_; - const Mat3 &canonical_to_image1_; - int num_samples_x_; - int num_samples_y_; - const Warp &warp_; - double src_mean_; - FloatImage pattern_and_gradient_; - - // This contains the position from where the cached pattern samples were - // taken from. This is also used to warp from src to dest without going from - // canonical pixels to src first. - FloatImage pattern_positions_; - - FloatImage pattern_mask_; -}; - -template -class WarpRegularizingCostFunctor { - public: - WarpRegularizingCostFunctor(const TrackRegionOptions &options, - const double *x1, - const double *y1, - const double *x2_original, - const double *y2_original, - const Warp &warp) - : options_(options), - x1_(x1), - y1_(y1), - x2_original_(x2_original), - y2_original_(y2_original), - warp_(warp) { - // Compute the centroid of the first guess quad. - // TODO(keir): Use Quad class here. - original_centroid_[0] = 0.0; - original_centroid_[1] = 0.0; - for (int i = 0; i < 4; ++i) { - original_centroid_[0] += x2_original[i]; - original_centroid_[1] += y2_original[i]; - } - original_centroid_[0] /= 4; - original_centroid_[1] /= 4; - } - - template - bool operator()(const T *warp_parameters, T *residuals) const { - T dst_centroid[2] = { T(0.0), T(0.0) }; - for (int i = 0; i < 4; ++i) { - T image1_position[2] = { T(x1_[i]), T(y1_[i]) }; - T image2_position[2]; - warp_.Forward(warp_parameters, - T(x1_[i]), - T(y1_[i]), - &image2_position[0], - &image2_position[1]); - - // Subtract the positions. Note that this ignores the centroids. - residuals[2 * i + 0] = image2_position[0] - image1_position[0]; - residuals[2 * i + 1] = image2_position[1] - image1_position[1]; - - // Accumulate the dst centroid. - dst_centroid[0] += image2_position[0]; - dst_centroid[1] += image2_position[1]; - } - dst_centroid[0] /= T(4.0); - dst_centroid[1] /= T(4.0); - - // Adjust for the centroids. - for (int i = 0; i < 4; ++i) { - residuals[2 * i + 0] += T(original_centroid_[0]) - dst_centroid[0]; - residuals[2 * i + 1] += T(original_centroid_[1]) - dst_centroid[1]; - } - - // Reweight the residuals. - for (int i = 0; i < 8; ++i) { - residuals[i] *= T(options_.regularization_coefficient); - } - - return true; - } - - const TrackRegionOptions &options_; - const double *x1_; - const double *y1_; - const double *x2_original_; - const double *y2_original_; - double original_centroid_[2]; - const Warp &warp_; -}; - -// Compute the warp from rectangular coordinates, where one corner is the -// origin, and the opposite corner is at (num_samples_x, num_samples_y). -Mat3 ComputeCanonicalHomography(const double *x1, - const double *y1, - int num_samples_x, - int num_samples_y) { - Mat canonical(2, 4); - canonical << 0, num_samples_x, num_samples_x, 0, - 0, 0, num_samples_y, num_samples_y; - - Mat xy1(2, 4); - xy1 << x1[0], x1[1], x1[2], x1[3], - y1[0], y1[1], y1[2], y1[3]; - - Mat3 H; - if (!Homography2DFromCorrespondencesLinear(canonical, xy1, &H, 1e-12)) { - LG << "Couldn't construct homography."; - } - return H; -} - -class Quad { - public: - Quad(const double *x, const double *y) : x_(x), y_(y) { - // Compute the centroid and store it. - centroid_ = Vec2(0.0, 0.0); - for (int i = 0; i < 4; ++i) { - centroid_ += Vec2(x_[i], y_[i]); - } - centroid_ /= 4.0; - } - - // The centroid of the four points representing the quad. - const Vec2& Centroid() const { - return centroid_; - } - - // The average magnitude of the four points relative to the centroid. - double Scale() const { - double scale = 0.0; - for (int i = 0; i < 4; ++i) { - scale += (Vec2(x_[i], y_[i]) - Centroid()).norm(); - } - return scale / 4.0; - } - - Vec2 CornerRelativeToCentroid(int i) const { - return Vec2(x_[i], y_[i]) - centroid_; - } - - private: - const double *x_; - const double *y_; - Vec2 centroid_; -}; - -struct TranslationWarp { - TranslationWarp(const double *x1, const double *y1, - const double *x2, const double *y2) { - Vec2 t = Quad(x2, y2).Centroid() - Quad(x1, y1).Centroid(); - parameters[0] = t[0]; - parameters[1] = t[1]; - } - - template - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { - *x2 = x1 + warp_parameters[0]; - *y2 = y1 + warp_parameters[1]; - } - - // Translation x, translation y. - enum { NUM_PARAMETERS = 2 }; - double parameters[NUM_PARAMETERS]; -}; - -struct TranslationScaleWarp { - TranslationScaleWarp(const double *x1, const double *y1, - const double *x2, const double *y2) - : q1(x1, y1) { - Quad q2(x2, y2); - - // The difference in centroids is the best guess for translation. - Vec2 t = q2.Centroid() - q1.Centroid(); - parameters[0] = t[0]; - parameters[1] = t[1]; - - // The difference in scales is the estimate for the scale. - parameters[2] = 1.0 - q2.Scale() / q1.Scale(); - } - - // The strange way of parameterizing the translation and scaling is to make - // the knobs that the optimizer sees easy to adjust. This is less important - // for the scaling case than the rotation case. - template - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { - // Make the centroid of Q1 the origin. - const T x1_origin = x1 - q1.Centroid()(0); - const T y1_origin = y1 - q1.Centroid()(1); - - // Scale uniformly about the origin. - const T scale = 1.0 + warp_parameters[2]; - const T x1_origin_scaled = scale * x1_origin; - const T y1_origin_scaled = scale * y1_origin; - - // Translate back into the space of Q1 (but scaled). - const T x1_scaled = x1_origin_scaled + q1.Centroid()(0); - const T y1_scaled = y1_origin_scaled + q1.Centroid()(1); - - // Translate into the space of Q2. - *x2 = x1_scaled + warp_parameters[0]; - *y2 = y1_scaled + warp_parameters[1]; - } - - // Translation x, translation y, scale. - enum { NUM_PARAMETERS = 3 }; - double parameters[NUM_PARAMETERS]; - - Quad q1; -}; - -// Assumes the given points are already zero-centroid and the same size. -Mat2 OrthogonalProcrustes(const Mat2 &correlation_matrix) { - Eigen::JacobiSVD svd(correlation_matrix, - Eigen::ComputeFullU | Eigen::ComputeFullV); - return svd.matrixV() * svd.matrixU().transpose(); -} - -struct TranslationRotationWarp { - TranslationRotationWarp(const double *x1, const double *y1, - const double *x2, const double *y2) - : q1(x1, y1) { - Quad q2(x2, y2); - - // The difference in centroids is the best guess for translation. - Vec2 t = q2.Centroid() - q1.Centroid(); - parameters[0] = t[0]; - parameters[1] = t[1]; - - // Obtain the rotation via orthorgonal procrustes. - Mat2 correlation_matrix = Mat2::Zero(); - for (int i = 0; i < 4; ++i) { - correlation_matrix += q1.CornerRelativeToCentroid(i) * - q2.CornerRelativeToCentroid(i).transpose(); - } - Mat2 R = OrthogonalProcrustes(correlation_matrix); - parameters[2] = atan2(R(1, 0), R(0, 0)); - - LG << "Correlation_matrix:\n" << correlation_matrix; - LG << "R:\n" << R; - LG << "Theta:" << parameters[2]; - } - - // The strange way of parameterizing the translation and rotation is to make - // the knobs that the optimizer sees easy to adjust. The reason is that while - // it is always the case that it is possible to express composed rotations - // and translations as a single translation and rotation, the numerical - // values needed for the composition are often large in magnitude. This is - // enough to throw off any minimizer, since it must do the equivalent of - // compose rotations and translations. - // - // Instead, use the parameterization below that offers a parameterization - // that exposes the degrees of freedom in a way amenable to optimization. - template - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { - // Make the centroid of Q1 the origin. - const T x1_origin = x1 - q1.Centroid()(0); - const T y1_origin = y1 - q1.Centroid()(1); - - // Rotate about the origin (i.e. centroid of Q1). - const T theta = warp_parameters[2]; - const T costheta = cos(theta); - const T sintheta = sin(theta); - const T x1_origin_rotated = costheta * x1_origin - sintheta * y1_origin; - const T y1_origin_rotated = sintheta * x1_origin + costheta * y1_origin; - - // Translate back into the space of Q1 (but scaled). - const T x1_rotated = x1_origin_rotated + q1.Centroid()(0); - const T y1_rotated = y1_origin_rotated + q1.Centroid()(1); - - // Translate into the space of Q2. - *x2 = x1_rotated + warp_parameters[0]; - *y2 = y1_rotated + warp_parameters[1]; - } - - // Translation x, translation y, rotation about the center of Q1 degrees. - enum { NUM_PARAMETERS = 3 }; - double parameters[NUM_PARAMETERS]; - - Quad q1; -}; - -struct TranslationRotationScaleWarp { - TranslationRotationScaleWarp(const double *x1, const double *y1, - const double *x2, const double *y2) - : q1(x1, y1) { - Quad q2(x2, y2); - - // The difference in centroids is the best guess for translation. - Vec2 t = q2.Centroid() - q1.Centroid(); - parameters[0] = t[0]; - parameters[1] = t[1]; - - // The difference in scales is the estimate for the scale. - parameters[2] = 1.0 - q2.Scale() / q1.Scale(); - - // Obtain the rotation via orthorgonal procrustes. - Mat2 correlation_matrix = Mat2::Zero(); - for (int i = 0; i < 4; ++i) { - correlation_matrix += q1.CornerRelativeToCentroid(i) * - q2.CornerRelativeToCentroid(i).transpose(); - } - Mat2 R = OrthogonalProcrustes(correlation_matrix); - parameters[3] = atan2(R(1, 0), R(0, 0)); - - LG << "Correlation_matrix:\n" << correlation_matrix; - LG << "R:\n" << R; - LG << "Theta:" << parameters[3]; - } - - // The strange way of parameterizing the translation and rotation is to make - // the knobs that the optimizer sees easy to adjust. The reason is that while - // it is always the case that it is possible to express composed rotations - // and translations as a single translation and rotation, the numerical - // values needed for the composition are often large in magnitude. This is - // enough to throw off any minimizer, since it must do the equivalent of - // compose rotations and translations. - // - // Instead, use the parameterization below that offers a parameterization - // that exposes the degrees of freedom in a way amenable to optimization. - template - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { - // Make the centroid of Q1 the origin. - const T x1_origin = x1 - q1.Centroid()(0); - const T y1_origin = y1 - q1.Centroid()(1); - - // Rotate about the origin (i.e. centroid of Q1). - const T theta = warp_parameters[3]; - const T costheta = cos(theta); - const T sintheta = sin(theta); - const T x1_origin_rotated = costheta * x1_origin - sintheta * y1_origin; - const T y1_origin_rotated = sintheta * x1_origin + costheta * y1_origin; - - // Scale uniformly about the origin. - const T scale = 1.0 + warp_parameters[2]; - const T x1_origin_rotated_scaled = scale * x1_origin_rotated; - const T y1_origin_rotated_scaled = scale * y1_origin_rotated; - - // Translate back into the space of Q1 (but scaled and rotated). - const T x1_rotated_scaled = x1_origin_rotated_scaled + q1.Centroid()(0); - const T y1_rotated_scaled = y1_origin_rotated_scaled + q1.Centroid()(1); - - // Translate into the space of Q2. - *x2 = x1_rotated_scaled + warp_parameters[0]; - *y2 = y1_rotated_scaled + warp_parameters[1]; - } - - // Translation x, translation y, rotation about the center of Q1 degrees, - // scale. - enum { NUM_PARAMETERS = 4 }; - double parameters[NUM_PARAMETERS]; - - Quad q1; -}; - -struct AffineWarp { - AffineWarp(const double *x1, const double *y1, - const double *x2, const double *y2) - : q1(x1, y1) { - Quad q2(x2, y2); - - // The difference in centroids is the best guess for translation. - Vec2 t = q2.Centroid() - q1.Centroid(); - parameters[0] = t[0]; - parameters[1] = t[1]; - - // Estimate the four affine parameters with the usual least squares. - Mat Q1(8, 4); - Vec Q2(8); - for (int i = 0; i < 4; ++i) { - Vec2 v1 = q1.CornerRelativeToCentroid(i); - Vec2 v2 = q2.CornerRelativeToCentroid(i); - - Q1.row(2 * i + 0) << v1[0], v1[1], 0, 0; - Q1.row(2 * i + 1) << 0, 0, v1[0], v1[1]; - - Q2(2 * i + 0) = v2[0]; - Q2(2 * i + 1) = v2[1]; - } - - // TODO(keir): Check solution quality. - Vec4 a = Q1.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(Q2); - parameters[2] = a[0]; - parameters[3] = a[1]; - parameters[4] = a[2]; - parameters[5] = a[3]; - - LG << "a:" << a.transpose(); - LG << "t:" << t.transpose(); - } - - // See comments in other parameterizations about why the centroid is used. - template - void Forward(const T *p, const T &x1, const T& y1, T *x2, T* y2) const { - // Make the centroid of Q1 the origin. - const T x1_origin = x1 - q1.Centroid()(0); - const T y1_origin = y1 - q1.Centroid()(1); - - // Apply the affine transformation. - const T x1_origin_affine = p[2] * x1_origin + p[3] * y1_origin; - const T y1_origin_affine = p[4] * x1_origin + p[5] * y1_origin; - - // Translate back into the space of Q1 (but affine transformed). - const T x1_affine = x1_origin_affine + q1.Centroid()(0); - const T y1_affine = y1_origin_affine + q1.Centroid()(1); - - // Translate into the space of Q2. - *x2 = x1_affine + p[0]; - *y2 = y1_affine + p[1]; - } - - // Translation x, translation y, rotation about the center of Q1 degrees, - // scale. - enum { NUM_PARAMETERS = 6 }; - double parameters[NUM_PARAMETERS]; - - Quad q1; -}; - -struct HomographyWarp { - HomographyWarp(const double *x1, const double *y1, - const double *x2, const double *y2) { - Mat quad1(2, 4); - quad1 << x1[0], x1[1], x1[2], x1[3], - y1[0], y1[1], y1[2], y1[3]; - - Mat quad2(2, 4); - quad2 << x2[0], x2[1], x2[2], x2[3], - y2[0], y2[1], y2[2], y2[3]; - - Mat3 H; - if (!Homography2DFromCorrespondencesLinear(quad1, quad2, &H, 1e-12)) { - LG << "Couldn't construct homography."; - } - - // Assume H(2, 2) != 0, and fix scale at H(2, 2) == 1.0. - H /= H(2, 2); - - // Assume H is close to identity, so subtract out the diagonal. - H(0, 0) -= 1.0; - H(1, 1) -= 1.0; - - CHECK_NE(H(2, 2), 0.0) << H; - for (int i = 0; i < 8; ++i) { - parameters[i] = H(i / 3, i % 3); - LG << "Parameters[" << i << "]: " << parameters[i]; - } - } - - template - static void Forward(const T *p, - const T &x1, const T& y1, T *x2, T* y2) { - // Homography warp with manual 3x3 matrix multiply. - const T xx2 = (1.0 + p[0]) * x1 + p[1] * y1 + p[2]; - const T yy2 = p[3] * x1 + (1.0 + p[4]) * y1 + p[5]; - const T zz2 = p[6] * x1 + p[7] * y1 + 1.0; - *x2 = xx2 / zz2; - *y2 = yy2 / zz2; - } - - enum { NUM_PARAMETERS = 8 }; - double parameters[NUM_PARAMETERS]; -}; - -// Determine the number of samples to use for x and y. Quad winding goes: -// -// 0 1 -// 3 2 -// -// The idea is to take the maximum x or y distance. This may be oversampling. -// TODO(keir): Investigate the various choices; perhaps average is better? -void PickSampling(const double *x1, const double *y1, - const double *x2, const double *y2, - int *num_samples_x, int *num_samples_y) { - (void) x2; // Ignored. - (void) y2; // Ignored. - - Vec2 a0(x1[0], y1[0]); - Vec2 a1(x1[1], y1[1]); - Vec2 a2(x1[2], y1[2]); - Vec2 a3(x1[3], y1[3]); - - Vec2 b0(x1[0], y1[0]); - Vec2 b1(x1[1], y1[1]); - Vec2 b2(x1[2], y1[2]); - Vec2 b3(x1[3], y1[3]); - - double x_dimensions[4] = { - (a1 - a0).norm(), - (a3 - a2).norm(), - (b1 - b0).norm(), - (b3 - b2).norm() - }; - - double y_dimensions[4] = { - (a3 - a0).norm(), - (a1 - a2).norm(), - (b3 - b0).norm(), - (b1 - b2).norm() - }; - const double kScaleFactor = 1.0; - *num_samples_x = static_cast( - kScaleFactor * *std::max_element(x_dimensions, x_dimensions + 4)); - *num_samples_y = static_cast( - kScaleFactor * *std::max_element(y_dimensions, y_dimensions + 4)); - LG << "Automatic num_samples_x: " << *num_samples_x - << ", num_samples_y: " << *num_samples_y; -} - -bool SearchAreaTooBigForDescent(const FloatImage &image2, - const double *x2, const double *y2) { - // TODO(keir): Check the bounds and enable only when it makes sense. - (void) image2; // Ignored. - (void) x2; // Ignored. - (void) y2; // Ignored. - - return true; -} - -bool PointOnRightHalfPlane(const Vec2 &a, const Vec2 &b, double x, double y) { - Vec2 ba = b - a; - return ((Vec2(x, y) - b).transpose() * Vec2(-ba.y(), ba.x())) > 0; -} - -// Determine if a point is in a quad. The quad is arranged as: -// -// +-------> x -// | -// | a0------a1 -// | | | -// | | | -// | | | -// | a3------a2 -// v -// y -// -// The implementation does up to four half-plane comparisons. -bool PointInQuad(const double *xs, const double *ys, double x, double y) { - Vec2 a0(xs[0], ys[0]); - Vec2 a1(xs[1], ys[1]); - Vec2 a2(xs[2], ys[2]); - Vec2 a3(xs[3], ys[3]); - - return PointOnRightHalfPlane(a0, a1, x, y) && - PointOnRightHalfPlane(a1, a2, x, y) && - PointOnRightHalfPlane(a2, a3, x, y) && - PointOnRightHalfPlane(a3, a0, x, y); -} - -// This makes it possible to map between Eigen float arrays and FloatImage -// without using comparisons. -typedef Eigen::Array FloatArray; - -// This creates a pattern in the frame of image2, from the pixel is image1, -// based on the initial guess represented by the two quads x1, y1, and x2, y2. -template -void CreateBrutePattern(const double *x1, const double *y1, - const double *x2, const double *y2, - const FloatImage &image1, - const FloatImage *image1_mask, - FloatArray *pattern, - FloatArray *mask, - int *origin_x, - int *origin_y) { - // Get integer bounding box of quad2 in image2. - int min_x = static_cast(floor(*std::min_element(x2, x2 + 4))); - int min_y = static_cast(floor(*std::min_element(y2, y2 + 4))); - int max_x = static_cast(ceil (*std::max_element(x2, x2 + 4))); - int max_y = static_cast(ceil (*std::max_element(y2, y2 + 4))); - - int w = max_x - min_x; - int h = max_y - min_y; - - pattern->resize(h, w); - mask->resize(h, w); - - Warp inverse_warp(x2, y2, x1, y1); - - // r,c are in the coordinate frame of image2. - for (int r = min_y; r < max_y; ++r) { - for (int c = min_x; c < max_x; ++c) { - // i and j are in the coordinate frame of the pattern in image2. - int i = r - min_y; - int j = c - min_x; - - double dst_x = c; - double dst_y = r; - double src_x; - double src_y; - inverse_warp.Forward(inverse_warp.parameters, - dst_x, dst_y, - &src_x, &src_y); - - if (PointInQuad(x1, y1, src_x, src_y)) { - (*pattern)(i, j) = SampleLinear(image1, src_y, src_x); - (*mask)(i, j) = 1.0; - if (image1_mask) { - (*mask)(i, j) = SampleLinear(*image1_mask, src_y, src_x); - } - } else { - (*pattern)(i, j) = 0.0; - (*mask)(i, j) = 0.0; - } - } - } - *origin_x = min_x; - *origin_y = min_y; -} - -// Compute a translation-only estimate of the warp, using brute force search. A -// smarter implementation would use the FFT to compute the normalized cross -// correlation. Instead, this is a dumb implementation. Surprisingly, it is -// fast enough in practice. -// -// Returns true if any alignment was found, and false if the projected pattern -// is zero sized. -// -// TODO(keir): The normalization is less effective for the brute force search -// than it is with the Ceres solver. It's unclear if this is a bug or due to -// the original frame being too different from the reprojected reference in the -// destination frame. -// -// The likely solution is to use the previous frame, instead of the original -// pattern, when doing brute initialization. Unfortunately that implies a -// totally different warping interface, since access to more than a the source -// and current destination frame is necessary. -template -bool BruteTranslationOnlyInitialize(const FloatImage &image1, - const FloatImage *image1_mask, - const FloatImage &image2, - const int num_extra_points, - const bool use_normalized_intensities, - const double *x1, const double *y1, - double *x2, double *y2) { - // Create the pattern to match in the space of image2, assuming our inital - // guess isn't too far from the template in image1. If there is no image1 - // mask, then the resulting mask is binary. - FloatArray pattern; - FloatArray mask; - int origin_x = -1, origin_y = -1; - CreateBrutePattern(x1, y1, x2, y2, - image1, image1_mask, - &pattern, &mask, - &origin_x, &origin_y); - - // For normalization, premultiply the pattern by the inverse pattern mean. - double mask_sum = 1.0; - if (use_normalized_intensities) { - mask_sum = mask.sum(); - double inverse_pattern_mean = mask_sum / ((mask * pattern).sum()); - pattern *= inverse_pattern_mean; - } - - // Use Eigen on the images via maps for strong vectorization. - Map search(image2.Data(), image2.Height(), image2.Width()); - - // Try all possible locations inside the search area. Yes, everywhere. - // - // TODO(keir): There are a number of possible optimizations here. One choice - // is to make a grid and only try one out of every N possible samples. - // - // Another, slightly more clever idea, is to compute some sort of spatial - // frequency distribution of the pattern patch. If the spatial resolution is - // high (e.g. a grating pattern or fine lines) then checking every possible - // translation is necessary, since a 1-pixel shift may induce a massive - // change in the cost function. If the image is a blob or splotch with blurry - // edges, then fewer samples are necessary since a few pixels offset won't - // change the cost function much. - double best_sad = std::numeric_limits::max(); - int best_r = -1; - int best_c = -1; - int w = pattern.cols(); - int h = pattern.rows(); - - for (int r = 0; r < (image2.Height() - h); ++r) { - for (int c = 0; c < (image2.Width() - w); ++c) { - // Compute the weighted sum of absolute differences, Eigen style. Note - // that the block from the search image is never stored in a variable, to - // avoid copying overhead and permit inlining. - double sad; - if (use_normalized_intensities) { - // TODO(keir): It's really dumb to recompute the search mean for every - // shift. A smarter implementation would use summed area tables - // instead, reducing the mean calculation to an O(1) operation. - double inverse_search_mean = - mask_sum / ((mask * search.block(r, c, h, w)).sum()); - sad = (mask * (pattern - (search.block(r, c, h, w) * - inverse_search_mean))).abs().sum(); - } else { - sad = (mask * (pattern - search.block(r, c, h, w))).abs().sum(); - } - if (sad < best_sad) { - best_r = r; - best_c = c; - best_sad = sad; - } - } - } - - // This mean the effective pattern area is zero. This check could go earlier, - // but this is less code. - if (best_r == -1 || best_c == -1) { - return false; - } - - LG << "Brute force translation found a shift. " - << "best_c: " << best_c << ", best_r: " << best_r << ", " - << "origin_x: " << origin_x << ", origin_y: " << origin_y << ", " - << "dc: " << (best_c - origin_x) << ", " - << "dr: " << (best_r - origin_y) - << ", tried " << ((image2.Height() - h) * (image2.Width() - w)) - << " shifts."; - - // Apply the shift. - for (int i = 0; i < 4 + num_extra_points; ++i) { - x2[i] += best_c - origin_x; - y2[i] += best_r - origin_y; - } - return true; -} - -void CopyQuad(double *src_x, double *src_y, - double *dst_x, double *dst_y, - int num_extra_points) { - for (int i = 0; i < 4 + num_extra_points; ++i) { - dst_x[i] = src_x[i]; - dst_y[i] = src_y[i]; - } -} - -} // namespace - -template -void TemplatedTrackRegion(const FloatImage &image1, - const FloatImage &image2, - const double *x1, const double *y1, - const TrackRegionOptions &options, - double *x2, double *y2, - TrackRegionResult *result) { - for (int i = 0; i < 4 + options.num_extra_points; ++i) { - LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); guess (" - << x2[i] << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", " - << (y2[i] - y1[i]) << ")."; - } - - // Since (x2, y2) contains a prediction for where the tracked point should - // go, try a refinement immediately in the hope that the prediction is close - // enough. - if (options.attempt_refine_before_brute) { - TrackRegionOptions modified_options = options; - modified_options.use_brute_initialization = false; - modified_options.attempt_refine_before_brute = false; - - double x2_first_try[5]; - double y2_first_try[5]; - CopyQuad(x2, y2, x2_first_try, y2_first_try, options.num_extra_points); - - TemplatedTrackRegion(image1, image2, - x1, y1, modified_options, - x2_first_try, y2_first_try, result); - - // Of the things that can happen in the first pass, don't try the brute - // pass (and second attempt) if the error is one of the terminations below. - if (result->termination == TrackRegionResult::CONVERGENCE || - result->termination == TrackRegionResult::SOURCE_OUT_OF_BOUNDS || - result->termination == TrackRegionResult::DESTINATION_OUT_OF_BOUNDS || - result->termination == TrackRegionResult::INSUFFICIENT_PATTERN_AREA) { - LG << "Terminated with first try at refinement; no brute needed."; - // TODO(keir): Also check correlation? - CopyQuad(x2_first_try, y2_first_try, x2, y2, options.num_extra_points); - LG << "Early termination correlation: " << result->correlation; - return; - } else { - LG << "Initial eager-refinement failed; retrying normally."; - } - } - - if (options.use_normalized_intensities) { - LG << "Using normalized intensities."; - } - - // Bail early if the points are already outside. - if (!AllInBounds(image1, x1, y1)) { - result->termination = TrackRegionResult::SOURCE_OUT_OF_BOUNDS; - return; - } - if (!AllInBounds(image2, x2, y2)) { - result->termination = TrackRegionResult::DESTINATION_OUT_OF_BOUNDS; - return; - } - // TODO(keir): Check quads to ensure there is some area. - - // Keep a copy of the "original" guess for regularization. - double x2_original[4]; - double y2_original[4]; - for (int i = 0; i < 4; ++i) { - x2_original[i] = x2[i]; - y2_original[i] = y2[i]; - } - - // Prepare the image and gradient. - Array3Df image_and_gradient1; - Array3Df image_and_gradient2; - BlurredImageAndDerivativesChannels(image1, options.sigma, - &image_and_gradient1); - BlurredImageAndDerivativesChannels(image2, options.sigma, - &image_and_gradient2); - - // Possibly do a brute-force translation-only initialization. - if (SearchAreaTooBigForDescent(image2, x2, y2) && - options.use_brute_initialization) { - LG << "Running brute initialization..."; - bool found_any_alignment = BruteTranslationOnlyInitialize( - image_and_gradient1, - options.image1_mask, - image2, - options.num_extra_points, - options.use_normalized_intensities, - x1, y1, x2, y2); - if (!found_any_alignment) { - LG << "Brute failed to find an alignment; pattern too small. " - << "Failing entire track operation."; - result->termination = TrackRegionResult::INSUFFICIENT_PATTERN_AREA; - return; - } - for (int i = 0; i < 4; ++i) { - LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); brute (" - << x2[i] << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) - << ", " << (y2[i] - y1[i]) << ")."; - } - } - - // Prepare the initial warp parameters from the four correspondences. - // Note: This must happen after the brute initialization runs, since the - // brute initialization mutates x2 and y2 in place. - Warp warp(x1, y1, x2, y2); - - // Decide how many samples to use in the x and y dimensions. - int num_samples_x; - int num_samples_y; - PickSampling(x1, y1, x2, y2, &num_samples_x, &num_samples_y); - - // Compute the warp from rectangular coordinates. - Mat3 canonical_homography = ComputeCanonicalHomography(x1, y1, - num_samples_x, - num_samples_y); - - ceres::Problem problem; - - // Construct the warp cost function. AutoDiffCostFunction takes ownership. - PixelDifferenceCostFunctor *pixel_difference_cost_function = - new PixelDifferenceCostFunctor(options, - image_and_gradient1, - image_and_gradient2, - canonical_homography, - num_samples_x, - num_samples_y, - warp); - problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - PixelDifferenceCostFunctor, - ceres::DYNAMIC, - Warp::NUM_PARAMETERS>(pixel_difference_cost_function, - num_samples_x * num_samples_y), - NULL, - warp.parameters); - - // Construct the regularizing cost function - if (options.regularization_coefficient != 0.0) { - WarpRegularizingCostFunctor *regularizing_warp_cost_function = - new WarpRegularizingCostFunctor(options, - x1, y2, - x2_original, - y2_original, - warp); - - problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - WarpRegularizingCostFunctor, - 8 /* num_residuals */, - Warp::NUM_PARAMETERS>(regularizing_warp_cost_function), - NULL, - warp.parameters); - } - - // Configure the solve. - ceres::Solver::Options solver_options; - solver_options.linear_solver_type = ceres::DENSE_QR; - solver_options.max_num_iterations = options.max_iterations; - solver_options.update_state_every_iteration = true; - solver_options.parameter_tolerance = 1e-16; - solver_options.function_tolerance = 1e-16; - - // Prevent the corners from going outside the destination image and - // terminate if the optimizer is making tiny moves (converged). - TerminationCheckingCallback callback(options, image2, warp, x1, y1); - solver_options.callbacks.push_back(&callback); - - // Run the solve. - ceres::Solver::Summary summary; - ceres::Solve(solver_options, &problem, &summary); - - LG << "Summary:\n" << summary.FullReport(); - - // Update the four points with the found solution; if the solver failed, then - // the warp parameters are the identity (so ignore failure). - // - // Also warp any extra points on the end of the array. - for (int i = 0; i < 4 + options.num_extra_points; ++i) { - warp.Forward(warp.parameters, x1[i], y1[i], x2 + i, y2 + i); - LG << "Warped point " << i << ": (" << x1[i] << ", " << y1[i] << ") -> (" - << x2[i] << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", " - << (y2[i] - y1[i]) << ")."; - } - - // TODO(keir): Update the result statistics. - // TODO(keir): Add a normalize-cross-correlation variant. - - if (summary.termination_type == ceres::USER_FAILURE) { - result->termination = TrackRegionResult::FELL_OUT_OF_BOUNDS; - return; - } - -#define HANDLE_TERMINATION(termination_enum) \ - if (summary.termination_type == ceres::termination_enum) { \ - result->termination = TrackRegionResult::termination_enum; \ - return; \ - } - - // Avoid computing correlation for tracking failures. - HANDLE_TERMINATION(FAILURE); - - // Otherwise, run a final correlation check. - if (options.minimum_correlation > 0.0) { - result->correlation = pixel_difference_cost_function-> - PearsonProductMomentCorrelationCoefficient(warp.parameters); - if (result->correlation < options.minimum_correlation) { - LG << "Failing with insufficient correlation."; - result->termination = TrackRegionResult::INSUFFICIENT_CORRELATION; - return; - } - } - - // This happens when the minimum corner shift tolerance is reached. Due to - // how the tolerance is computed this can't be done by Ceres. So return the - // same termination enum as Ceres, even though this is slightly different - // than Ceres's parameter tolerance, which operates on the raw parameter - // values rather than the pixel shifts of the patch corners. - if (summary.termination_type == ceres::USER_SUCCESS) { - result->termination = TrackRegionResult::CONVERGENCE; - return; - } - - HANDLE_TERMINATION(CONVERGENCE); - HANDLE_TERMINATION(NO_CONVERGENCE); -#undef HANDLE_TERMINATION -}; - -void TrackRegion(const FloatImage &image1, - const FloatImage &image2, - const double *x1, const double *y1, - const TrackRegionOptions &options, - double *x2, double *y2, - TrackRegionResult *result) { - // Enum is necessary due to templated nature of autodiff. -#define HANDLE_MODE(mode_enum, mode_type) \ - if (options.mode == TrackRegionOptions::mode_enum) { \ - TemplatedTrackRegion(image1, image2, \ - x1, y1, \ - options, \ - x2, y2, \ - result); \ - return; \ - } - HANDLE_MODE(TRANSLATION, TranslationWarp); - HANDLE_MODE(TRANSLATION_SCALE, TranslationScaleWarp); - HANDLE_MODE(TRANSLATION_ROTATION, TranslationRotationWarp); - HANDLE_MODE(TRANSLATION_ROTATION_SCALE, TranslationRotationScaleWarp); - HANDLE_MODE(AFFINE, AffineWarp); - HANDLE_MODE(HOMOGRAPHY, HomographyWarp); -#undef HANDLE_MODE -} - -bool SamplePlanarPatch(const FloatImage &image, - const double *xs, const double *ys, - int num_samples_x, int num_samples_y, - FloatImage *mask, FloatImage *patch, - double *warped_position_x, double *warped_position_y) { - // Bail early if the points are outside the image. - if (!AllInBounds(image, xs, ys)) { - LG << "Can't sample patch: out of bounds."; - return false; - } - - // Make the patch have the appropriate size, and match the depth of image. - patch->Resize(num_samples_y, num_samples_x, image.Depth()); - - // Compute the warp from rectangular coordinates. - Mat3 canonical_homography = ComputeCanonicalHomography(xs, ys, - num_samples_x, - num_samples_y); - - // Walk over the coordinates in the canonical space, sampling from the image - // in the original space and copying the result into the patch. - for (int r = 0; r < num_samples_y; ++r) { - for (int c = 0; c < num_samples_x; ++c) { - Vec3 image_position = canonical_homography * Vec3(c, r, 1); - image_position /= image_position(2); - SampleLinear(image, image_position(1), - image_position(0), - &(*patch)(r, c, 0)); - if (mask) { - float mask_value = SampleLinear(*mask, image_position(1), - image_position(0), 0); - - for (int d = 0; d < image.Depth(); d++) - (*patch)(r, c, d) *= mask_value; - } - } - } - - Vec3 warped_position = canonical_homography.inverse() * Vec3(xs[4], ys[4], 1); - warped_position /= warped_position(2); - - *warped_position_x = warped_position(0); - *warped_position_y = warped_position(1); - - return true; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/tracking/track_region.h b/extern/libmv/libmv/tracking/track_region.h deleted file mode 100644 index be1d8ef3e03..00000000000 --- a/extern/libmv/libmv/tracking/track_region.h +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) 2012 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_TRACKING_TRACK_REGION_H_ - -// Necessary for M_E when building with MSVC. -#define _USE_MATH_DEFINES - -#include "libmv/image/image.h" -#include "libmv/image/sample.h" -#include "libmv/numeric/numeric.h" - -namespace libmv { - -struct TrackRegionOptions { - TrackRegionOptions(); - - enum Mode { - TRANSLATION, - TRANSLATION_ROTATION, - TRANSLATION_SCALE, - TRANSLATION_ROTATION_SCALE, - AFFINE, - HOMOGRAPHY, - }; - Mode mode; - - // Minimum normalized cross-correlation necessary between the final tracked - // positoin of the patch on the destination image and the reference patch - // needed to declare tracking success. If the minimum correlation is not met, - // then TrackResult::termination is INSUFFICIENT_CORRELATION. - double minimum_correlation; - - // Maximum number of Ceres iterations to run for the inner minimization. - int max_iterations; - - // Use the "Efficient Second-order Minimization" scheme. This increases - // convergence speed at the cost of more per-iteration work. - bool use_esm; - - // If true, apply a brute-force translation-only search before attempting the - // full search. This is not enabled if the destination image ("image2") is - // too small; in that case eithen the basin of attraction is close enough - // that the nearby minima is correct, or the search area is too small. - bool use_brute_initialization; - - // If true and brute initialization is enabled, first try refining with the - // initial guess instead of starting with the brute initialization. If the - // initial refinement fails, then a normal brute search followed by - // refinement is attempted. If the initial refinement succeeds, then the - // result is returned as is (skipping a costly brute search). - bool attempt_refine_before_brute; - - // If true, normalize the image patches by their mean before doing the sum of - // squared error calculation. This is reasonable since the effect of - // increasing light intensity is multiplicative on the pixel intensities. - // - // Note: This does nearly double the solving time, so it is not advised to - // turn this on all the time. - bool use_normalized_intensities; - - // The size in pixels of the blur kernel used to both smooth the image and - // take the image derivative. - double sigma; - - // Extra points that should get transformed by the warp. These points are - // appended to the x and y arrays. This is useful because the actual warp - // parameters are not exposed. - int num_extra_points; - - // For motion models other than translation, the optimizer sometimes has - // trouble deciding what to do around flat areas in the cost function. This - // leads to the optimizer picking poor solutions near the minimum. Visually, - // the effect is that the quad corners jiggle around, even though the center - // of the patch is well estimated. regularization_coefficient controls a term - // in the sum of squared error cost that makes it expensive for the optimizer - // to pick a warp that changes the shape of the patch dramatically (e.g. - // rotating, scaling, skewing, etc). - // - // In particular it adds an 8-residual cost function to the optimization, - // where each corner induces 2 residuals: the difference between the warped - // and the initial guess. However, the patch centroids are subtracted so that - // only patch distortions are penalized. - // - // If zero, no regularization is used. - double regularization_coefficient; - - // If the maximum shift of any patch corner between successful iterations of - // the solver is less than this amount, then the tracking is declared - // successful. The solver termination becomes PARAMETER_TOLERANCE. - double minimum_corner_shift_tolerance_pixels; - - // If non-null, this is used as the pattern mask. It should match the size of - // image1, even though only values inside the image1 quad are examined. The - // values must be in the range 0.0 to 0.1. - FloatImage *image1_mask; -}; - -struct TrackRegionResult { - enum Termination { - // Ceres termination types, duplicated; though, not the int values. - CONVERGENCE, - NO_CONVERGENCE, - FAILURE, - - // Libmv specific errors. - SOURCE_OUT_OF_BOUNDS, - DESTINATION_OUT_OF_BOUNDS, - FELL_OUT_OF_BOUNDS, - INSUFFICIENT_CORRELATION, - INSUFFICIENT_PATTERN_AREA, - CONFIGURATION_ERROR, - }; - Termination termination; - - bool is_usable() { - return termination == CONVERGENCE || - termination == NO_CONVERGENCE; - } - - int num_iterations; - double correlation; - - // Final parameters? - bool used_brute_translation_initialization; -}; - -// Always needs 4 correspondences. -void TrackRegion(const FloatImage &image1, - const FloatImage &image2, - const double *x1, const double *y1, - const TrackRegionOptions &options, - double *x2, double *y2, - TrackRegionResult *result); - -// Sample a "canonical" version of the passed planar patch, using bilinear -// sampling. The passed corners must be within the image, and have at least two -// pixels of border around them. (so e.g. a corner of the patch cannot lie -// directly on the edge of the image). Four corners are always required. All -// channels are interpolated. -// When mask is not null it'll be used as a pattern mask. Ot should match -// the size of image. -// Warped coordinates of marker's position would be returned in -// warped_position_x and warped_position_y -bool SamplePlanarPatch(const FloatImage &image, - const double *xs, const double *ys, - int num_samples_x, int num_samples_y, - FloatImage *mask, FloatImage *patch, - double *warped_position_x, double *warped_position_y); - -} // namespace libmv - -#endif // LIBMV_TRACKING_TRACK_REGION_H_ diff --git a/extern/libmv/libmv/tracking/trklt_region_tracker.cc b/extern/libmv/libmv/tracking/trklt_region_tracker.cc deleted file mode 100644 index 05ef3d1d272..00000000000 --- a/extern/libmv/libmv/tracking/trklt_region_tracker.cc +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "libmv/tracking/trklt_region_tracker.h" - -#include "libmv/logging/logging.h" -#include "libmv/numeric/numeric.h" -#include "libmv/image/image.h" -#include "libmv/image/convolve.h" -#include "libmv/image/sample.h" - -namespace libmv { - -// TODO(keir): Switch this to use the smarter LM loop like in ESM. - -// Computes U and e from the Ud = e equation (number 14) from the paper. -static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, - const Array3Df &image_and_gradient2, - double x1, double y1, - double x2, double y2, - int half_width, - double lambda, - Mat2f *U, - Vec2f *e) { - Mat2f A, B, C, D; - A = B = C = D = Mat2f::Zero(); - - Vec2f R, S, V, W; - R = S = V = W = Vec2f::Zero(); - - for (int r = -half_width; r <= half_width; ++r) { - for (int c = -half_width; c <= half_width; ++c) { - float xx1 = x1 + c; - float yy1 = y1 + r; - float xx2 = x2 + c; - float yy2 = y2 + r; - - float I = SampleLinear(image_and_gradient1, yy1, xx1, 0); - float J = SampleLinear(image_and_gradient2, yy2, xx2, 0); - - Vec2f gI, gJ; - gI << SampleLinear(image_and_gradient1, yy1, xx1, 1), - SampleLinear(image_and_gradient1, yy1, xx1, 2); - gJ << SampleLinear(image_and_gradient2, yy2, xx2, 1), - SampleLinear(image_and_gradient2, yy2, xx2, 2); - - // Equation 15 from the paper. - A += gI * gI.transpose(); - B += gI * gJ.transpose(); - C += gJ * gJ.transpose(); - R += I * gI; - S += J * gI; - V += I * gJ; - W += J * gJ; - } - } - - // In the paper they show a D matrix, but it is just B transpose, so use that - // instead of explicitly computing D. - Mat2f Di = B.transpose().inverse(); - - // Equation 14 from the paper. - *U = A*Di*C + lambda*Di*C - 0.5*B; - *e = (A + lambda*Mat2f::Identity())*Di*(V - W) + 0.5*(S - R); -} - -static bool RegionIsInBounds(const FloatImage &image1, - double x, double y, - int half_window_size) { - // Check the minimum coordinates. - int min_x = floor(x) - half_window_size - 1; - int min_y = floor(y) - half_window_size - 1; - if (min_x < 0.0 || - min_y < 0.0) { - return false; - } - - // Check the maximum coordinates. - int max_x = ceil(x) + half_window_size + 1; - int max_y = ceil(y) + half_window_size + 1; - if (max_x > image1.cols() || - max_y > image1.rows()) { - return false; - } - - // Ok, we're good. - return true; -} - -bool TrkltRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { - if (!RegionIsInBounds(image1, x1, y1, half_window_size)) { - LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1 - << ", hw=" << half_window_size << "."; - return false; - } - - Array3Df image_and_gradient1; - Array3Df image_and_gradient2; - BlurredImageAndDerivativesChannels(image1, sigma, &image_and_gradient1); - BlurredImageAndDerivativesChannels(image2, sigma, &image_and_gradient2); - - int i; - Vec2f d = Vec2f::Zero(); - for (i = 0; i < max_iterations; ++i) { - // Check that the entire image patch is within the bounds of the images. - if (!RegionIsInBounds(image2, *x2, *y2, half_window_size)) { - LG << "Fell out of image2's window with x2=" << *x2 << ", y2=" << *y2 - << ", hw=" << half_window_size << "."; - return false; - } - - // Compute gradient matrix and error vector. - Mat2f U; - Vec2f e; - ComputeTrackingEquation(image_and_gradient1, - image_and_gradient2, - x1, y1, - *x2, *y2, - half_window_size, - lambda, - &U, &e); - - // Solve the linear system for the best update to x2 and y2. - d = U.lu().solve(e); - - // Update the position with the solved displacement. - *x2 += d[0]; - *y2 += d[1]; - - // Check for the quality of the solution, but not until having already - // updated the position with our best estimate. The reason to do the update - // anyway is that the user already knows the position is bad, so we may as - // well try our best. - float determinant = U.determinant(); - if (fabs(determinant) < min_determinant) { - // The determinant, which indicates the trackiness of the point, is too - // small, so fail out. - LG << "Determinant " << determinant << " is too small; failing tracking."; - return false; - } - LG << "x=" << *x2 << ", y=" << *y2 << ", dx=" << d[0] << ", dy=" << d[1] - << ", det=" << determinant; - - - // If the update is small, then we probably found the target. - if (d.squaredNorm() < min_update_squared_distance) { - LG << "Successful track in " << i << " iterations."; - return true; - } - } - // Getting here means we hit max iterations, so tracking failed. - LG << "Too many iterations; max is set to " << max_iterations << "."; - return false; -} - -} // namespace libmv diff --git a/extern/libmv/libmv/tracking/trklt_region_tracker.h b/extern/libmv/libmv/tracking/trklt_region_tracker.h deleted file mode 100644 index 26d0621aa02..00000000000 --- a/extern/libmv/libmv/tracking/trklt_region_tracker.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2011 libmv authors. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#ifndef LIBMV_REGION_TRACKING_TRKLT_REGION_TRACKER_H_ -#define LIBMV_REGION_TRACKING_TRKLT_REGION_TRACKER_H_ - -#include "libmv/image/image.h" -#include "libmv/tracking/region_tracker.h" - -namespace libmv { - -// An improved KLT algorithm that enforces that the tracking is time-reversible -// [1]. This is not the same as the "symmetric" KLT that is sometimes used. -// Anecdotally, this tracks much more consistently than vanilla KLT. -// -// [1] H. Wu, R. Chellappa, and A. Sankaranarayanan and S. Kevin Zhou. Robust -// visual tracking using the time-reversibility constraint. International -// Conference on Computer Vision (ICCV), Rio de Janeiro, October 2007. -// -struct TrkltRegionTracker : public RegionTracker { - TrkltRegionTracker() - : half_window_size(4), - max_iterations(100), - min_determinant(1e-6), - min_update_squared_distance(1e-6), - sigma(0.9), - lambda(0.05) {} - - virtual ~TrkltRegionTracker() {} - - // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; - - // No point in creating getters or setters. - int half_window_size; - int max_iterations; - double min_determinant; - double min_update_squared_distance; - double sigma; - double lambda; -}; - -} // namespace libmv - -#endif // LIBMV_REGION_TRACKING_TRKLT_REGION_TRACKER_H_ diff --git a/extern/libmv/mkfiles.sh b/extern/libmv/mkfiles.sh deleted file mode 100755 index 618070f0a81..00000000000 --- a/extern/libmv/mkfiles.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -find ./libmv/ -type f | sed -r 's/^\.\///' | sort > files.txt -find ./third_party/ -mindepth 2 -type f | \ - grep -v third_party/ceres | \ - sed -r 's/^\.\///' | sort >> files.txt diff --git a/extern/libmv/third_party/msinttypes/README.libmv b/extern/libmv/third_party/msinttypes/README.libmv deleted file mode 100644 index 423f599b4ad..00000000000 --- a/extern/libmv/third_party/msinttypes/README.libmv +++ /dev/null @@ -1,5 +0,0 @@ -Project: msinttypes -URL: http://code.google.com/p/msinttypes/ -License: New BSD License -Upstream version: r24 -Local modifications: None. diff --git a/extern/libmv/third_party/msinttypes/inttypes.h b/extern/libmv/third_party/msinttypes/inttypes.h deleted file mode 100644 index 0e8af69cb07..00000000000 --- a/extern/libmv/third_party/msinttypes/inttypes.h +++ /dev/null @@ -1,305 +0,0 @@ -// ISO C9x compliant inttypes.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The name of the author may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_INTTYPES_H_ // [ -#define _MSC_INTTYPES_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include - -// 7.8 Format conversion of integer types - -typedef struct { - intmax_t quot; - intmax_t rem; -} imaxdiv_t; - -// 7.8.1 Macros for format specifiers - -#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 - -// The fprintf macros for signed integers are: -#define PRId8 "d" -#define PRIi8 "i" -#define PRIdLEAST8 "d" -#define PRIiLEAST8 "i" -#define PRIdFAST8 "d" -#define PRIiFAST8 "i" - -#define PRId16 "hd" -#define PRIi16 "hi" -#define PRIdLEAST16 "hd" -#define PRIiLEAST16 "hi" -#define PRIdFAST16 "hd" -#define PRIiFAST16 "hi" - -#define PRId32 "I32d" -#define PRIi32 "I32i" -#define PRIdLEAST32 "I32d" -#define PRIiLEAST32 "I32i" -#define PRIdFAST32 "I32d" -#define PRIiFAST32 "I32i" - -#define PRId64 "I64d" -#define PRIi64 "I64i" -#define PRIdLEAST64 "I64d" -#define PRIiLEAST64 "I64i" -#define PRIdFAST64 "I64d" -#define PRIiFAST64 "I64i" - -#define PRIdMAX "I64d" -#define PRIiMAX "I64i" - -#define PRIdPTR "Id" -#define PRIiPTR "Ii" - -// The fprintf macros for unsigned integers are: -#define PRIo8 "o" -#define PRIu8 "u" -#define PRIx8 "x" -#define PRIX8 "X" -#define PRIoLEAST8 "o" -#define PRIuLEAST8 "u" -#define PRIxLEAST8 "x" -#define PRIXLEAST8 "X" -#define PRIoFAST8 "o" -#define PRIuFAST8 "u" -#define PRIxFAST8 "x" -#define PRIXFAST8 "X" - -#define PRIo16 "ho" -#define PRIu16 "hu" -#define PRIx16 "hx" -#define PRIX16 "hX" -#define PRIoLEAST16 "ho" -#define PRIuLEAST16 "hu" -#define PRIxLEAST16 "hx" -#define PRIXLEAST16 "hX" -#define PRIoFAST16 "ho" -#define PRIuFAST16 "hu" -#define PRIxFAST16 "hx" -#define PRIXFAST16 "hX" - -#define PRIo32 "I32o" -#define PRIu32 "I32u" -#define PRIx32 "I32x" -#define PRIX32 "I32X" -#define PRIoLEAST32 "I32o" -#define PRIuLEAST32 "I32u" -#define PRIxLEAST32 "I32x" -#define PRIXLEAST32 "I32X" -#define PRIoFAST32 "I32o" -#define PRIuFAST32 "I32u" -#define PRIxFAST32 "I32x" -#define PRIXFAST32 "I32X" - -#define PRIo64 "I64o" -#define PRIu64 "I64u" -#define PRIx64 "I64x" -#define PRIX64 "I64X" -#define PRIoLEAST64 "I64o" -#define PRIuLEAST64 "I64u" -#define PRIxLEAST64 "I64x" -#define PRIXLEAST64 "I64X" -#define PRIoFAST64 "I64o" -#define PRIuFAST64 "I64u" -#define PRIxFAST64 "I64x" -#define PRIXFAST64 "I64X" - -#define PRIoMAX "I64o" -#define PRIuMAX "I64u" -#define PRIxMAX "I64x" -#define PRIXMAX "I64X" - -#define PRIoPTR "Io" -#define PRIuPTR "Iu" -#define PRIxPTR "Ix" -#define PRIXPTR "IX" - -// The fscanf macros for signed integers are: -#define SCNd8 "d" -#define SCNi8 "i" -#define SCNdLEAST8 "d" -#define SCNiLEAST8 "i" -#define SCNdFAST8 "d" -#define SCNiFAST8 "i" - -#define SCNd16 "hd" -#define SCNi16 "hi" -#define SCNdLEAST16 "hd" -#define SCNiLEAST16 "hi" -#define SCNdFAST16 "hd" -#define SCNiFAST16 "hi" - -#define SCNd32 "ld" -#define SCNi32 "li" -#define SCNdLEAST32 "ld" -#define SCNiLEAST32 "li" -#define SCNdFAST32 "ld" -#define SCNiFAST32 "li" - -#define SCNd64 "I64d" -#define SCNi64 "I64i" -#define SCNdLEAST64 "I64d" -#define SCNiLEAST64 "I64i" -#define SCNdFAST64 "I64d" -#define SCNiFAST64 "I64i" - -#define SCNdMAX "I64d" -#define SCNiMAX "I64i" - -#ifdef _WIN64 // [ -# define SCNdPTR "I64d" -# define SCNiPTR "I64i" -#else // _WIN64 ][ -# define SCNdPTR "ld" -# define SCNiPTR "li" -#endif // _WIN64 ] - -// The fscanf macros for unsigned integers are: -#define SCNo8 "o" -#define SCNu8 "u" -#define SCNx8 "x" -#define SCNX8 "X" -#define SCNoLEAST8 "o" -#define SCNuLEAST8 "u" -#define SCNxLEAST8 "x" -#define SCNXLEAST8 "X" -#define SCNoFAST8 "o" -#define SCNuFAST8 "u" -#define SCNxFAST8 "x" -#define SCNXFAST8 "X" - -#define SCNo16 "ho" -#define SCNu16 "hu" -#define SCNx16 "hx" -#define SCNX16 "hX" -#define SCNoLEAST16 "ho" -#define SCNuLEAST16 "hu" -#define SCNxLEAST16 "hx" -#define SCNXLEAST16 "hX" -#define SCNoFAST16 "ho" -#define SCNuFAST16 "hu" -#define SCNxFAST16 "hx" -#define SCNXFAST16 "hX" - -#define SCNo32 "lo" -#define SCNu32 "lu" -#define SCNx32 "lx" -#define SCNX32 "lX" -#define SCNoLEAST32 "lo" -#define SCNuLEAST32 "lu" -#define SCNxLEAST32 "lx" -#define SCNXLEAST32 "lX" -#define SCNoFAST32 "lo" -#define SCNuFAST32 "lu" -#define SCNxFAST32 "lx" -#define SCNXFAST32 "lX" - -#define SCNo64 "I64o" -#define SCNu64 "I64u" -#define SCNx64 "I64x" -#define SCNX64 "I64X" -#define SCNoLEAST64 "I64o" -#define SCNuLEAST64 "I64u" -#define SCNxLEAST64 "I64x" -#define SCNXLEAST64 "I64X" -#define SCNoFAST64 "I64o" -#define SCNuFAST64 "I64u" -#define SCNxFAST64 "I64x" -#define SCNXFAST64 "I64X" - -#define SCNoMAX "I64o" -#define SCNuMAX "I64u" -#define SCNxMAX "I64x" -#define SCNXMAX "I64X" - -#ifdef _WIN64 // [ -# define SCNoPTR "I64o" -# define SCNuPTR "I64u" -# define SCNxPTR "I64x" -# define SCNXPTR "I64X" -#else // _WIN64 ][ -# define SCNoPTR "lo" -# define SCNuPTR "lu" -# define SCNxPTR "lx" -# define SCNXPTR "lX" -#endif // _WIN64 ] - -#endif // __STDC_FORMAT_MACROS ] - -// 7.8.2 Functions for greatest-width integer types - -// 7.8.2.1 The imaxabs function -#define imaxabs _abs64 - -// 7.8.2.2 The imaxdiv function - -// This is modified version of div() function from Microsoft's div.c found -// in %MSVC.NET%\crt\src\div.c -#ifdef STATIC_IMAXDIV // [ -static -#else // STATIC_IMAXDIV ][ -_inline -#endif // STATIC_IMAXDIV ] -imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) -{ - imaxdiv_t result; - - result.quot = numer / denom; - result.rem = numer % denom; - - if (numer < 0 && result.rem > 0) { - // did division wrong; must fix up - ++result.quot; - result.rem -= denom; - } - - return result; -} - -// 7.8.2.3 The strtoimax and strtoumax functions -#define strtoimax _strtoi64 -#define strtoumax _strtoui64 - -// 7.8.2.4 The wcstoimax and wcstoumax functions -#define wcstoimax _wcstoi64 -#define wcstoumax _wcstoui64 - - -#endif // _MSC_INTTYPES_H_ ] diff --git a/extern/libmv/third_party/msinttypes/stdint.h b/extern/libmv/third_party/msinttypes/stdint.h deleted file mode 100644 index 189ee34571c..00000000000 --- a/extern/libmv/third_party/msinttypes/stdint.h +++ /dev/null @@ -1,247 +0,0 @@ -// ISO C9x compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2008 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The name of the author may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_STDINT_H_ // [ -#define _MSC_STDINT_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include - -// For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we should wrap include with 'extern "C++" {}' -// or compiler give many errors like this: -// error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#ifdef __cplusplus -extern "C" { -#endif -# include -#ifdef __cplusplus -} -#endif - -// Define _W64 macros to mark types changing their size, like intptr_t. -#ifndef _W64 -# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -# define _W64 __w64 -# else -# define _W64 -# endif -#endif - - -// 7.18.1 Integer types - -// 7.18.1.1 Exact-width integer types - -// Visual Studio 6 and Embedded Visual C++ 4 doesn't -// realize that, e.g. char has the same size as __int8 -// so we give up on __intX for them. -#if (_MSC_VER < 1300) - 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 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; -#endif -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; - - -// 7.18.1.2 Minimum-width integer types -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -typedef int64_t int_least64_t; -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -typedef uint64_t uint_least64_t; - -// 7.18.1.3 Fastest minimum-width integer types -typedef int8_t int_fast8_t; -typedef int16_t int_fast16_t; -typedef int32_t int_fast32_t; -typedef int64_t int_fast64_t; -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; - -// 7.18.1.4 Integer types capable of holding object pointers -#ifdef _WIN64 // [ - typedef __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -#else // _WIN64 ][ - typedef _W64 int intptr_t; - typedef _W64 unsigned int uintptr_t; -#endif // _WIN64 ] - -// 7.18.1.5 Greatest-width integer types -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] - -// WCHAR_MIN and WCHAR_MAX are also defined in -#ifndef WCHAR_MIN // [ -# define WCHAR_MIN 0 -#endif // WCHAR_MIN ] -#ifndef WCHAR_MAX // [ -# define WCHAR_MAX _UI16_MAX -#endif // WCHAR_MAX ] - -#define WINT_MIN 0 -#define WINT_MAX _UI16_MAX - -#endif // __STDC_LIMIT_MACROS ] - - -// 7.18.4 Limits of other integer types - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -#define INTMAX_C INT64_C -#define UINTMAX_C UINT64_C - -#endif // __STDC_CONSTANT_MACROS ] - - -#endif // _MSC_STDINT_H_ ] -- cgit v1.2.3