Camera tracking integration
authorSergey Sharybin <sergey.vfx@gmail.com>
Mon, 7 Nov 2011 12:55:18 +0000 (12:55 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Mon, 7 Nov 2011 12:55:18 +0000 (12:55 +0000)
===========================

Commiting camera tracking integration gsoc project into trunk.

This commit includes:

- Bundled version of libmv library (with some changes against official repo,
  re-sync with libmv repo a bit later)
- New datatype ID called MovieClip which is optimized to work with movie
  clips (both of movie files and image sequences) and doing camera/motion
  tracking operations.
- New editor called Clip Editor which is currently used for motion/tracking
  stuff only, but which can be easily extended to work with masks too.

  This editor supports:
  * Loading movie files/image sequences
  * Build proxies with different size for loaded movie clip, also supports
    building undistorted proxies to increase speed of playback in
    undistorted mode.
  * Manual lens distortion mode calibration using grid and grease pencil
  * Supervised 2D tracking using two different algorithms KLT and SAD.
  * Basic algorithm for feature detection
  * Camera motion solving. scene orientation

- New constraints to "link" scene objects with solved motions from clip:

  * Follow Track (make object follow 2D motion of track with given name
    or parent object to reconstructed 3D position of track)
  * Camera Solver to make camera moving in the same way as reconstructed camera

This commit NOT includes changes from tomato branch:

- New nodes (they'll be commited as separated patch)
- Automatic image offset guessing for image input node and image editor
  (need to do more tests and gather more feedback)
- Code cleanup in libmv-capi. It's not so critical cleanup, just increasing
  readability and understanadability of code. Better to make this chaneg when
  Keir will finish his current patch.

More details about this project can be found on this page:
    http://wiki.blender.org/index.php/User:Nazg-gul/GSoC-2011

Further development of small features would be done in trunk, bigger/experimental
features would first be implemented in tomato branch.

306 files changed:
CMakeLists.txt
build_files/scons/tools/Blender.py
build_files/scons/tools/btools.py
extern/CMakeLists.txt
extern/SConscript
extern/libmv/CMakeLists.txt [new file with mode: 0644]
extern/libmv/ChangeLog [new file with mode: 0644]
extern/libmv/SConscript [new file with mode: 0644]
extern/libmv/bundle.sh [new file with mode: 0755]
extern/libmv/files.txt [new file with mode: 0644]
extern/libmv/libmv-capi.cpp [new file with mode: 0644]
extern/libmv/libmv-capi.h [new file with mode: 0644]
extern/libmv/libmv/base/id_generator.h [new file with mode: 0644]
extern/libmv/libmv/base/scoped_ptr.h [new file with mode: 0644]
extern/libmv/libmv/base/vector.h [new file with mode: 0644]
extern/libmv/libmv/base/vector_utils.h [new file with mode: 0644]
extern/libmv/libmv/image/array_nd.cc [new file with mode: 0644]
extern/libmv/libmv/image/array_nd.h [new file with mode: 0644]
extern/libmv/libmv/image/convolve.cc [new file with mode: 0644]
extern/libmv/libmv/image/convolve.h [new file with mode: 0644]
extern/libmv/libmv/image/image.h [new file with mode: 0644]
extern/libmv/libmv/image/sample.h [new file with mode: 0644]
extern/libmv/libmv/image/tuple.h [new file with mode: 0644]
extern/libmv/libmv/logging/logging.h [new file with mode: 0644]
extern/libmv/libmv/multiview/conditioning.cc [new file with mode: 0644]
extern/libmv/libmv/multiview/conditioning.h [new file with mode: 0644]
extern/libmv/libmv/multiview/euclidean_resection.cc [new file with mode: 0644]
extern/libmv/libmv/multiview/euclidean_resection.h [new file with mode: 0644]
extern/libmv/libmv/multiview/fundamental.cc [new file with mode: 0644]
extern/libmv/libmv/multiview/fundamental.h [new file with mode: 0644]
extern/libmv/libmv/multiview/nviewtriangulation.h [new file with mode: 0644]
extern/libmv/libmv/multiview/projection.cc [new file with mode: 0644]
extern/libmv/libmv/multiview/projection.h [new file with mode: 0644]
extern/libmv/libmv/multiview/resection.h [new file with mode: 0644]
extern/libmv/libmv/multiview/triangulation.cc [new file with mode: 0644]
extern/libmv/libmv/multiview/triangulation.h [new file with mode: 0644]
extern/libmv/libmv/numeric/dogleg.h [new file with mode: 0644]
extern/libmv/libmv/numeric/function_derivative.h [new file with mode: 0644]
extern/libmv/libmv/numeric/levenberg_marquardt.h [new file with mode: 0644]
extern/libmv/libmv/numeric/numeric.cc [new file with mode: 0644]
extern/libmv/libmv/numeric/numeric.h [new file with mode: 0644]
extern/libmv/libmv/numeric/poly.cc [new file with mode: 0644]
extern/libmv/libmv/numeric/poly.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/bundle.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/bundle.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/camera_intrinsics.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/detect.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/detect.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/intersect.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/intersect.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/pipeline.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/pipeline.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/reconstruction.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/reconstruction.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/resect.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/resect.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/tracks.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/tracks.h [new file with mode: 0644]
extern/libmv/libmv/tracking/klt_region_tracker.cc [new file with mode: 0644]
extern/libmv/libmv/tracking/klt_region_tracker.h [new file with mode: 0644]
extern/libmv/libmv/tracking/pyramid_region_tracker.cc [new file with mode: 0644]
extern/libmv/libmv/tracking/pyramid_region_tracker.h [new file with mode: 0644]
extern/libmv/libmv/tracking/region_tracker.h [new file with mode: 0644]
extern/libmv/libmv/tracking/retrack_region_tracker.cc [new file with mode: 0644]
extern/libmv/libmv/tracking/retrack_region_tracker.h [new file with mode: 0644]
extern/libmv/libmv/tracking/sad.cc [new file with mode: 0644]
extern/libmv/libmv/tracking/sad.h [new file with mode: 0644]
extern/libmv/libmv/tracking/trklt_region_tracker.cc [new file with mode: 0644]
extern/libmv/libmv/tracking/trklt_region_tracker.h [new file with mode: 0644]
extern/libmv/mkfiles.sh [new file with mode: 0755]
extern/libmv/patches/bundle_tweaks.patch [new file with mode: 0644]
extern/libmv/patches/config_mac.patch [new file with mode: 0644]
extern/libmv/patches/detect.patch [new file with mode: 0644]
extern/libmv/patches/fast.patch [new file with mode: 0644]
extern/libmv/patches/function_derivative.patch [new file with mode: 0644]
extern/libmv/patches/high_distortion_crash_fix.patch [new file with mode: 0644]
extern/libmv/patches/levenberg_marquardt.patch [new file with mode: 0644]
extern/libmv/patches/mingw.patch [new file with mode: 0644]
extern/libmv/patches/msvc2010.patch [new file with mode: 0644]
extern/libmv/patches/overscan.patch [new file with mode: 0644]
extern/libmv/patches/scaled_distortion.patch [new file with mode: 0644]
extern/libmv/patches/series [new file with mode: 0644]
extern/libmv/patches/snrptinf_fix.patch [new file with mode: 0644]
extern/libmv/patches/v3d_verbosity.patch [new file with mode: 0644]
extern/libmv/third_party/fast/LICENSE [new file with mode: 0644]
extern/libmv/third_party/fast/README [new file with mode: 0644]
extern/libmv/third_party/fast/README.libmv [new file with mode: 0644]
extern/libmv/third_party/fast/fast.c [new file with mode: 0644]
extern/libmv/third_party/fast/fast.h [new file with mode: 0644]
extern/libmv/third_party/fast/fast_10.c [new file with mode: 0644]
extern/libmv/third_party/fast/fast_11.c [new file with mode: 0644]
extern/libmv/third_party/fast/fast_12.c [new file with mode: 0644]
extern/libmv/third_party/fast/fast_9.c [new file with mode: 0644]
extern/libmv/third_party/fast/nonmax.c [new file with mode: 0644]
extern/libmv/third_party/gflags/README.libmv [new file with mode: 0644]
extern/libmv/third_party/gflags/config.h [new file with mode: 0644]
extern/libmv/third_party/gflags/gflags.cc [new file with mode: 0644]
extern/libmv/third_party/gflags/gflags.h [new file with mode: 0644]
extern/libmv/third_party/gflags/gflags_completions.cc [new file with mode: 0644]
extern/libmv/third_party/gflags/gflags_completions.h [new file with mode: 0644]
extern/libmv/third_party/gflags/gflags_reporting.cc [new file with mode: 0644]
extern/libmv/third_party/gflags/mutex.h [new file with mode: 0644]
extern/libmv/third_party/glog/AUTHORS [new file with mode: 0644]
extern/libmv/third_party/glog/COPYING [new file with mode: 0644]
extern/libmv/third_party/glog/ChangeLog [new file with mode: 0644]
extern/libmv/third_party/glog/NEWS [new file with mode: 0644]
extern/libmv/third_party/glog/README [new file with mode: 0644]
extern/libmv/third_party/glog/README.libmv [new file with mode: 0644]
extern/libmv/third_party/glog/src/base/commandlineflags.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/base/googleinit.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/base/mutex.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/config.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/config_linux.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/config_mac.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/demangle.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/demangle.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/glog/log_severity.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/glog/logging.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/glog/raw_logging.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/glog/vlog_is_on.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/logging.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/raw_logging.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/signalhandler.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace_generic-inl.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace_libunwind-inl.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace_powerpc-inl.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace_x86-inl.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace_x86_64-inl.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/symbolize.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/symbolize.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/utilities.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/utilities.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/vlog_is_on.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/config.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/glog/log_severity.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/glog/logging.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/glog/raw_logging.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/glog/vlog_is_on.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/port.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/port.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/preprocess.sh [new file with mode: 0755]
extern/libmv/third_party/ldl/CMakeLists.txt [new file with mode: 0644]
extern/libmv/third_party/ldl/Doc/ChangeLog [new file with mode: 0644]
extern/libmv/third_party/ldl/Doc/lesser.txt [new file with mode: 0644]
extern/libmv/third_party/ldl/Include/ldl.h [new file with mode: 0644]
extern/libmv/third_party/ldl/README.libmv [new file with mode: 0644]
extern/libmv/third_party/ldl/README.txt [new file with mode: 0644]
extern/libmv/third_party/ldl/Source/ldl.c [new file with mode: 0644]
extern/libmv/third_party/msinttypes/README.libmv [new file with mode: 0644]
extern/libmv/third_party/msinttypes/inttypes.h [new file with mode: 0644]
extern/libmv/third_party/msinttypes/stdint.h [new file with mode: 0644]
extern/libmv/third_party/ssba/COPYING.TXT [new file with mode: 0644]
extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Geometry/v3d_distortion.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp [new file with mode: 0644]
extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Math/v3d_linear.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Math/v3d_linear_utils.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Math/v3d_mathutilities.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Math/v3d_optimization.cpp [new file with mode: 0644]
extern/libmv/third_party/ssba/Math/v3d_optimization.h [new file with mode: 0644]
extern/libmv/third_party/ssba/README.TXT [new file with mode: 0644]
extern/libmv/third_party/ssba/README.libmv [new file with mode: 0755]
release/datafiles/blender_icons.png
release/scripts/modules/bpy_extras/keyconfig_utils.py
release/scripts/presets/tracking_camera/Blender.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Canon_1100D.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Canon_1D.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Canon_1DS.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Canon_500D.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Canon_550D.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Canon_5D.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Canon_600D.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Canon_60D.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Canon_7D.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Nikon_D300S.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Nikon_D3100.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Nikon_D35.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Nikon_D5000.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Nikon_D5100.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Nikon_D7000.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Nikon_D90.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Red_Epic.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Red_One_2K.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Red_One_3K.py [new file with mode: 0644]
release/scripts/presets/tracking_camera/Red_One_4K.py [new file with mode: 0644]
release/scripts/presets/tracking_track_color/default.py [new file with mode: 0644]
release/scripts/presets/tracking_track_color/far_plane.py [new file with mode: 0644]
release/scripts/presets/tracking_track_color/near_plane.py [new file with mode: 0644]
release/scripts/startup/bl_operators/__init__.py
release/scripts/startup/bl_operators/clip.py [new file with mode: 0644]
release/scripts/startup/bl_operators/presets.py
release/scripts/startup/bl_ui/__init__.py
release/scripts/startup/bl_ui/properties_object_constraint.py
release/scripts/startup/bl_ui/properties_scene.py
release/scripts/startup/bl_ui/space_clip.py [new file with mode: 0644]
release/scripts/startup/bl_ui/space_time.py
release/scripts/startup/bl_ui/space_view3d.py
source/blender/CMakeLists.txt
source/blender/blenkernel/BKE_context.h
source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/BKE_main.h
source/blender/blenkernel/BKE_movieclip.h [new file with mode: 0644]
source/blender/blenkernel/BKE_object.h
source/blender/blenkernel/BKE_tracking.h [new file with mode: 0644]
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/SConscript
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/context.c
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/idcode.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/movieclip.c [new file with mode: 0644]
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/tracking.c [new file with mode: 0644]
source/blender/blenlib/BLI_threads.h
source/blender/blenlib/intern/threads.c
source/blender/blenloader/intern/readblenentry.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/readfile.h
source/blender/blenloader/intern/writefile.c
source/blender/editors/CMakeLists.txt
source/blender/editors/SConscript
source/blender/editors/datafiles/blender_icons.png.c
source/blender/editors/gpencil/drawgpencil.c
source/blender/editors/gpencil/editaction_gpencil.c
source/blender/editors/gpencil/gpencil_edit.c
source/blender/editors/gpencil/gpencil_paint.c
source/blender/editors/include/ED_clip.h [new file with mode: 0644]
source/blender/editors/include/ED_space_api.h
source/blender/editors/include/ED_transform.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/include/UI_icons.h
source/blender/editors/include/UI_interface.h
source/blender/editors/include/UI_resources.h
source/blender/editors/interface/interface_draw.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_intern.h
source/blender/editors/interface/interface_templates.c
source/blender/editors/interface/interface_widgets.c
source/blender/editors/interface/resources.c
source/blender/editors/object/object_constraint.c
source/blender/editors/screen/area.c
source/blender/editors/screen/screen_edit.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/space_api/spacetypes.c
source/blender/editors/space_clip/CMakeLists.txt [new file with mode: 0644]
source/blender/editors/space_clip/SConscript [new file with mode: 0644]
source/blender/editors/space_clip/clip_buttons.c [new file with mode: 0644]
source/blender/editors/space_clip/clip_draw.c [new file with mode: 0644]
source/blender/editors/space_clip/clip_editor.c [new file with mode: 0644]
source/blender/editors/space_clip/clip_graph_draw.c [new file with mode: 0644]
source/blender/editors/space_clip/clip_graph_ops.c [new file with mode: 0644]
source/blender/editors/space_clip/clip_intern.h [new file with mode: 0644]
source/blender/editors/space_clip/clip_ops.c [new file with mode: 0644]
source/blender/editors/space_clip/clip_toolbar.c [new file with mode: 0644]
source/blender/editors/space_clip/clip_utils.c [new file with mode: 0644]
source/blender/editors/space_clip/space_clip.c [new file with mode: 0644]
source/blender/editors/space_clip/tracking_ops.c [new file with mode: 0644]
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_intern.h
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/space_view3d/view3d_snap.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_ops.c
source/blender/editors/util/CMakeLists.txt
source/blender/makesdna/DNA_ID.h
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesdna/DNA_movieclip_types.h [new file with mode: 0644]
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_space_types.h
source/blender/makesdna/DNA_tracking_types.h [new file with mode: 0644]
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesdna/intern/makesdna.c
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_constraint.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_main.c
source/blender/makesrna/intern/rna_main_api.c
source/blender/makesrna/intern/rna_movieclip.c [new file with mode: 0644]
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_screen.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_tracking.c [new file with mode: 0644]
source/blender/makesrna/intern/rna_ui_api.c
source/blender/makesrna/intern/rna_userdef.c
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_operators.c
source/blenderplayer/CMakeLists.txt
source/blenderplayer/bad_level_call_stubs/stubs.c
source/creator/CMakeLists.txt
source/creator/creator.c

index 0e06f39e7187267081979e683737820a6e2aa42a..6bc409fe0df5d056beb1fb7c10da9a995999abfd 100644 (file)
@@ -202,6 +202,9 @@ option(WITH_JACK          "Enable Jack Support (http://www.jackaudio.org)" OFF)
 option(WITH_LZO           "Enable fast LZO compression (used for pointcache)" ON)
 option(WITH_LZMA          "Enable best LZMA compression, (used for pointcache)" ON)
 
+# Camera/motion tracking
+option(WITH_LIBMV         "Enable libmv structure from motion library" ON)
+
 # Misc
 option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ON)
 option(WITH_RAYOPTIMIZATION    "Enable use of SIMD (SSE) optimizations for the raytracer" ON)
index 44f9a4c8062a6b60bcb100e88e66fc6be54d5e89..ba15f1c1c09a9e5415448b123233c8a8c87a788f 100644 (file)
@@ -329,6 +329,10 @@ def creator(env):
     if env['WITH_BF_SDL']:
         defs.append('WITH_SDL')
 
+    if env['WITH_BF_LIBMV']:
+        incs.append('#/extern/libmv')
+        defs.append('WITH_LIBMV')
+
     if env['WITH_BF_PYTHON']:
         incs.append('#/source/blender/python')
         defs.append('WITH_PYTHON')
index 68054fe485e3d6326408c6ddb8152a946c162aab..5c78dc646bb1980a50290d858fe5aae16d2fd6f5 100644 (file)
@@ -515,6 +515,8 @@ def read_opts(env, cfg, args):
         (BoolVariable('WITH_BF_LZO', 'Enable fast LZO pointcache compression', True)),
         (BoolVariable('WITH_BF_LZMA', 'Enable best LZMA pointcache compression', True)),
         
+        (BoolVariable('WITH_BF_LIBMV', 'Enable libmv structure from motion library', True)),
+
         ('BF_X264_CONFIG', 'configuration flags for x264', ''),
         ('BF_XVIDCORE_CONFIG', 'configuration flags for xvidcore', ''),
 #        (BoolVariable('WITH_BF_DOCS', 'Generate API documentation', False)),
index 321ebc11985dca3e0c84d7001453142e62d8e69c..a5dd3b168607b4b10b376a0e66fe9701307f4711 100644 (file)
@@ -63,3 +63,7 @@ endif()
 if(WITH_LZMA)
        add_subdirectory(lzma)
 endif()
+
+if(WITH_LIBMV)
+       add_subdirectory(libmv)
+endif()
index f363d75d0683088ab71c4a50d114fc7ef932eebc..031471a8a016cfc71c9212d83a60534f1fea5c49 100644 (file)
@@ -28,3 +28,6 @@ if env['WITH_BF_LZO']:
 
 if env['WITH_BF_LZMA']:
     SConscript(['lzma/SConscript'])
+
+if env['WITH_BF_LIBMV']:
+    SConscript(['libmv/SConscript'])
diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt
new file mode 100644 (file)
index 0000000..41fc39c
--- /dev/null
@@ -0,0 +1,210 @@
+# ***** 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2011, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+#                 Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+       .
+       ../Eigen3
+       ./third_party/ssba
+       ./third_party/ldl/Include
+       ../colamd/Include
+)
+
+set(INC_SYS
+       ${PNG_INCLUDE_DIR}
+       ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+       libmv-capi.cpp
+       libmv/numeric/numeric.cc
+       libmv/numeric/poly.cc
+       libmv/simple_pipeline/reconstruction.cc
+       libmv/simple_pipeline/resect.cc
+       libmv/simple_pipeline/intersect.cc
+       libmv/simple_pipeline/initialize_reconstruction.cc
+       libmv/simple_pipeline/camera_intrinsics.cc
+       libmv/simple_pipeline/pipeline.cc
+       libmv/simple_pipeline/detect.cc
+       libmv/simple_pipeline/tracks.cc
+       libmv/simple_pipeline/bundle.cc
+       libmv/image/convolve.cc
+       libmv/image/array_nd.cc
+       libmv/tracking/pyramid_region_tracker.cc
+       libmv/tracking/sad.cc
+       libmv/tracking/trklt_region_tracker.cc
+       libmv/tracking/klt_region_tracker.cc
+       libmv/tracking/retrack_region_tracker.cc
+       libmv/multiview/projection.cc
+       libmv/multiview/conditioning.cc
+       libmv/multiview/fundamental.cc
+       libmv/multiview/euclidean_resection.cc
+       libmv/multiview/triangulation.cc
+
+       third_party/ssba/Geometry/v3d_metricbundle.cpp
+       third_party/ssba/Math/v3d_optimization.cpp
+       third_party/gflags/gflags.cc
+       third_party/gflags/gflags_reporting.cc
+       third_party/gflags/gflags_completions.cc
+       third_party/fast/fast_9.c
+       third_party/fast/fast_10.c
+       third_party/fast/fast_11.c
+       third_party/fast/fast_12.c
+       third_party/fast/fast.c
+       third_party/fast/nonmax.c
+       third_party/ldl/Source/ldl.c
+
+       libmv-capi.h
+       libmv/logging/logging.h
+       libmv/numeric/dogleg.h
+       libmv/numeric/levenberg_marquardt.h
+       libmv/numeric/poly.h
+       libmv/numeric/function_derivative.h
+       libmv/numeric/numeric.h
+       libmv/simple_pipeline/resect.h
+       libmv/simple_pipeline/reconstruction.h
+       libmv/simple_pipeline/camera_intrinsics.h
+       libmv/simple_pipeline/tracks.h
+       libmv/simple_pipeline/detect.h
+       libmv/simple_pipeline/pipeline.h
+       libmv/simple_pipeline/intersect.h
+       libmv/simple_pipeline/bundle.h
+       libmv/simple_pipeline/initialize_reconstruction.h
+       libmv/image/convolve.h
+       libmv/image/tuple.h
+       libmv/image/array_nd.h
+       libmv/image/sample.h
+       libmv/image/image.h
+       libmv/tracking/region_tracker.h
+       libmv/tracking/retrack_region_tracker.h
+       libmv/tracking/sad.h
+       libmv/tracking/pyramid_region_tracker.h
+       libmv/tracking/trklt_region_tracker.h
+       libmv/tracking/klt_region_tracker.h
+       libmv/base/id_generator.h
+       libmv/base/vector.h
+       libmv/base/scoped_ptr.h
+       libmv/base/vector_utils.h
+       libmv/multiview/nviewtriangulation.h
+       libmv/multiview/resection.h
+       libmv/multiview/euclidean_resection.h
+       libmv/multiview/triangulation.h
+       libmv/multiview/projection.h
+       libmv/multiview/fundamental.h
+       libmv/multiview/conditioning.h
+
+       third_party/ssba/Geometry/v3d_metricbundle.h
+       third_party/ssba/Geometry/v3d_cameramatrix.h
+       third_party/ssba/Geometry/v3d_distortion.h
+       third_party/ssba/Math/v3d_linear_utils.h
+       third_party/ssba/Math/v3d_optimization.h
+       third_party/ssba/Math/v3d_mathutilities.h
+       third_party/ssba/Math/v3d_linear.h
+       third_party/gflags/gflags_completions.h
+       third_party/gflags/mutex.h
+       third_party/gflags/config.h
+       third_party/gflags/gflags.h
+       third_party/fast/fast.h
+       third_party/ldl/Include/ldl.h
+       third_party/msinttypes/stdint.h
+       third_party/msinttypes/inttypes.h
+)
+
+IF(WIN32)
+       list(APPEND SRC
+               third_party/glog/src/logging.cc
+               third_party/glog/src/raw_logging.cc
+               third_party/glog/src/utilities.cc
+               third_party/glog/src/vlog_is_on.cc
+               third_party/glog/src/windows/port.cc
+
+               third_party/glog/src/utilities.h
+               third_party/glog/src/stacktrace_generic-inl.h
+               third_party/glog/src/stacktrace.h
+               third_party/glog/src/stacktrace_x86_64-inl.h
+               third_party/glog/src/base/googleinit.h
+               third_party/glog/src/base/mutex.h
+               third_party/glog/src/base/commandlineflags.h
+               third_party/glog/src/stacktrace_powerpc-inl.h
+               third_party/glog/src/stacktrace_x86-inl.h
+               third_party/glog/src/config.h
+               third_party/glog/src/stacktrace_libunwind-inl.h
+               third_party/glog/src/windows/glog/raw_logging.h
+               third_party/glog/src/windows/glog/vlog_is_on.h
+               third_party/glog/src/windows/glog/logging.h
+               third_party/glog/src/windows/glog/log_severity.h
+               third_party/glog/src/windows/port.h
+               third_party/glog/src/windows/config.h
+       )
+
+       list(APPEND INC
+               ./third_party/glog/src/windows
+               ./third_party/msinttypes
+       )
+
+       IF(MSVC)
+               set(MSVC_OFLAGS O1 O2 Ox)
+               foreach(FLAG )
+                       string(REPLACE "" "Od" CMAKE_CXX_FLAGS_RELEASE "")
+                       string(REPLACE "" "Od" CMAKE_C_FLAGS_RELWITHDEBINFO "")
+               endforeach()
+       ENDIF(MSVC)
+ELSE(WIN32)
+       list(APPEND SRC
+               third_party/glog/src/utilities.cc
+               third_party/glog/src/symbolize.cc
+               third_party/glog/src/vlog_is_on.cc
+               third_party/glog/src/signalhandler.cc
+               third_party/glog/src/logging.cc
+               third_party/glog/src/demangle.cc
+               third_party/glog/src/raw_logging.cc
+
+               third_party/glog/src/utilities.h
+               third_party/glog/src/stacktrace_generic-inl.h
+               third_party/glog/src/config_mac.h
+               third_party/glog/src/stacktrace.h
+               third_party/glog/src/stacktrace_x86_64-inl.h
+               third_party/glog/src/symbolize.h
+               third_party/glog/src/base/googleinit.h
+               third_party/glog/src/base/mutex.h
+               third_party/glog/src/base/commandlineflags.h
+               third_party/glog/src/stacktrace_powerpc-inl.h
+               third_party/glog/src/stacktrace_x86-inl.h
+               third_party/glog/src/config.h
+               third_party/glog/src/demangle.h
+               third_party/glog/src/stacktrace_libunwind-inl.h
+               third_party/glog/src/glog/raw_logging.h
+               third_party/glog/src/glog/vlog_is_on.h
+               third_party/glog/src/glog/logging.h
+               third_party/glog/src/glog/log_severity.h
+               third_party/glog/src/config_linux.h
+       )
+
+       list(APPEND INC
+               ./third_party/glog/src
+       )
+ENDIF(WIN32)
+
+add_definitions(-DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL=)
+
+blender_add_lib(extern_libmv "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/libmv/ChangeLog b/extern/libmv/ChangeLog
new file mode 100644 (file)
index 0000000..7e10abf
--- /dev/null
@@ -0,0 +1,312 @@
+commit 531c79bf95fddaaa70707d1abcd4fdafda16bbf0
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sat Aug 20 00:00:42 2011 +0200
+
+    Display warped pattern in marker preview.
+
+commit bb5c27e671b6f8eb56ddf490f0795d59bede591b
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 19 18:37:48 2011 +0200
+
+    Fix CMake build.
+
+commit 2ac7281ff6b9545b425dd84fb03bf9c5c98b4de2
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 19 17:34:45 2011 +0200
+
+    Avoid symbol shadowing.
+
+commit 2a7c3de4acc60e0433b4952f69e30528dbafe0d2
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 19 17:22:47 2011 +0200
+
+    Better dragging behavior when hitting borders.
+
+commit a14eb3953c9521b2e08ff9ddd45b33ff1f8aeafb
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 19 17:12:12 2011 +0200
+
+    Update marker preview to new affine tracking.
+
+commit 5299ea67043459eda147950e589c2d327a8fbced
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 19 16:05:54 2011 +0200
+
+    sqrt takes double precision.
+
+commit 9f9221ce151d788c49b48f6f293ab2e2f8813978
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 19 16:04:37 2011 +0200
+
+    MSVC compatibility: heap allocate pattern, explicit float cast.
+
+commit 702658d2f8616964a6eeb3743fd85e97ac7ff09d
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 19 14:59:24 2011 +0200
+
+    Expose regularization parameters (areaPenalty and conditionPenalty) in API.
+
+commit 3e84ae5fbac10451d4935418f6281a90cedace11
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 19 14:19:27 2011 +0200
+
+    Add LaplaceFilter.
+    Add regularization in affine SAD Tracker (keep constant area and good condition number).
+    UI: Better track display (+enable line antialiasing).
+
+commit 6d26d9a8ccc4ce009fbf253898fea8864dd5001a
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 19 10:25:26 2011 +0200
+
+    Add optimization for integer pixel search.
+    Allows more agressive settings for affine coordinate descent.
+
+commit 70ceae81c0ab561b07e640ecb9933f0a902b57cd
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 19 00:02:12 2011 +0200
+
+    Document coordinate descent method in affine SAD matcher.
+    Add heuristic to prevent high distortions.
+
+commit 75520f4bc4ccbb272a1b4149d3b8d05a90f7f896
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Aug 18 23:14:17 2011 +0200
+
+    Fix affine iteration.
+
+commit 4e8e0aa6018e3eb2fbebdad7f1cbd6c909d26e79
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Aug 18 23:03:26 2011 +0200
+
+    Handle rotations.
+
+commit 3ce41cf3c1b5c136a61d8f4c63ccae3cafbdb8da
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Aug 18 22:24:47 2011 +0200
+
+    Slow brute-force affine diamond search implementation.
+
+commit 1c4acd03e030c1c50dc6fc36c419c72ea69a0713
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Aug 18 20:51:43 2011 +0200
+
+    Fix detect.cc.
+
+commit ec18cc5ea9ae2e641075a847e82d0aacb8415ad8
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Aug 18 17:45:37 2011 +0200
+
+    Compute and return Pearson product-moment correlation coefficient between reference and matched pattern.
+
+commit 21d4245c63a01bfc736192d55baf10983e7c9ec7
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Aug 18 16:18:44 2011 +0200
+
+    UI and API support for affine tracking.
+
+commit a4876d8c40dcde615b44009c38c49e9a1b1d4698
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Aug 17 20:26:01 2011 +0200
+
+    Hack to make sad.cc compile with MSVC on system without support for the SSE instruction set.
+
+commit 0de723dfce5bbe44dbd19be8cd6dd6e9b03b7924
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Aug 17 20:10:46 2011 +0200
+
+    Fix slow path (for computers without SSE2).
+    Heap allocate scores in detect.cc
+
+commit 65a9d496f81e8b37eae39a4063957b8be9a4e6f0
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Aug 17 19:25:17 2011 +0200
+
+    Fix compilation on OSX.
+
+commit d22720e618456329388d2c107422c3b371657cba
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Aug 17 14:14:45 2011 +0200
+
+    Improve Detect and SAD Tracker API and documentation.
+
+commit 5d6cd4ad365b061901bad40695b51d568487a0cf
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Aug 17 11:57:29 2011 +0200
+
+    MSVC support fixes.
+
+commit 50f0323173c6deebd6aaf9c126f0b51b2a79c3c1
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 16 23:21:37 2011 +0200
+
+    Detector can detect features similar to a given pattern.
+
+commit 5734cc27bbf84c2b6edcfcc1ea736798e12d5820
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 16 22:53:54 2011 +0200
+
+    Ensure SAD Tracker is C compatible.
+    Update Detect API documentation.
+
+commit 701c42842574064fea992f8822e3899cb9066108
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 16 21:56:42 2011 +0200
+
+    Remove FAST detector.
+    Add Moravec detector.
+    This detector is more suited to tracking since it try to choose patterns which are unlikely to drift by computing SAD with neighbouring patches.
+    It could be improved to better avoid edges.
+
+commit 9bdf93e13fc880c78b6f34397da673388c16040e
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 16 21:55:08 2011 +0200
+
+    Fix Qt Tracker GL to work with AMD drivers.
+
+commit 81613ee0cc94b315f333c9632b18b95d426aad05
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 16 21:54:12 2011 +0200
+
+    Make CameraIntrinsics (and thus Qt tracker) compilable without linking libmv.
+
+commit a1d9a8fa8b01ef7cf2a79b3b891633fc333fc9cf
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 16 21:24:51 2011 +0200
+
+    Fix SAD tracker. Pattern was transposed by affine pattern sampler.
+
+commit c3b794da2e7fd23f2fbdf90dbd71de0e6b3bc811
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 16 21:19:02 2011 +0200
+
+    Fix SAD tracker. Pattern was transposed by affine pattern sampler.
+
+commit a9b61bf3356f27174cdd983f562f99c3a6a2cc35
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sun Aug 14 09:56:51 2011 +0200
+
+    Clarify CameraIntrinsics documentation.
+    Edit CameraInstrinsics test to fail.
+
+commit 10bdad9ad2cea2603896263cde5a5339169a9af0
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 12 21:05:32 2011 +0200
+
+    Fix out of bound access in warp bilinear sampling.
+
+commit dd9a418db021a28af2c1198d5e5b9e68fe048a03
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 12 19:14:36 2011 +0200
+
+    Fix compilation with -funsigned-char.
+
+commit bd1a268ede39b67f2ba4b360f6fc693419e7cd7f
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Aug 12 18:39:27 2011 +0200
+
+    CameraIntrinsics fixes.
+
+commit ae513b39fb779632f96ceff7c1e014fb8e68702a
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 9 19:38:58 2011 +0200
+
+    Remove stray QDebug include.
+
+commit 1e58f55078ce6009a885be30ae0316aec6ed8239
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 9 14:16:31 2011 +0200
+
+    Make API future-proof (for an eventual affine or planar tracker).
+
+commit c2af303e7bf0dddcb02937323ac5846b1801e6cc
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 9 11:13:29 2011 +0200
+
+    Remove reconstruction breaking debug code.
+
+commit 8792a633e5c5f1c1f12e164b9e8897ca0790ac59
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 9 10:49:18 2011 +0200
+
+    Remove getchar()s.
+
+commit 63a9bdee0cbd1197e0315d01c27bfc2361bd5656
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 9 10:35:07 2011 +0200
+
+    Adapt patch to new PipelineRoutines code generation strategy.
+
+commit 096ff1a4070f7212c50fb0a4b2feec7ca9d97158
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 9 09:54:12 2011 +0200
+
+    Merge max_image and max_track fix from tomato.
+
+commit d8450cd3c37278a397482cd36b1e2419f154cfb9
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Aug 9 09:38:49 2011 +0200
+
+    Synchronize tree with Tomato: Merge patch for better resection, keep deprecated KLT tracker.
+
+commit e9b2dca920cf9575c15150a4988634b00e343a41
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Mon Aug 8 17:07:08 2011 +0200
+
+    Fixes, Documentation.
+
+commit 4fc1c57a2d92442808ac4a3676e6d9a25a51e310
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sun Aug 7 14:35:08 2011 +0200
+
+    Improve tracker resilience by penalizing large motion vectors.
+
+commit cc8e7e8e08cd91f75c080a0091461ca9fe969664
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sun Aug 7 09:28:09 2011 +0200
+
+    Leverage SSE2 SAD instruction for 16x speed improvement in integer pixel search resulting in ~1ms per marker for 16x16 pattern on 128x128 region.
+
+commit f362ab4999a768370fca57552464b459eb9fbddc
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sun Aug 7 09:06:04 2011 +0200
+
+    Improve SAD Tracker subpixel precision (avoid drift even when adapting at each frame).
+
+commit fce7a214c561b5f5f0e17115c31fb48814bde2db
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sat Aug 6 21:57:06 2011 +0200
+
+    Track using simple Sum of Absolute Differences matching.
+    This method is simpler, more robust, faster and accurate.
+
+commit 620a7a35d9a2818bf6e9dbf5d11debda4be6bc26
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Jul 29 12:35:57 2011 +0200
+
+    Add Intersect unit test.
+
+commit a2bf58fa57be11215eb17ff7f7de58f97d480ec3
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jul 28 11:08:06 2011 +0200
+
+    Remove tests depending on dead code.
+    Fix CameraIntrinsics test.
+    Add Intersect and Resect tests.
+
+commit 19bddee10b4879c8cd2238ccdf5b8f7620cf8384
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jul 27 12:07:21 2011 +0200
+
+    Image Distortion: Fixes and more testing.
+
+commit 0454d97da328fb0eda8c6c50511ac31864a6d3d6
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jul 27 10:32:37 2011 +0200
+
+    Test float image distortion.
+
+commit 8db01595a8721f766d85931a8d92b780461d8741
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jul 27 10:27:07 2011 +0200
+
+    Image Distortion: Bilinear sampling, Optimization, Instantiate all variants (Distort/Undistort, float/ubyte, 1-4 channels).
diff --git a/extern/libmv/SConscript b/extern/libmv/SConscript
new file mode 100644 (file)
index 0000000..1ffc623
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+import sys
+import os
+
+Import('env')
+
+defs = []
+
+cflags_libmv = Split(env['CFLAGS'])
+ccflags_libmv = Split(env['CCFLAGS'])
+cxxflags_libmv = Split(env['CXXFLAGS'])
+
+defs.append('V3DLIB_ENABLE_SUITESPARSE')
+defs.append('GOOGLE_GLOG_DLL_DECL=')
+
+src = env.Glob("*.cpp")
+src += env.Glob('libmv/image/*.cc')
+src += env.Glob('libmv/multiview/*.cc')
+src += env.Glob('libmv/numeric/*.cc')
+src += env.Glob('libmv/simple_pipeline/*.cc')
+src += env.Glob('libmv/tracking/*.cc')
+src += env.Glob('third_party/fast/*.c')
+src += env.Glob('third_party/gflags/*.cc')
+src += env.Glob('third_party/ldl/Source/*.c')
+src += env.Glob('third_party/ssba/Geometry/*.cpp')
+src += env.Glob('third_party/ssba/Math/*.cpp')
+
+incs = '. ../Eigen3'
+incs += ' ' + env['BF_PNG_INC']
+incs += ' ' + env['BF_ZLIB_INC']
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
+    incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog ./third_party/msinttypes'
+
+    src += ['./third_party/glog/src/logging.cc', './third_party/glog/src/raw_logging.cc', './third_party/glog/src/utilities.cc', './third_party/glog/src/vlog_is_on.cc']
+    src += ['./third_party/glog/src/windows/port.cc']
+
+    if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
+        cflags_libmv.append('/Od')
+        ccflags_libmv.append('/Od')
+        cxxflags_libmv.append('/Od')
+
+        if not env['BF_DEBUG']:
+            defs.append('NDEBUG')
+    else:
+        if not env['BF_DEBUG']:
+            cflags_libmv = Split(env['REL_CFLAGS'])
+            ccflags_libmv = Split(env['REL_CCFLAGS'])
+            cxxflags_libmv = Split(env['REL_CXXFLAGS'])
+else:
+    src += env.Glob("third_party/glog/src/*.cc")
+    incs += ' ./third_party/glog/src'
+    if not env['BF_DEBUG']:
+        cflags_libmv = Split(env['REL_CFLAGS'])
+        ccflags_libmv = Split(env['REL_CCFLAGS'])
+        cxxflags_libmv = Split(env['REL_CXXFLAGS'])
+
+incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include'
+
+env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137], compileflags=cflags_libmv, cc_compileflags=ccflags_libmv, cxx_compileflags=cxxflags_libmv )
diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh
new file mode 100755 (executable)
index 0000000..c8df8ae
--- /dev/null
@@ -0,0 +1,250 @@
+#!/bin/sh
+
+#BRANCH="keir"
+BRANCH="Matthias-Fauconneau"
+
+if [ -d ./.svn ]; then
+  echo "This script is supposed to work only when using git-svn"
+  exit 1
+fi
+
+repo="git://github.com/${BRANCH}/libmv.git"
+tmp=`mktemp -d`
+
+git clone $repo $tmp/libmv
+
+#git --git-dir $tmp/libmv/.git --work-tree $tmp/libmv log --since="1 month ago" > ChangeLog
+git --git-dir $tmp/libmv/.git --work-tree $tmp/libmv log -n 50 > ChangeLog
+
+for p in `cat ./patches/series`; do
+  echo "Applying patch $p..."
+  cat ./patches/$p | patch -d $tmp/libmv -p1
+done
+
+rm -rf libmv
+rm -rf third_party
+
+cat "files.txt" | while f=`line`; do
+  mkdir -p `dirname $f`
+  cp $tmp/libmv/src/$f $f
+done
+
+rm -rf $tmp
+
+chmod 664 ./third_party/glog/src/windows/*.cc ./third_party/glog/src/windows/*.h ./third_party/glog/src/windows/glog/*.h
+
+sources=`find ./libmv -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t/'`
+headers=`find ./libmv -type f -iname '*.h' | sed -r 's/^\.\//\t/'`
+
+third_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep -v glog | sed -r 's/^\.\//\t/'`
+third_headers=`find ./third_party -type f -iname '*.h' | grep -v glog | sed -r 's/^\.\//\t/'`
+
+third_glog_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t/'`
+third_glog_headers=`find ./third_party -type f -iname '*.h' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t/'`
+
+src_dir=`find ./libmv -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t/' | sort | 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/'  | sort | uniq`
+src=""
+win_src=""
+for x in $src_dir $src_third_dir; do
+  t=""
+
+  if test  `echo "$x" | grep -c glog ` -eq 1; then
+    continue;
+  fi
+
+  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 ` -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
+# \$Id\$
+# ***** 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2011, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+#                 Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+       .
+       ../Eigen3
+       ./third_party/ssba
+       ./third_party/ldl/Include
+       ../colamd/Include
+)
+
+set(INC_SYS
+       ${PNG_INCLUDE_DIR}
+       ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+       libmv-capi.cpp
+${sources}
+
+${third_sources}
+
+       libmv-capi.h
+${headers}
+
+${third_headers}
+)
+
+IF(WIN32)
+       list(APPEND SRC
+               third_party/glog/src/logging.cc
+               third_party/glog/src/raw_logging.cc
+               third_party/glog/src/utilities.cc
+               third_party/glog/src/vlog_is_on.cc
+               third_party/glog/src/windows/port.cc
+
+               third_party/glog/src/utilities.h
+               third_party/glog/src/stacktrace_generic-inl.h
+               third_party/glog/src/stacktrace.h
+               third_party/glog/src/stacktrace_x86_64-inl.h
+               third_party/glog/src/base/googleinit.h
+               third_party/glog/src/base/mutex.h
+               third_party/glog/src/base/commandlineflags.h
+               third_party/glog/src/stacktrace_powerpc-inl.h
+               third_party/glog/src/stacktrace_x86-inl.h
+               third_party/glog/src/config.h
+               third_party/glog/src/stacktrace_libunwind-inl.h
+               third_party/glog/src/windows/glog/raw_logging.h
+               third_party/glog/src/windows/glog/vlog_is_on.h
+               third_party/glog/src/windows/glog/logging.h
+               third_party/glog/src/windows/glog/log_severity.h
+               third_party/glog/src/windows/port.h
+               third_party/glog/src/windows/config.h
+       )
+
+       list(APPEND INC
+               ./third_party/glog/src/windows
+               ./third_party/msinttypes
+       )
+
+       IF(MSVC)
+               set(MSVC_OFLAGS O1 O2 Ox)
+               foreach(FLAG ${MSVC_OFLAGS})
+                       string(REPLACE "${FLAG}" "Od" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
+                       string(REPLACE "${FLAG}" "Od" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+               endforeach()
+       ENDIF(MSVC)
+ELSE(WIN32)
+       list(APPEND SRC
+${third_glog_sources}
+
+${third_glog_headers}
+       )
+
+       list(APPEND INC
+               ./third_party/glog/src
+       )
+ENDIF(WIN32)
+
+add_definitions(-DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL=)
+
+blender_add_lib(extern_libmv "\${SRC}" "\${INC}" "\${INC_SYS}")
+EOF
+
+cat > SConscript << EOF
+#!/usr/bin/python
+import sys
+import os
+
+Import('env')
+
+defs = []
+
+cflags_libmv = Split(env['CFLAGS'])
+ccflags_libmv = Split(env['CCFLAGS'])
+cxxflags_libmv = Split(env['CXXFLAGS'])
+
+defs.append('V3DLIB_ENABLE_SUITESPARSE')
+defs.append('GOOGLE_GLOG_DLL_DECL=')
+
+src = env.Glob("*.cpp")
+$src
+
+incs = '. ../Eigen3'
+incs += ' ' + env['BF_PNG_INC']
+incs += ' ' + env['BF_ZLIB_INC']
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
+    incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog ./third_party/msinttypes'
+${win_src}
+    src += ['./third_party/glog/src/logging.cc', './third_party/glog/src/raw_logging.cc', './third_party/glog/src/utilities.cc', './third_party/glog/src/vlog_is_on.cc']
+    src += ['./third_party/glog/src/windows/port.cc']
+
+    if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
+        cflags_libmv.append('/Od')
+        ccflags_libmv.append('/Od')
+        cxxflags_libmv.append('/Od')
+
+        if not env['BF_DEBUG']:
+            defs.append('NDEBUG')
+    else:
+        if not env['BF_DEBUG']:
+            cflags_libmv = Split(env['REL_CFLAGS'])
+            ccflags_libmv = Split(env['REL_CCFLAGS'])
+            cxxflags_libmv = Split(env['REL_CXXFLAGS'])
+else:
+    src += env.Glob("third_party/glog/src/*.cc")
+    incs += ' ./third_party/glog/src'
+    if not env['BF_DEBUG']:
+        cflags_libmv = Split(env['REL_CFLAGS'])
+        ccflags_libmv = Split(env['REL_CCFLAGS'])
+        cxxflags_libmv = Split(env['REL_CXXFLAGS'])
+
+incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include'
+
+env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137], compileflags=cflags_libmv, cc_compileflags=ccflags_libmv, cxx_compileflags=cxxflags_libmv )
+EOF
diff --git a/extern/libmv/files.txt b/extern/libmv/files.txt
new file mode 100644 (file)
index 0000000..fe6be5d
--- /dev/null
@@ -0,0 +1,141 @@
+libmv/logging/logging.h
+libmv/numeric/dogleg.h
+libmv/numeric/levenberg_marquardt.h
+libmv/numeric/poly.h
+libmv/numeric/numeric.cc
+libmv/numeric/function_derivative.h
+libmv/numeric/poly.cc
+libmv/numeric/tinyvector.cc
+libmv/numeric/numeric.h
+libmv/simple_pipeline/reconstruction.cc
+libmv/simple_pipeline/resect.h
+libmv/simple_pipeline/resect.cc
+libmv/simple_pipeline/reconstruction.h
+libmv/simple_pipeline/camera_intrinsics.h
+libmv/simple_pipeline/intersect.cc
+libmv/simple_pipeline/initialize_reconstruction.cc
+libmv/simple_pipeline/camera_intrinsics.cc
+libmv/simple_pipeline/pipeline.cc
+libmv/simple_pipeline/tracks.h
+libmv/simple_pipeline/detect.h
+libmv/simple_pipeline/detect.cc
+libmv/simple_pipeline/pipeline.h
+libmv/simple_pipeline/tracks.cc
+libmv/simple_pipeline/bundle.cc
+libmv/simple_pipeline/intersect.h
+libmv/simple_pipeline/bundle.h
+libmv/simple_pipeline/initialize_reconstruction.h
+libmv/image/convolve.h
+libmv/image/tuple.h
+libmv/image/array_nd.h
+libmv/image/convolve.cc
+libmv/image/array_nd.cc
+libmv/image/sample.h
+libmv/image/image.h
+libmv/tracking/pyramid_region_tracker.cc
+libmv/tracking/region_tracker.h
+libmv/tracking/sad.cc
+libmv/tracking/trklt_region_tracker.cc
+libmv/tracking/klt_region_tracker.cc
+libmv/tracking/retrack_region_tracker.h
+libmv/tracking/sad.h
+libmv/tracking/pyramid_region_tracker.h
+libmv/tracking/trklt_region_tracker.h
+libmv/tracking/retrack_region_tracker.cc
+libmv/tracking/klt_region_tracker.h
+libmv/base/id_generator.h
+libmv/base/vector.h
+libmv/base/scoped_ptr.h
+libmv/base/vector_utils.h
+libmv/multiview/projection.cc
+libmv/multiview/conditioning.cc
+libmv/multiview/nviewtriangulation.h
+libmv/multiview/resection.h
+libmv/multiview/fundamental.cc
+libmv/multiview/euclidean_resection.cc
+libmv/multiview/euclidean_resection.h
+libmv/multiview/triangulation.h
+libmv/multiview/projection.h
+libmv/multiview/triangulation.cc
+libmv/multiview/fundamental.h
+libmv/multiview/conditioning.h
+third_party/ssba/README.TXT
+third_party/ssba/COPYING.TXT
+third_party/ssba/Geometry/v3d_metricbundle.h
+third_party/ssba/Geometry/v3d_metricbundle.cpp
+third_party/ssba/Geometry/v3d_cameramatrix.h
+third_party/ssba/Geometry/v3d_distortion.h
+third_party/ssba/README.libmv
+third_party/ssba/Math/v3d_linear_utils.h
+third_party/ssba/Math/v3d_optimization.h
+third_party/ssba/Math/v3d_mathutilities.h
+third_party/ssba/Math/v3d_linear.h
+third_party/ssba/Math/v3d_optimization.cpp
+third_party/gflags/gflags_completions.h
+third_party/gflags/mutex.h
+third_party/gflags/gflags.cc
+third_party/gflags/gflags_reporting.cc
+third_party/gflags/README.libmv
+third_party/gflags/config.h
+third_party/gflags/gflags_completions.cc
+third_party/gflags/gflags.h
+third_party/fast/fast_9.c
+third_party/fast/fast_10.c
+third_party/fast/fast_11.c
+third_party/fast/fast.h
+third_party/fast/LICENSE
+third_party/fast/fast_12.c
+third_party/fast/fast.c
+third_party/fast/README
+third_party/fast/README.libmv
+third_party/fast/nonmax.c
+third_party/ldl/Include/ldl.h
+third_party/ldl/CMakeLists.txt
+third_party/ldl/README.libmv
+third_party/ldl/Doc/ChangeLog
+third_party/ldl/Doc/lesser.txt
+third_party/ldl/README.txt
+third_party/ldl/Source/ldl.c
+third_party/glog/ChangeLog
+third_party/glog/COPYING
+third_party/glog/src/utilities.cc
+third_party/glog/src/utilities.h
+third_party/glog/src/symbolize.cc
+third_party/glog/src/stacktrace_generic-inl.h
+third_party/glog/src/config_mac.h
+third_party/glog/src/vlog_is_on.cc
+third_party/glog/src/signalhandler.cc
+third_party/glog/src/stacktrace.h
+third_party/glog/src/stacktrace_x86_64-inl.h
+third_party/glog/src/symbolize.h
+third_party/glog/src/base/googleinit.h
+third_party/glog/src/base/mutex.h
+third_party/glog/src/base/commandlineflags.h
+third_party/glog/src/windows/preprocess.sh
+third_party/glog/src/windows/port.h
+third_party/glog/src/windows/config.h
+third_party/glog/src/windows/glog/raw_logging.h
+third_party/glog/src/windows/glog/vlog_is_on.h
+third_party/glog/src/windows/glog/logging.h
+third_party/glog/src/windows/glog/log_severity.h
+third_party/glog/src/windows/port.cc
+third_party/glog/src/logging.cc
+third_party/glog/src/stacktrace_powerpc-inl.h
+third_party/glog/src/stacktrace_x86-inl.h
+third_party/glog/src/demangle.cc
+third_party/glog/src/config.h
+third_party/glog/src/demangle.h
+third_party/glog/src/stacktrace_libunwind-inl.h
+third_party/glog/src/glog/raw_logging.h
+third_party/glog/src/glog/vlog_is_on.h
+third_party/glog/src/glog/logging.h
+third_party/glog/src/glog/log_severity.h
+third_party/glog/src/raw_logging.cc
+third_party/glog/src/config_linux.h
+third_party/glog/NEWS
+third_party/glog/README
+third_party/glog/README.libmv
+third_party/glog/AUTHORS
+third_party/msinttypes/stdint.h
+third_party/msinttypes/inttypes.h
+third_party/msinttypes/README.libmv
diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp
new file mode 100644 (file)
index 0000000..2e007bb
--- /dev/null
@@ -0,0 +1,770 @@
+/*
+ * ***** 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 *****
+ */
+
+/* define this to generate PNG images with content of search areas
+   tracking between which failed */
+#undef DUMP_FAILURE
+
+#include "libmv-capi.h"
+
+#include "glog/logging.h"
+#include "Math/v3d_optimization.h"
+
+#include "libmv/tracking/klt_region_tracker.h"
+#include "libmv/tracking/trklt_region_tracker.h"
+#include "libmv/tracking/pyramid_region_tracker.h"
+
+#include "libmv/tracking/sad.h"
+
+#include "libmv/simple_pipeline/tracks.h"
+#include "libmv/simple_pipeline/initialize_reconstruction.h"
+#include "libmv/simple_pipeline/bundle.h"
+#include "libmv/simple_pipeline/detect.h"
+#include "libmv/simple_pipeline/pipeline.h"
+#include "libmv/simple_pipeline/camera_intrinsics.h"
+
+#include <stdlib.h>
+
+#ifdef DUMP_FAILURE
+#  include <png.h>
+#endif
+
+#ifdef _MSC_VER
+#  define snprintf _snprintf
+#endif
+
+#define DEFAULT_WINDOW_HALFSIZE        5
+
+typedef struct libmv_RegionTracker {
+       libmv::TrkltRegionTracker *trklt_region_tracker;
+       libmv::RegionTracker *region_tracker;
+} libmv_RegionTracker;
+
+typedef struct libmv_Reconstruction {
+       libmv::EuclideanReconstruction reconstruction;
+
+       /* used for per-track average error calculation after reconstruction */
+       libmv::Tracks tracks;
+       libmv::CameraIntrinsics intrinsics;
+
+       double error;
+} libmv_Reconstruction;
+
+typedef struct libmv_Features {
+       int count, margin;
+       libmv::Feature *features;
+} libmv_Features;
+
+/* ************ Logging ************ */
+
+void libmv_initLogging(const char *argv0)
+{
+       google::InitGoogleLogging(argv0);
+       google::SetCommandLineOption("logtostderr", "1");
+       google::SetCommandLineOption("v", "0");
+       google::SetCommandLineOption("stderrthreshold", "7");
+       google::SetCommandLineOption("minloglevel", "7");
+       V3D::optimizerVerbosenessLevel = 0;
+}
+
+void libmv_startDebugLogging(void)
+{
+       google::SetCommandLineOption("logtostderr", "1");
+       google::SetCommandLineOption("v", "0");
+       google::SetCommandLineOption("stderrthreshold", "1");
+       google::SetCommandLineOption("minloglevel", "0");
+       V3D::optimizerVerbosenessLevel = 1;
+}
+
+void libmv_setLoggingVerbosity(int verbosity)
+{
+       char val[10];
+       snprintf(val, sizeof(val), "%d", verbosity);
+
+       google::SetCommandLineOption("v", val);
+       V3D::optimizerVerbosenessLevel = verbosity;
+}
+
+/* ************ RegionTracker ************ */
+
+libmv_RegionTracker *libmv_regionTrackerNew(int max_iterations, int pyramid_level)
+{
+       libmv::TrkltRegionTracker *trklt_region_tracker = new libmv::TrkltRegionTracker;
+
+       trklt_region_tracker->half_window_size = DEFAULT_WINDOW_HALFSIZE;
+       trklt_region_tracker->max_iterations = max_iterations;
+       trklt_region_tracker->min_determinant = 1e-4;
+
+       libmv::PyramidRegionTracker *region_tracker =
+               new libmv::PyramidRegionTracker(trklt_region_tracker, pyramid_level);
+
+       libmv_RegionTracker *configured_region_tracker = new libmv_RegionTracker;
+       configured_region_tracker->trklt_region_tracker = trklt_region_tracker;
+       configured_region_tracker->region_tracker = region_tracker;
+
+       return configured_region_tracker;
+}
+
+static void floatBufToImage(const float *buf, int width, int height, libmv::FloatImage *image)
+{
+       int x, y, a = 0;
+
+       image->resize(height, width);
+
+       for (y = 0; y < height; y++) {
+               for (x = 0; x < width; x++) {
+                       (*image)(y, x, 0) = buf[a++];
+               }
+       }
+}
+
+#ifdef DUMP_FAILURE
+void savePNGImage(png_bytep *row_pointers, int width, int height, int depth, int color_type, char *file_name)
+{
+       png_infop info_ptr;
+       png_structp png_ptr;
+       FILE *fp = fopen(file_name, "wb");
+
+       if (!fp)
+               return;
+
+       /* 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;
+       }
+
+       png_init_io(png_ptr, fp);
+
+       /* write header */
+       if (setjmp(png_jmpbuf(png_ptr))) {
+               fclose(fp);
+               return;
+       }
+
+       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;
+       }
+
+       png_write_image(png_ptr, row_pointers);
+
+       /* end write */
+       if (setjmp(png_jmpbuf(png_ptr))) {
+               fclose(fp);
+               return;
+       }
+
+       png_write_end(png_ptr, NULL);
+
+       fclose(fp);
+}
+
+static void saveImage(char *prefix, libmv::FloatImage image, int x0, int y0)
+{
+       int x, y;
+       png_bytep *row_pointers;
+
+       row_pointers= (png_bytep*)malloc(sizeof(png_bytep)*image.Height());
+
+       for (y = 0; y < image.Height(); y++) {
+               row_pointers[y]= (png_bytep)malloc(sizeof(png_byte)*4*image.Width());
+
+               for (x = 0; x < image.Width(); x++) {
+                       if (x0 == x && y0 == 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(y, 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 a= 0;
+               char buf[128];
+               snprintf(buf, sizeof(buf), "%s_%02d.png", prefix, ++a);
+               savePNGImage(row_pointers, image.Width(), image.Height(), 8, PNG_COLOR_TYPE_RGBA, buf);
+       }
+
+       for (y = 0; y < image.Height(); y++) {
+               free(row_pointers[y]);
+       }
+       free(row_pointers);
+}
+
+static void saveBytesImage(char *prefix, unsigned char *data, int width, int height)
+{
+       int x, y;
+       png_bytep *row_pointers;
+
+       row_pointers= (png_bytep*)malloc(sizeof(png_bytep)*height);
+
+       for (y = 0; y < height; y++) {
+               row_pointers[y]= (png_bytep)malloc(sizeof(png_byte)*4*width);
+
+               for (x = 0; x < width; x++) {
+                       char pixel = data[width*y+x];
+                       row_pointers[y][x*4+0]= pixel;
+                       row_pointers[y][x*4+1]= pixel;
+                       row_pointers[y][x*4+2]= pixel;
+                       row_pointers[y][x*4+3]= 255;
+               }
+       }
+
+       {
+               static int a= 0;
+               char buf[128];
+               snprintf(buf, sizeof(buf), "%s_%02d.png", prefix, ++a);
+               savePNGImage(row_pointers, width, height, 8, PNG_COLOR_TYPE_RGBA, buf);
+       }
+
+       for (y = 0; y < height; y++) {
+               free(row_pointers[y]);
+       }
+       free(row_pointers);
+}
+#endif
+
+int libmv_regionTrackerTrack(libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2,
+                        int width, int height, int half_window_size,
+                        double x1, double y1, double *x2, double *y2)
+{
+       libmv::RegionTracker *region_tracker;
+       libmv::TrkltRegionTracker *trklt_region_tracker;
+       libmv::FloatImage old_patch, new_patch;
+
+       trklt_region_tracker = libmv_tracker->trklt_region_tracker;
+       region_tracker = libmv_tracker->region_tracker;
+
+       trklt_region_tracker->half_window_size = half_window_size;
+
+       floatBufToImage(ima1, width, height, &old_patch);
+       floatBufToImage(ima2, width, height, &new_patch);
+
+#ifndef DUMP_FAILURE
+       return region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2);
+#else
+       {
+               double sx2 = *x2, sy2 = *y2;
+               int result = region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2);
+
+               if (!result) {
+                       saveImage("old_patch", old_patch, x1, y1);
+                       saveImage("new_patch", new_patch, sx2, sy2);
+               }
+
+               return result;
+       }
+#endif
+}
+
+void libmv_regionTrackerDestroy(libmv_RegionTracker *libmv_tracker)
+{
+       delete libmv_tracker->region_tracker;
+       delete libmv_tracker;
+}
+
+/* ************ Tracks ************ */
+
+void libmv_SADSamplePattern(unsigned char *image, int stride,
+                       float warp[3][2], unsigned char *pattern)
+{
+       libmv::mat32 mat32;
+
+       memcpy(mat32.data, warp, sizeof(float)*3*2);
+
+       libmv::SamplePattern(image, stride, mat32, pattern, 16);
+}
+
+float libmv_SADTrackerTrack(unsigned char *pattern, unsigned char *warped, unsigned char *image, int stride,
+                       int width, int height, float warp[3][2])
+{
+       float result;
+       libmv::mat32 mat32;
+
+       memcpy(mat32.data, warp, sizeof(float)*3*2);
+
+       result = libmv::Track(pattern, warped, 16, image, stride, width, height, &mat32, 16, 16);
+
+       memcpy(warp, mat32.data, sizeof(float)*3*2);
+
+       return result;
+}
+
+/* ************ Tracks ************ */
+
+libmv_Tracks *libmv_tracksNew(void)
+{
+       libmv::Tracks *libmv_tracks = new libmv::Tracks();
+
+       return (libmv_Tracks *)libmv_tracks;
+}
+
+void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y)
+{
+       ((libmv::Tracks*)libmv_tracks)->Insert(image, track, x, y);
+}
+
+void libmv_tracksDestroy(libmv_Tracks *libmv_tracks)
+{
+       delete (libmv::Tracks*)libmv_tracks;
+}
+
+/* ************ Reconstruction solver ************ */
+
+libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyframe1, int keyframe2,
+                       double focal_length, double principal_x, double principal_y, double k1, double k2, double k3)
+{
+       /* Invert the camera intrinsics. */
+       libmv::vector<libmv::Marker> markers = ((libmv::Tracks*)tracks)->AllMarkers();
+       libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
+       libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+       libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
+
+       intrinsics->SetFocalLength(focal_length, focal_length);
+       intrinsics->SetPrincipalPoint(principal_x, principal_y);
+       intrinsics->SetRadialDistortion(k1, k2, k3);
+
+       if(focal_length) {
+               /* do a lens undistortion if focal length is non-zero only */
+               for (int i = 0; i < markers.size(); ++i) {
+                       intrinsics->InvertIntrinsics(markers[i].x,
+                               markers[i].y,
+                               &(markers[i].x),
+                               &(markers[i].y));
+               }
+       }
+
+       libmv::Tracks normalized_tracks(markers);
+
+       libmv::vector<libmv::Marker> keyframe_markers =
+               normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
+
+       libmv::EuclideanReconstructTwoFrames(keyframe_markers, reconstruction);
+       libmv::EuclideanBundle(normalized_tracks, reconstruction);
+       libmv::EuclideanCompleteReconstruction(normalized_tracks, reconstruction);
+
+       libmv_reconstruction->tracks = *(libmv::Tracks *)tracks;
+       libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics);
+
+       return (libmv_Reconstruction *)libmv_reconstruction;
+}
+
+int libmv_reporojectionPointForTrack(libmv_Reconstruction *libmv_reconstruction, int track, double pos[3])
+{
+       libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+       libmv::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;
+}
+
+static libmv::Marker ProjectMarker(const libmv::EuclideanPoint &point, const libmv::EuclideanCamera &camera,
+                       const libmv::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;
+}
+
+double libmv_reporojectionErrorForTrack(libmv_Reconstruction *libmv_reconstruction, int track)
+{
+       libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+       libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
+       libmv::vector<libmv::Marker> markers =  libmv_reconstruction->tracks.MarkersForTrack(track);
+
+       int num_reprojected = 0;
+       double total_error = 0.0;
+
+       for (int i = 0; i < markers.size(); ++i) {
+               const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
+               const libmv::EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
+
+               if (!camera || !point) {
+                       continue;
+               }
+
+               num_reprojected++;
+
+               libmv::Marker reprojected_marker = ProjectMarker(*point, *camera, *intrinsics);
+               double ex = reprojected_marker.x - markers[i].x;
+               double ey = reprojected_marker.y - markers[i].y;
+
+               total_error += sqrt(ex*ex + ey*ey);
+       }
+
+       return total_error / num_reprojected;
+}
+
+double libmv_reporojectionErrorForImage(libmv_Reconstruction *libmv_reconstruction, int image)
+{
+       libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+       libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
+       libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersInImage(image);
+       const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(image);
+       int num_reprojected = 0;
+       double total_error = 0.0;
+
+       if (!camera)
+               return 0;
+
+       for (int i = 0; i < markers.size(); ++i) {
+               const libmv::EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
+
+               if (!point) {
+                       continue;
+               }
+
+               num_reprojected++;
+
+               libmv::Marker reprojected_marker = ProjectMarker(*point, *camera, *intrinsics);
+               double ex = reprojected_marker.x - markers[i].x;
+               double ey = reprojected_marker.y - markers[i].y;
+
+               total_error += sqrt(ex*ex + ey*ey);
+       }
+
+       return total_error / num_reprojected;
+}
+
+int libmv_reporojectionCameraForImage(libmv_Reconstruction *libmv_reconstruction, int image, double mat[4][4])
+{
+       libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+       libmv::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(libmv_Reconstruction *libmv_reconstruction)
+{
+       return libmv_reconstruction->error;
+}
+
+void libmv_destroyReconstruction(libmv_Reconstruction *libmv_reconstruction)
+{
+       delete libmv_reconstruction;
+}
+
+/* ************ feature detector ************ */
+
+struct libmv_Features *libmv_detectFeaturesFAST(unsigned char *data, int width, int height, int stride,
+                       int margin, int min_trackness, int min_distance)
+{
+       libmv::Feature *features = NULL;
+       std::vector<libmv::Feature> v;
+       libmv_Features *libmv_features = new libmv_Features();
+       int i= 0, count;
+
+       if(margin) {
+               data += margin*stride+margin;
+               width -= 2*margin;
+               height -= 2*margin;
+       }
+
+       v = libmv::DetectFAST(data, width, height, stride, min_trackness, min_distance);
+
+       count = v.size();
+
+       if(count) {
+               features= new libmv::Feature[count];
+
+               for(std::vector<libmv::Feature>::iterator it = v.begin(); it != v.end(); it++) {
+                       features[i++]= *it;
+               }
+       }
+
+       libmv_features->features = features;
+       libmv_features->count = count;
+       libmv_features->margin = margin;
+
+       return (libmv_Features *)libmv_features;
+}
+
+struct libmv_Features *libmv_detectFeaturesMORAVEC(unsigned char *data, int width, int height, int stride,
+                       int margin, int count, int min_distance)
+{
+       libmv::Feature *features = NULL;
+       libmv_Features *libmv_features = new libmv_Features;
+
+       if(count) {
+               if(margin) {
+                       data += margin*stride+margin;
+                       width -= 2*margin;
+                       height -= 2*margin;
+               }
+
+               features = new libmv::Feature[count];
+               libmv::DetectMORAVEC(data, stride, width, height, features, &count, min_distance, NULL);
+       }
+
+       libmv_features->count = count;
+       libmv_features->margin = margin;
+       libmv_features->features = features;
+
+       return libmv_features;
+}
+
+int libmv_countFeatures(struct libmv_Features *libmv_features)
+{
+       return libmv_features->count;
+}
+
+void libmv_getFeature(struct libmv_Features *libmv_features, int number, double *x, double *y, double *score, double *size)
+{
+       libmv::Feature feature= libmv_features->features[number];
+
+       *x = feature.x + libmv_features->margin;
+       *y = feature.y + libmv_features->margin;
+       *score = feature.score;
+       *size = feature.size;
+}
+
+void libmv_destroyFeatures(struct libmv_Features *libmv_features)
+{
+       if(libmv_features->features)
+               delete [] libmv_features->features;
+
+       delete libmv_features;
+}
+
+/* ************ camera intrinsics ************ */
+
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y,
+                       double k1, double k2, double k3, int width, int height)
+{
+       libmv::CameraIntrinsics *intrinsics= new libmv::CameraIntrinsics();
+
+       intrinsics->SetFocalLength(focal_length, focal_length);
+       intrinsics->SetPrincipalPoint(principal_x, principal_y);
+       intrinsics->SetRadialDistortion(k1, k2, k3);
+       intrinsics->SetImageSize(width, height);
+
+       return (struct libmv_CameraIntrinsics *) intrinsics;
+}
+
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics)
+{
+       libmv::CameraIntrinsics *orig_intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+       libmv::CameraIntrinsics *new_intrinsics= new libmv::CameraIntrinsics(*orig_intrinsics);
+
+       return (struct libmv_CameraIntrinsics *) new_intrinsics;
+}
+
+void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsics)
+{
+       libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+
+       delete intrinsics;
+}
+
+void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length,
+                       double principal_x, double principal_y, double k1, double k2, double k3, int width, int height)
+{
+       libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+
+       if (intrinsics->focal_length() != focal_length)
+               intrinsics->SetFocalLength(focal_length, focal_length);
+
+       if (intrinsics->principal_point_x() != principal_x || intrinsics->principal_point_y() != principal_y)
+               intrinsics->SetFocalLength(focal_length, focal_length);
+
+       if (intrinsics->k1() != k1 || intrinsics->k2() != k2 || intrinsics->k3() != k3)
+               intrinsics->SetRadialDistortion(k1, k2, k3);
+
+       if (intrinsics->image_width() != width || intrinsics->image_height() != height)
+               intrinsics->SetImageSize(width, height);
+}
+
+void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+                       unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
+{
+       libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+
+       intrinsics->Undistort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
+                       float *src, float *dst, int width, int height, float overscan, int channels)
+{
+       libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+
+       intrinsics->Undistort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+                       unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
+{
+       libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+       intrinsics->Distort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
+                       float *src, float *dst, int width, int height, float overscan, int channels)
+{
+       libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+
+       intrinsics->Distort(src, dst, width, height, overscan, channels);
+}
+
+/* ************ distortion ************ */
+
+void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
+{
+       libmv::CameraIntrinsics intrinsics;
+
+       intrinsics.SetFocalLength(focal_length, focal_length);
+       intrinsics.SetPrincipalPoint(principal_x, principal_y);
+       intrinsics.SetRadialDistortion(k1, k2, k3);
+
+       intrinsics.Undistort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       float *src, float *dst, int width, int height, float overscan, int channels)
+{
+       libmv::CameraIntrinsics intrinsics;
+
+       intrinsics.SetFocalLength(focal_length, focal_length);
+       intrinsics.SetPrincipalPoint(principal_x, principal_y);
+       intrinsics.SetRadialDistortion(k1, k2, k3);
+
+       intrinsics.Undistort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
+{
+       libmv::CameraIntrinsics intrinsics;
+
+       intrinsics.SetFocalLength(focal_length, focal_length);
+       intrinsics.SetPrincipalPoint(principal_x, principal_y);
+       intrinsics.SetRadialDistortion(k1, k2, k3);
+
+       intrinsics.Distort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       float *src, float *dst, int width, int height, float overscan, int channels)
+{
+       libmv::CameraIntrinsics intrinsics;
+
+       intrinsics.SetFocalLength(focal_length, focal_length);
+       intrinsics.SetPrincipalPoint(principal_x, principal_y);
+       intrinsics.SetRadialDistortion(k1, k2, k3);
+
+       intrinsics.Distort(src, dst, width, height, overscan, channels);
+}
+
+/* ************ utils ************ */
+
+void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       double x, double y, double *x1, double *y1)
+{
+       libmv::CameraIntrinsics intrinsics;
+
+       intrinsics.SetFocalLength(focal_length, focal_length);
+       intrinsics.SetPrincipalPoint(principal_x, principal_y);
+       intrinsics.SetRadialDistortion(k1, k2, k3);
+
+       if(focal_length) {
+               /* do a lens undistortion if focal length is non-zero only */
+
+               intrinsics.ApplyIntrinsics(x, y, x1, y1);
+       }
+}
+
+void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       double x, double y, double *x1, double *y1)
+{
+       libmv::CameraIntrinsics intrinsics;
+
+       intrinsics.SetFocalLength(focal_length, focal_length);
+       intrinsics.SetPrincipalPoint(principal_x, principal_y);
+       intrinsics.SetRadialDistortion(k1, k2, k3);
+
+       if(focal_length) {
+               /* do a lens distortion if focal length is non-zero only */
+
+               intrinsics.InvertIntrinsics(x, y, x1, y1);
+       }
+}
diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h
new file mode 100644 (file)
index 0000000..b71a66b
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * ***** 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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct libmv_RegionTracker;
+struct libmv_Tracks;
+struct libmv_Reconstruction;
+struct libmv_Features;
+struct libmv_CameraIntrinsics;
+
+/* Logging */
+void libmv_initLogging(const char *argv0);
+void libmv_startDebugLogging(void);
+void libmv_setLoggingVerbosity(int verbosity);
+
+/* RegionTracker */
+struct libmv_RegionTracker *libmv_regionTrackerNew(int max_iterations, int pyramid_level);
+int libmv_regionTrackerTrack(struct libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2,
+                       int width, int height, int half_window_size,
+                       double  x1, double  y1, double *x2, double *y2);
+void libmv_regionTrackerDestroy(struct libmv_RegionTracker *libmv_tracker);
+
+/* SAD Tracker */
+void libmv_SADSamplePattern(unsigned char *image, int stride,
+                       float warp[3][2], unsigned char *pattern);
+float libmv_SADTrackerTrack(unsigned char *pattern, unsigned char *warped, unsigned char *image,
+                       int stride, int width, int height, float warp[3][2]);
+
+/* Tracks */
+struct libmv_Tracks *libmv_tracksNew(void);
+void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y);
+void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks);
+
+/* Reconstruction solver */
+struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *tracks, int keyframe1, int keyframe2,
+                       double focal_length, double principal_x, double principal_y, double k1, double k2, double k3);
+int libmv_reporojectionPointForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]);
+double libmv_reporojectionErrorForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track);
+double libmv_reporojectionErrorForImage(struct libmv_Reconstruction *libmv_reconstruction, int image);
+int libmv_reporojectionCameraForImage(struct libmv_Reconstruction *libmv_reconstruction, int image, double mat[4][4]);
+double libmv_reprojectionError(struct libmv_Reconstruction *libmv_reconstruction);
+void libmv_destroyReconstruction(struct libmv_Reconstruction *libmv_reconstruction);
+
+/* feature detector */
+struct libmv_Features *libmv_detectFeaturesFAST(unsigned char *data, int width, int height, int stride,
+                       int margin, int min_trackness, int min_distance);
+struct libmv_Features *libmv_detectFeaturesMORAVEC(unsigned char *data, int width, int height, int stride,
+                       int margin, int count, int min_distance);
+int libmv_countFeatures(struct libmv_Features *libmv_features);
+void libmv_getFeature(struct libmv_Features *libmv_features, int number, double *x, double *y, double *score, double *size);
+void libmv_destroyFeatures(struct libmv_Features *libmv_features);
+
+/* camera intrinsics */
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y,
+                       double k1, double k2, double k3, int width, int height);
+
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics);
+
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics);
+
+void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsics);
+
+void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length,
+                       double principal_x, double principal_y, double k1, double k2, double k3, int width, int height);
+
+void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+                       unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
+
+void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
+                       float *src, float *dst, int width, int height, float overscan, int channels);
+
+void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+                       unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
+
+void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
+                       float *src, float *dst, int width, int height, float overscan, int channels);
+
+/* dsitortion */
+void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       unsigned char *src, unsigned char *dst, int width, int height, int channels);
+void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       float *src, float *dst, int width, int height, int channels);
+
+void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       unsigned char *src, unsigned char *dst, int width, int height, int channels);
+void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       float *src, float *dst, int width, int height, int channels);
+
+/* utils */
+void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       double x, double y, double *x1, double *y1);
+void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+                       double x, double y, double *x1, double *y1);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIBMV_C_API_H
diff --git a/extern/libmv/libmv/base/id_generator.h b/extern/libmv/libmv/base/id_generator.h
new file mode 100644 (file)
index 0000000..bf1eafd
--- /dev/null
@@ -0,0 +1,37 @@
+// 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 <typename ID>
+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
new file mode 100644 (file)
index 0000000..f1e89eb
--- /dev/null
@@ -0,0 +1,60 @@
+// 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
+
+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<typename T>
+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_;
+};
+
+}  // namespace libmv
+
+#endif  // LIBMV_BASE_SCOPED_PTR_H
diff --git a/extern/libmv/libmv/base/vector.h b/extern/libmv/libmv/base/vector.h
new file mode 100644 (file)
index 0000000..9dc4867
--- /dev/null
@@ -0,0 +1,172 @@
+// 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 <vector>. 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 <cstring>
+#include <new>
+
+#include <Eigen/Core>
+
+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 <T> class vector : std::vector<T, aligned_allocator> {} declaration
+// provided it doesn't break code relying on libmv::vector specific behavior
+template <typename T,
+          typename Allocator = Eigen::aligned_allocator<T> >
+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<T, Allocator> &rhs) {
+    init();
+    copy(rhs);
+  }
+  vector<T, Allocator> &operator=(const vector<T, Allocator> &rhs) {
+    if (&rhs != this) {
+      copy(rhs);
+    }
+    return *this;
+  }
+
+  /// Swaps the contents of two vectors in constant time.
+  void swap(vector<T, Allocator> &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 * 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<T *>(allocate(size));
+      memcpy(data, data_, sizeof(*data)*size_);
+      allocator_.deallocate(data_, capacity_);
+      data_ = data;
+      capacity_ = size;
+    }
+  }
+
+ 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<T, Allocator> &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_utils.h b/extern/libmv/libmv/base/vector_utils.h
new file mode 100644 (file)
index 0000000..7a0c3ba
--- /dev/null
@@ -0,0 +1,34 @@
+// 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 <class Array>
+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
new file mode 100644 (file)
index 0000000..3a77e3e
--- /dev/null
@@ -0,0 +1,108 @@
+// 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 <iostream>
+#include <cmath>
+
+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
new file mode 100644 (file)
index 0000000..6d7570c
--- /dev/null
@@ -0,0 +1,473 @@
+// 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 <cassert>
+#include <cstdio>
+#include <cstring>
+
+#include "libmv/image/tuple.h"
+
+namespace libmv {
+
+class BaseArray {};
+
+/// A multidimensional array class.
+template <typename T, int N>
+class ArrayND : public BaseArray {
+ public:
+  typedef T Scalar;
+
+  /// Type for the multidimensional indices.
+  typedef Tuple<int, N> 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<T, N> &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) : data_(data), own_data(false) { Resize(s0, s1, s2); }
+
+  /// Destructor deletes pixel data.
+  ~ArrayND() {
+    delete [] data_;
+  }
+
+  /// Assignation copies pixel data.
+  ArrayND &operator=(const ArrayND<T, N> &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<typename D>
+  void ResizeLike(const ArrayND<D,N> &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<typename D>
+  void CopyFrom(const ArrayND<D,N> &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<T, N> &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<T, N> &other) const {
+    return !(*this == other);
+  }
+
+  ArrayND<T, N> operator*(const ArrayND<T, N> &other) const {
+    assert(Shape() = other.Shape());
+    ArrayND<T, N> 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 <typename T>
+class Array3D : public ArrayND<T, 3> {
+  typedef ArrayND<T, 3> 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<unsigned char> Array3Du;
+typedef Array3D<unsigned int> Array3Dui;
+typedef Array3D<int> Array3Di;
+typedef Array3D<float> Array3Df;
+typedef Array3D<short> 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 <typename AArrayType, typename BArrayType, typename CArrayType>
+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 <typename TA, typename TB, typename TC>
+void MultiplyElements(const ArrayND<TA, 3> &a,
+                      const ArrayND<TB, 3> &b,
+                      ArrayND<TC, 3> *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/convolve.cc b/extern/libmv/libmv/image/convolve.cc
new file mode 100644 (file)
index 0000000..be73a1a
--- /dev/null
@@ -0,0 +1,305 @@
+// 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 <cmath>
+
+#include "libmv/image/image.h"
+#include "libmv/image/convolve.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 <int size, bool vertical>
+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<float>(sum);
+      src += src_stride;
+      dst += dst_stride;
+    }
+  }
+}
+
+template<bool vertical>
+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<size, vertical>(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<float>(sum);
+          src += src_stride;
+          dst += dst_stride;
+        }
+      }
+  }
+}
+
+void ConvolveHorizontal(const Array3Df &in,
+                        const Vec &kernel,
+                        Array3Df *out_pointer,
+                        int plane) {
+  Convolve<false>(in, kernel, out_pointer, plane);
+}
+
+void ConvolveVertical(const Array3Df &in,
+                      const Vec &kernel,
+                      Array3Df *out_pointer,
+                      int plane) {
+  Convolve<true>(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 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);
+}
+
+}  // namespace libmv
diff --git a/extern/libmv/libmv/image/convolve.h b/extern/libmv/libmv/image/convolve.h
new file mode 100644 (file)
index 0000000..c6c995f
--- /dev/null
@@ -0,0 +1,93 @@
+// 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);
+
+}  // namespace libmv
+
+#endif  // LIBMV_IMAGE_CONVOLVE_H_
+
diff --git a/extern/libmv/libmv/image/image.h b/extern/libmv/libmv/image/image.h
new file mode 100644 (file)
index 0000000..d158b0e
--- /dev/null
@@ -0,0 +1,158 @@
+// 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 <cmath>
+
+#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<Array3Du *>(array_)->MemorySizeInBytes();
+      break;
+      case FLOAT:
+        size = reinterpret_cast<Array3Df *>(array_)->MemorySizeInBytes();
+      break;
+      case INT:
+        size = reinterpret_cast<Array3Di *>(array_)->MemorySizeInBytes();
+      break;
+      case SHORT:
+        size = reinterpret_cast<Array3Ds *>(array_)->MemorySizeInBytes();
+      break;
+    default :
+      size = 0;
+      assert(0);
+    }
+    size += sizeof(*this);
+    return size;
+  }
+
+  ~Image() {
+    switch (array_type_)
+      {
+        case BYTE:
+          delete reinterpret_cast<Array3Du *>(array_);
+
+        break;
+        case FLOAT:
+          delete reinterpret_cast<Array3Df *>(array_);
+
+        break;
+        case INT:
+          delete reinterpret_cast<Array3Di *>(array_);
+
+        break;
+        case SHORT:
+          delete reinterpret_cast<Array3Ds *>(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<Array3Du *>(array_);
+          array_ = new Array3Du( *(Array3Du *)f.array_);
+        break;
+        case FLOAT:
+          delete reinterpret_cast<Array3Df *>(array_);
+          array_ = new Array3Df( *(Array3Df *)f.array_);
+        break;
+        case INT:
+          delete reinterpret_cast<Array3Di *>(array_);
+          array_ = new Array3Di( *(Array3Di *)f.array_);
+        break;
+        case SHORT:
+          delete reinterpret_cast<Array3Ds *>(array_);
+          array_ = new Array3Ds( *(Array3Ds *)f.array_);
+        break;
+        default:
+          assert(0);
+      }
+    }
+    return *this;
+  }
+
+  Array3Du *AsArray3Du() const {
+    if (array_type_ == BYTE) {
+      return reinterpret_cast<Array3Du *>(array_);
+    }
+    return NULL;
+  }
+
+  Array3Df *AsArray3Df() const {
+    if (array_type_ == FLOAT) {
+      return reinterpret_cast<Array3Df *>(array_);
+    }
+    return NULL;
+  }
+
+ private:
+  DataType array_type_;
+  BaseArray *array_;
+};
+
+}  // namespace libmv
+
+#endif  // LIBMV_IMAGE_IMAGE_IMAGE_H
diff --git a/extern/libmv/libmv/image/sample.h b/extern/libmv/libmv/image/sample.h
new file mode 100644 (file)
index 0000000..cd36123
--- /dev/null
@@ -0,0 +1,103 @@
+// 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<typename T>
+inline T SampleNearest(const Array3D<T> &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);
+}
+
+static inline void LinearInitAxis(float fx, int width,
+                                  int *x1, int *x2,
+                                  float *dx1, float *dx2) {
+  const int ix = int(fx);
+  if (ix < 0) {
+    *x1 = 0;
+    *x2 = 0;
+    *dx1 = 1;
+    *dx2 = 0;
+  } else if (ix > width-2) {
+    *x1 = width-1;
+    *x2 = width-1;
+    *dx1 = 1;
+    *dx2 = 0;
+  } else {
+    *x1 = ix;
+    *x2 = *x1 + 1;
+    *dx1 = *x2 - fx;
+    *dx2 = 1 - *dx1;
+  }
+}
+
+/// Linear interpolation.
+template<typename T>
+inline T SampleLinear(const Array3D<T> &image, float y, float x, int v = 0) {
+  int x1, y1, x2, y2;
+  float dx1, dy1, dx2, dy2;
+
+  LinearInitAxis(y, image.Height(), &y1, &y2, &dy1, &dy2);
+  LinearInitAxis(x, image.Width(),  &x1, &x2, &dx1, &dx2);
+
+  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(dy1 * ( dx1 * im11 + dx2 * im12 ) +
+           dy2 * ( dx1 * im21 + dx2 * 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;
+      }
+    }
+  }
+
+}
+
+}  // namespace libmv
+
+#endif  // LIBMV_IMAGE_SAMPLE_H_
diff --git a/extern/libmv/libmv/image/tuple.h b/extern/libmv/libmv/image/tuple.h
new file mode 100644 (file)
index 0000000..79acc95
--- /dev/null
@@ -0,0 +1,90 @@
+// 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 <algorithm>
+
+namespace libmv {
+
+// A vector of elements with fixed lenght and deep copy semantics.
+template <typename T, int N>
+class Tuple {
+ public:
+  enum { SIZE = N };
+  Tuple() {}
+  Tuple(T initial_value) { Reset(initial_value); }
+
+  template <typename D>
+  Tuple(D *values) { Reset(values); }
+
+  template <typename D>
+  Tuple(const Tuple<D,N> &b) { Reset(b); }
+
+  template <typename D>
+  Tuple& operator=(const Tuple<D,N>& b) {
+    Reset(b);
+    return *this;
+  }
+
+  template <typename D>
+  void Reset(const Tuple<D, N>& b) { Reset(b.Data()); }
+
+  template <typename D>
+  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<T, N> &other) const {
+    for (int i = 0; i < N; ++i) {
+      if ((*this)(i) != other(i)) {
+        return false;
+      }
+    }
+    return true;
+  }
+  bool operator!=(const Tuple<T, N> &other) const {
+    return !(*this == other);
+  }
+
+ private:
+  T data_[N];
+};
+
+}  // namespace libmv
+
+#endif  // LIBMV_IMAGE_TUPLE_H
diff --git a/extern/libmv/libmv/logging/logging.h b/extern/libmv/libmv/logging/logging.h
new file mode 100644 (file)
index 0000000..af86c4b
--- /dev/null
@@ -0,0 +1,31 @@
+// 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 "glog/logging.h"
+
+#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
new file mode 100644 (file)
index 0000000..20e3a88
--- /dev/null
@@ -0,0 +1,99 @@
+// 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
new file mode 100644 (file)
index 0000000..181d748
--- /dev/null
@@ -0,0 +1,60 @@
+// 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
new file mode 100644 (file)
index 0000000..6d918a1
--- /dev/null
@@ -0,0 +1,661 @@
+// 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 <cmath>
+#include <limits>
+
+#include <Eigen/SVD>
+#include <Eigen/Geometry>
+
+#include "libmv/base/vector.h"
+#include "libmv/logging/logging.h"
+#include "libmv/multiview/euclidean_resection.h"
+#include "libmv/multiview/projection.h"
+
+namespace libmv {
+namespace euclidean_resection {
+
+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;
+    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.
+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<Mat3> 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
+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
+void ComputePointsCoordinatesInCameraFrame(
+    const Mat4X &alphas, 
+    const Vec4 &betas,
+    const Eigen::Matrix<double, 12, 12> &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<double, 2, 12> 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<Mat> MtMsvd(M.transpose()*M, Eigen::ComputeFullU);
+  Eigen::Matrix<double, 12, 12> u2 = MtMsvd.matrixU().transpose();
+
+  // Estimate the L matrix.
+  Eigen::Matrix<double, 6, 3> dv1;
+  Eigen::Matrix<double, 6, 3> dv2;
+  Eigen::Matrix<double, 6, 3> dv3;
+  Eigen::Matrix<double, 6, 3> 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<double, 6, 10> 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<Mat3> Rs(3);
+  vector<Vec3> ts(3);
+  Vec rmse(3);
+
+  // TODO(julien): Document where the "1e-3" magical constant comes from below.
+
+  // 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<double, 6, 4> 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<Mat> svd_of_l4(l_6x4, 
+                                  Eigen::ComputeFullU | Eigen::ComputeFullV);
+  Vec4 b4 = svd_of_l4.solve(rho);
+  if ((l_6x4 * b4).isApprox(rho, 1e-3)) {
+    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<double>::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<double, 6, 3> l_6x3;
+  l_6x3 = L.block(0, 0, 6, 3);
+  Eigen::JacobiSVD<Mat> 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, 1e-3)) {
+    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<double>::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<double, 6, 5> l_6x5;
+  l_6x5 = L.block(0, 0, 6, 5);
+  Eigen::JacobiSVD<Mat> svdOfL5(l_6x5, 
+                                Eigen::ComputeFullU | Eigen::ComputeFullV);
+  Vec5 b5 = svdOfL5.solve(rho);
+  if ((l_6x5 * b5).isApprox(rho, 1e-3)) {
+    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<double>::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(0);
+  VLOG(2) << "RMSE for solution 2: " << rmse(0);
+  size_t n = 0;
+  if (rmse(1) < rmse(0)) {
+    n = 1;
+  }
+  if (rmse(2) < rmse(n)) {
+    n = 2;
+  }
+  if (rmse(n) == std::numeric_limits<double>::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;
+}
+
+} // namespace resection
+} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/euclidean_resection.h b/extern/libmv/libmv/multiview/euclidean_resection.h
new file mode 100644 (file)
index 0000000..08fa3d9
--- /dev/null
@@ -0,0 +1,124 @@
+// 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,
+  RESECTION_EPNP,
+};
+
+/**
+ * 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);
+
+} // namespace euclidean_resection
+} // namespace libmv
+
+
+#endif /* LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ */
diff --git a/extern/libmv/libmv/multiview/fundamental.cc b/extern/libmv/libmv/multiview/fundamental.cc
new file mode 100644 (file)
index 0000000..7a6b4a0
--- /dev/null
@@ -0,0 +1,391 @@
+// 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/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"
+#include "libmv/multiview/fundamental.h"
+
+namespace libmv {
+
+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
+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<RMat3>(f.data());
+  return smaller_singular_value;
+}
+
+// HZ 11.1.1 pag.280
+void EnforceFundamentalRank2Constraint(Mat3 *F) {
+  Eigen::JacobiSVD<Mat3> 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<Mat3> *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<double, 7, 9> 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<RMat3>(f1.data());
+  Mat3 F2 = Map<RMat3>(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<Mat3> *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<Mat3> *Rs,
+                         std::vector<Vec3> *ts) {
+  Eigen::JacobiSVD<Mat3> USV(E, Eigen::ComputeFullU | Eigen::ComputeFullV);
+  Mat3 U =  USV.matrixU();
+  Vec3 d =  USV.singularValues();
+  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<Mat3> &Rs,
+                                      const std::vector<Vec3> &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<Mat3> Rs;
+  std::vector<Vec3> 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;
+  }
+}
+
+}  // namespace libmv
diff --git a/extern/libmv/libmv/multiview/fundamental.h b/extern/libmv/libmv/multiview/fundamental.h
new file mode 100644 (file)
index 0000000..3f4a3b7
--- /dev/null
@@ -0,0 +1,144 @@
+// 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 <vector>
+
+#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<Mat3> *F);
+
+/**
+ * 7 points (points coordinates must be in image space):
+ */
+double FundamentalFromCorrespondences7Point(const Mat &x1,
+                                            const Mat &x2,
+                                            std::vector<Mat3> *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<Mat3> *Rs,
+                         std::vector<Vec3> *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<Mat3> &Rs,
+                                      const std::vector<Vec3> &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);
+
+}  // namespace libmv
+
+#endif  // LIBMV_MULTIVIEW_FUNDAMENTAL_H_
diff --git a/extern/libmv/libmv/multiview/nviewtriangulation.h b/extern/libmv/libmv/multiview/nviewtriangulation.h
new file mode 100644 (file)
index 0000000..b4f521f
--- /dev/null
@@ -0,0 +1,80 @@
+// 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<typename T>
+void NViewTriangulate(const Matrix<T, 2, Dynamic> &x,
+                      const vector<Matrix<T, 3, 4> > &Ps,
+                      Matrix<T, 4, 1> *X) {
+  int nviews = x.cols();
+  assert(nviews == Ps.size());
+
+  Matrix<T, Dynamic, Dynamic> 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<T, Dynamic, 1>  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<typename T>
+void NViewTriangulateAlgebraic(const Matrix<T, 2, Dynamic> &x,
+                               const vector<Matrix<T, 3, 4> > &Ps,
+                               Matrix<T, 4, 1> *X) {
+  int nviews = x.cols();
+  assert(nviews == Ps.size());
+
+  Matrix<T, Dynamic, 4> 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/projection.cc b/extern/libmv/libmv/multiview/projection.cc
new file mode 100644 (file)
index 0000000..a7d1a05
--- /dev/null
@@ -0,0 +1,221 @@
+// 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
new file mode 100644 (file)
index 0000000..bc353b6
--- /dev/null
@@ -0,0 +1,231 @@
+// 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/resection.h b/extern/libmv/libmv/multiview/resection.h
new file mode 100644 (file)
index 0000000..e462389
--- /dev/null
@@ -0,0 +1,62 @@
+// 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<typename T>
+void Resection(const Matrix<T, 2, Dynamic> &x,
+               const Matrix<T, 4, Dynamic> &X,
+               Matrix<T, 3, 4> *P) {
+  int N = x.cols();
+  assert(X.cols() == N);
+
+  Matrix<T, Dynamic, 12> 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<T, 12, 1> 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/triangulation.cc b/extern/libmv/libmv/multiview/triangulation.cc
new file mode 100644 (file)
index 0000000..b9d38ce
--- /dev/null
@@ -0,0 +1,49 @@
+// 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/multiview/projection.h"
+#include "libmv/multiview/triangulation.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
new file mode 100644 (file)
index 0000000..c35774d
--- /dev/null
@@ -0,0 +1,38 @@
+// 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/numeric/dogleg.h b/extern/libmv/libmv/numeric/dogleg.h
new file mode 100644 (file)
index 0000000..f05882c
--- /dev/null
@@ -0,0 +1,261 @@
+// 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 <cmath>
+#include <cstdio>
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/function_derivative.h"
+#include "libmv/logging/logging.h"
+
+namespace libmv {
+
+template<typename Function,
+         typename Jacobian = NumericJacobian<Function>,
+         typename Solver = Eigen::PartialPivLU<
+           Matrix<typename Function::FMatrixType::RealScalar, 
+                  Function::XMatrixType::RowsAtCompileTime,
+                  Function::XMatrixType::RowsAtCompileTime> > >
+class Dogleg {
+ public:
+  typedef typename Function::XMatrixType::RealScalar Scalar;
+  typedef typename Function::FMatrixType FVec;
+  typedef typename Function::XMatrixType Parameters;
+  typedef Matrix<typename Function::FMatrixType::RealScalar,
+                 Function::FMatrixType::RowsAtCompileTime,
+                 Function::XMatrixType::RowsAtCompileTime> JMatrixType;
+  typedef Matrix<typename JMatrixType::RealScalar, 
+                 JMatrixType::ColsAtCompileTime, 
+                 JMatrixType::ColsAtCompileTime> 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 &params,
+                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 &params, 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/function_derivative.h b/extern/libmv/libmv/numeric/function_derivative.h
new file mode 100644 (file)
index 0000000..d7bc437
--- /dev/null
@@ -0,0 +1,107 @@
+// 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 <cmath>
+
+#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<typename Function, NumericJacobianMode mode=CENTRAL>
+class NumericJacobian {
+ public:
+  typedef typename Function::XMatrixType Parameters;
+  typedef typename Function::XMatrixType::RealScalar XScalar;
+  typedef typename Function::FMatrixType FMatrixType;
+  typedef Matrix<typename Function::FMatrixType::RealScalar,
+                 Function::FMatrixType::RowsAtCompileTime,
+                 Function::XMatrixType::RowsAtCompileTime>
+          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<typename Function, typename Jacobian>
+bool CheckJacobian(const Function &f, const typename Function::XMatrixType &x) {
+  Jacobian j_analytic(f);
+  NumericJacobian<Function> j_numeric(f);
+
+  typename NumericJacobian<Function>::JMatrixType J_numeric = j_numeric(x);
+  typename NumericJacobian<Function>::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/levenberg_marquardt.h b/extern/libmv/libmv/numeric/levenberg_marquardt.h
new file mode 100644 (file)
index 0000000..4473b72
--- /dev/null
@@ -0,0 +1,183 @@
+// 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 <cmath>
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/function_derivative.h"
+#include "libmv/logging/logging.h"
+
+namespace libmv {
+
+template<typename Function,
+         typename Jacobian = NumericJacobian<Function>,
+         typename Solver = Eigen::PartialPivLU<
+           Matrix<typename Function::FMatrixType::RealScalar, 
+                  Function::XMatrixType::RowsAtCompileTime,
+                  Function::XMatrixType::RowsAtCompileTime> > >
+class LevenbergMarquardt {
+ public:
+  typedef typename Function::XMatrixType::RealScalar Scalar;
+  typedef typename Function::FMatrixType FVec;
+  typedef typename Function::XMatrixType Parameters;
+  typedef Matrix<typename Function::FMatrixType::RealScalar,
+                 Function::FMatrixType::RowsAtCompileTime,
+                 Function::XMatrixType::RowsAtCompileTime> JMatrixType;
+  typedef Matrix<typename JMatrixType::RealScalar, 
+                 JMatrixType::ColsAtCompileTime, 
+                 JMatrixType::ColsAtCompileTime> 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 &params,
+                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 &params, 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(1) << "iteration: " << i;
+      VLOG(1) << "||f(x)||: " << f_(x).norm();
+      VLOG(1) << "max(g): " << g.array().abs().maxCoeff();
+      VLOG(1) << "u: " << u;
+      VLOG(1) << "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/numeric.cc b/extern/libmv/libmv/numeric/numeric.cc
new file mode 100644 (file)
index 0000000..0ca3a64
--- /dev/null
@@ -0,0 +1,136 @@
+// 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
new file mode 100644 (file)
index 0000000..21e0f06
--- /dev/null
@@ -0,0 +1,479 @@
+// 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 <Eigen/Cholesky>
+#include <Eigen/Core>
+#include <Eigen/Eigenvalues>
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+#include <Eigen/SVD>
+
+#if _WIN32 || __APPLE__
+  void static sincos (double x, double *sinx, double *cosx) {
+    *sinx = sin(x);
+    *cosx = cos(x);
+  }
+#endif //_WIN32 || __APPLE__
+
+#if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__)
+  inline long lround(double d) {
+    return (long)(d>0 ? d+0.5 : ceil(d-0.5));
+  }
+  inline int round(double d) {
+    return (d>0) ? int(d+0.5) : int(d-0.5);
+  }
+  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<unsigned int, Eigen::Dynamic, Eigen::Dynamic> Matu;
+typedef Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> Vecu;
+typedef Eigen::Matrix<unsigned int, 2, 1> Vec2u;
+
+typedef Eigen::Matrix<double, 2, 2> Mat2;
+typedef Eigen::Matrix<double, 2, 3> Mat23;
+typedef Eigen::Matrix<double, 3, 3> Mat3;
+typedef Eigen::Matrix<double, 3, 4> Mat34;
+typedef Eigen::Matrix<double, 3, 5> Mat35;
+typedef Eigen::Matrix<double, 4, 1> Mat41;
+typedef Eigen::Matrix<double, 4, 3> Mat43;
+typedef Eigen::Matrix<double, 4, 4> Mat4;
+typedef Eigen::Matrix<double, 4, 6> Mat46;
+typedef Eigen::Matrix<float, 2, 2> Mat2f;
+typedef Eigen::Matrix<float, 2, 3> Mat23f;
+typedef Eigen::Matrix<float, 3, 3> Mat3f;
+typedef Eigen::Matrix<float, 3, 4> Mat34f;
+typedef Eigen::Matrix<float, 3, 5> Mat35f;
+typedef Eigen::Matrix<float, 4, 3> Mat43f;
+typedef Eigen::Matrix<float, 4, 4> Mat4f;
+typedef Eigen::Matrix<float, 4, 6> Mat46f;
+
+typedef Eigen::Matrix<double, 3, 3, Eigen::RowMajor> RMat3;
+typedef Eigen::Matrix<double, 4, 4, Eigen::RowMajor> RMat4;
+
+typedef Eigen::Matrix<double, 2, Eigen::Dynamic> Mat2X;
+typedef Eigen::Matrix<double, 3, Eigen::Dynamic> Mat3X;
+typedef Eigen::Matrix<double, 4, Eigen::Dynamic> Mat4X;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 2> MatX2;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 3> MatX3;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 4> MatX4;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 5> MatX5;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 6> MatX6;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 7> MatX7;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 8> MatX8;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 9> MatX9;
+typedef Eigen::Matrix<double, Eigen::Dynamic,15> MatX15;
+typedef Eigen::Matrix<double, Eigen::Dynamic,16> MatX16;
+
+typedef Eigen::Vector2d Vec2;
+typedef Eigen::Vector3d Vec3;
+typedef Eigen::Vector4d Vec4;
+typedef Eigen::Matrix<double, 5, 1>  Vec5;
+typedef Eigen::Matrix<double, 6, 1>  Vec6;
+typedef Eigen::Matrix<double, 7, 1>  Vec7;
+typedef Eigen::Matrix<double, 8, 1>  Vec8;
+typedef Eigen::Matrix<double, 9, 1>  Vec9;
+typedef Eigen::Matrix<double, 10, 1> Vec10;
+typedef Eigen::Matrix<double, 11, 1> Vec11;
+typedef Eigen::Matrix<double, 12, 1> Vec12;
+typedef Eigen::Matrix<double, 13, 1> Vec13;
+typedef Eigen::Matrix<double, 14, 1> Vec14;
+typedef Eigen::Matrix<double, 15, 1> Vec15;
+typedef Eigen::Matrix<double, 16, 1> Vec16;
+typedef Eigen::Matrix<double, 17, 1> Vec17;
+typedef Eigen::Matrix<double, 18, 1> Vec18;
+typedef Eigen::Matrix<double, 19, 1> Vec19;
+typedef Eigen::Matrix<double, 20, 1> 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<float,
+                      Eigen::Dynamic,
+                      Eigen::Dynamic,
+                      Eigen::RowMajor> RMatf;
+
+typedef Eigen::NumTraits<double> EigenDouble;
+
+using Eigen::Map;
+using Eigen::Dynamic;
+using Eigen::Matrix;
+
+// Find U, s, and VT such that
+//
+//   A = U * diag(s) * VT
+//
+template <typename TMat, typename TVec>
+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 <typename TMat, typename TVec>
+double Nullspace(TMat *A, TVec *nullspace) {
+  Eigen::JacobiSVD<TMat> 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 <typename TMat, typename TVec1, typename TVec2>
+double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2) {
+  Eigen::JacobiSVD<TMat> 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<class TA>
+inline void TransposeInPlace(TA *A) {
+  *A = A->transpose().eval();
+}
+
+template<typename TVec>
+inline double NormL1(const TVec &x) {
+  return x.array().abs().sum();
+}
+
+template<typename TVec>
+inline double NormL2(const TVec &x) {
+  return x.norm();
+}
+
+template<typename TVec>
+inline double NormLInfinity(const TVec &x) {
+  return x.array().abs().maxCoeff();
+}
+
+template<typename TVec>
+inline double DistanceL1(const TVec &x, const TVec &y) {
+  return (x - y).array().abs().sum();
+}
+
+template<typename TVec>
+inline double DistanceL2(const TVec &x, const TVec &y) {
+  return (x - y).norm();
+}
+template<typename TVec>
+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<typename TVec>
+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<typename TVec>
+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<typename TVec>
+inline double NormalizeLInfinity(TVec *x) {
+  double norm = NormLInfinity(*x);
+  *x /= norm;
+  return norm;
+}
+
+// Return the square of a number.
+template<typename T>
+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 <typename TVec>
+inline Mat Diag(const TVec &x) {
+  return x.asDiagonal();
+}
+
+template<typename TMat>
+inline double FrobeniusNorm(const TMat &A) {
+  return sqrt(A.array().abs2().sum());
+}
+
+template<typename TMat>
+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<typename Derived1, typename Derived2>
+  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<Scalar,
+                RowsAtCompileTime,
+                ColsAtCompileTime,
+                Options,
+                MaxRowsAtCompileTime,
+                MaxColsAtCompileTime> type;
+  };
+
+  template<typename Derived1, typename Derived2>
+  typename hstack_return<Derived1,Derived2>::type
+  HStack (const Eigen::MatrixBase<Derived1>& lhs, const Eigen::MatrixBase<Derived2>& rhs) {
+    typename hstack_return<Derived1,Derived2>::type res;
+    res.resize(lhs.rows(), lhs.cols()+rhs.cols());
+    res << lhs, rhs;
+    return res;
+  };
+
+
+  template<typename Derived1, typename Derived2>
+  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<Scalar,
+                RowsAtCompileTime,
+                ColsAtCompileTime,
+                Options,
+                MaxRowsAtCompileTime,
+                MaxColsAtCompileTime> type;
+  };
+
+  template<typename Derived1, typename Derived2>
+  typename vstack_return<Derived1,Derived2>::type
+  VStack (const Eigen::MatrixBase<Derived1>& lhs, const Eigen::MatrixBase<Derived2>& rhs) {
+    typename vstack_return<Derived1,Derived2>::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<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
+  Eigen::Matrix<T, ROWS, COLS>
+  HStack(const Eigen::Matrix<T, RowsLeft,  ColsLeft>  &left,
+         const Eigen::Matrix<T, RowsRight, ColsRight> &right) {
+    assert(left.rows() == right.rows());
+    int n = left.rows();
+    int m1 = left.cols();
+    int m2 = right.cols();
+
+    Eigen::Matrix<T, ROWS, COLS> 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<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
+  Eigen::Matrix<T, COLS, ROWS>
+  VStack(const Eigen::Matrix<T, ColsLeft,  RowsLeft>  &top,
+         const Eigen::Matrix<T, ColsRight, RowsRight> &bottom) {
+    assert(top.cols() == bottom.cols());
+     int n1 = top.rows();
+    int n2 = bottom.rows();
+    int m = top.cols();
+
+    Eigen::Matrix<T, COLS, ROWS> 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<typename TTop, typename TBot, typename TStacked>
+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 <typename TMat, typename TCols>
+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 <typename TMat, typename TDest>
+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 <typename FloatType>
+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;
+}
+} // namespace libmv
+
+#endif  // LIBMV_NUMERIC_NUMERIC_H
diff --git a/extern/libmv/libmv/numeric/poly.cc b/extern/libmv/libmv/numeric/poly.cc
new file mode 100644 (file)
index 0000000..d96e3c1
--- /dev/null
@@ -0,0 +1,23 @@
+// 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
new file mode 100644 (file)
index 0000000..cb1d65b
--- /dev/null
@@ -0,0 +1,123 @@
+// 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 <cmath>
+#include <stdio.h>
+
+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<typename Real>
+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<typename Real>
+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/simple_pipeline/bundle.cc b/extern/libmv/libmv/simple_pipeline/bundle.cc
new file mode 100644 (file)
index 0000000..cb8822d
--- /dev/null
@@ -0,0 +1,184 @@
+// 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.
+
+#define V3DLIB_ENABLE_SUITESPARSE 1
+
+#include <map>
+
+#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/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
+#include "third_party/ssba/Geometry/v3d_cameramatrix.h"
+#include "third_party/ssba/Geometry/v3d_metricbundle.h"
+#include "third_party/ssba/Math/v3d_linear.h"
+#include "third_party/ssba/Math/v3d_linear_utils.h"
+
+namespace libmv {
+
+void EuclideanBundle(const Tracks &tracks,
+                     EuclideanReconstruction *reconstruction) {
+  vector<Marker> markers = tracks.AllMarkers();
+
+  // "index" in this context is the index that V3D's optimizer will see. The
+  // V3D index must be dense in that the cameras are numbered 0...n-1, which is
+  // not the case for the "image" numbering that arises from the tracks
+  // structure. The complicated mapping is necessary to convert between the two
+  // representations.
+  std::map<EuclideanCamera *, int> camera_to_index;
+  std::map<EuclideanPoint *, int> point_to_index;
+  vector<EuclideanCamera *> index_to_camera;
+  vector<EuclideanPoint *> index_to_point;
+  int num_cameras = 0;
+  int num_points = 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 && point) {
+      if (camera_to_index.find(camera) == camera_to_index.end()) {
+        camera_to_index[camera] = num_cameras;
+        index_to_camera.push_back(camera);
+        num_cameras++;
+      }
+      if (point_to_index.find(point) == point_to_index.end()) {
+        point_to_index[point] = num_points;
+        index_to_point.push_back(point);
+        num_points++;
+      }
+    }
+  }
+
+  // Make a V3D identity matrix, needed in a few places for K, since this
+  // assumes a calibrated setup.
+  V3D::Matrix3x3d identity3x3;
+  identity3x3[0][0] = 1.0;
+  identity3x3[0][1] = 0.0;
+  identity3x3[0][2] = 0.0;
+  identity3x3[1][0] = 0.0;
+  identity3x3[1][1] = 1.0;
+  identity3x3[1][2] = 0.0;
+  identity3x3[2][0] = 0.0;
+  identity3x3[2][1] = 0.0;
+  identity3x3[2][2] = 1.0;
+
+  // Convert libmv's cameras to V3D's cameras.
+  std::vector<V3D::CameraMatrix> v3d_cameras(index_to_camera.size());
+  for (int k = 0; k < index_to_camera.size(); ++k) {
+    V3D::Matrix3x3d R;
+    V3D::Vector3d t;
+
+    // Libmv's rotation matrix type.
+    const Mat3 &R_libmv = index_to_camera[k]->R;
+    const Vec3 &t_libmv = index_to_camera[k]->t;
+
+    for (int i = 0; i < 3; ++i) {
+      for (int j = 0; j < 3; ++j) {
+        R[i][j] = R_libmv(i, j);
+      }
+      t[i] = t_libmv(i);
+    }
+    v3d_cameras[k].setIntrinsic(identity3x3);
+    v3d_cameras[k].setRotation(R);
+    v3d_cameras[k].setTranslation(t);
+  }
+  LG << "Number of cameras: " << index_to_camera.size();
+
+  // Convert libmv's points to V3D's points.
+  std::vector<V3D::Vector3d> v3d_points(index_to_point.size());
+  for (int i = 0; i < index_to_point.size(); i++) {
+    v3d_points[i][0] = index_to_point[i]->X(0);
+    v3d_points[i][1] = index_to_point[i]->X(1);
+    v3d_points[i][2] = index_to_point[i]->X(2);
+  }
+  LG << "Number of points: " << index_to_point.size();
+
+  // Convert libmv's measurements to v3d measurements.
+  int num_residuals = 0;
+  std::vector<V3D::Vector2d> v3d_measurements;
+  std::vector<int> v3d_camera_for_measurement;
+  std::vector<int> v3d_point_for_measurement;
+  for (int i = 0; i < markers.size(); ++i) {
+    EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
+    EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
+    if (!camera || !point) {
+      continue;
+    }
+    V3D::Vector2d v3d_point;
+    v3d_point[0] = markers[i].x;
+    v3d_point[1] = markers[i].y;
+    v3d_measurements.push_back(v3d_point);
+    v3d_camera_for_measurement.push_back(camera_to_index[camera]);
+    v3d_point_for_measurement.push_back(point_to_index[point]);
+    num_residuals++;
+  }
+  LG << "Number of residuals: " << num_residuals;
+  
+  // This is calibrated reconstruction, so use zero distortion.
+  V3D::StdDistortionFunction v3d_distortion;
+  v3d_distortion.k1 = 0;
+  v3d_distortion.k2 = 0;
+  v3d_distortion.p1 = 0;
+  v3d_distortion.p2 = 0;
+
+  // Finally, run the bundle adjustment.
+  double const inlierThreshold = 500000.0;
+  V3D::CommonInternalsMetricBundleOptimizer opt(V3D::FULL_BUNDLE_METRIC,
+                                                inlierThreshold,
+                                                identity3x3,
+                                                v3d_distortion,
+                                                v3d_cameras,
+                                                v3d_points,
+                                                v3d_measurements,
+                                                v3d_camera_for_measurement,
+                                                v3d_point_for_measurement);
+  opt.maxIterations = 50;
+  opt.minimize();
+  LG << "Bundle status: " << opt.status;
+
+  // Convert V3D's cameras back to libmv's cameras.
+  for (int k = 0; k < num_cameras; k++) {
+    V3D::Matrix3x4d const Rt = v3d_cameras[k].getOrientation();
+    for (int i = 0; i < 3; ++i) {
+      for (int j = 0; j < 3; ++j) {
+        index_to_camera[k]->R(i, j) = Rt[i][j];
+      }
+      index_to_camera[k]->t(i) = Rt[i][3];
+    }
+  }
+
+  // Convert V3D's points back to libmv's points.
+  for (int k = 0; k < num_points; k++) {
+    for (int i = 0; i < 3; ++i) {
+      index_to_point[k]->X(i) = v3d_points[k][i];
+    }
+  }
+}
+
+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
new file mode 100644 (file)
index 0000000..c7fb2a7
--- /dev/null
@@ -0,0 +1,72 @@
+// 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
+
+namespace libmv {
+
+class EuclideanReconstruction;
+class ProjectiveReconstruction;
+class Tracks;
+
+/*!
+    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 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/camera_intrinsics.cc b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
new file mode 100644 (file)
index 0000000..366129d
--- /dev/null
@@ -0,0 +1,351 @@
+// 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/numeric/levenberg_marquardt.h"
+
+namespace libmv {
+
+struct Offset {
+  signed char ix, iy;
+  unsigned char fx,fy;
+};
+
+struct Grid {
+  struct Offset *offset;
+  int width, height;
+  double overscan;
+};
+
+static struct Grid *copyGrid(struct Grid *from)
+{
+  struct Grid *to = NULL;
+
+  if (from) {
+    to = new Grid;
+
+    to->width = from->width;
+    to->height = from->height;
+    to->overscan = from->overscan;
+
+    to->offset = new Offset[to->width*to->height];
+    memcpy(to->offset, from->offset, sizeof(struct Offset)*to->width*to->height);
+  }
+
+  return to;
+}
+
+CameraIntrinsics::CameraIntrinsics()
+    : K_(Mat3::Identity()),
+      image_width_(0),
+      image_height_(0),
+      k1_(0),
+      k2_(0),
+      k3_(0),
+      p1_(0),
+      p2_(0),
+      distort_(0),
+      undistort_(0) {}
+
+CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics &from)
+    : K_(from.K_),
+      image_width_(from.image_width_),
+      image_height_(from.image_height_),
+      k1_(from.k1_),
+      k2_(from.k2_),
+      k3_(from.k3_),
+      p1_(from.p1_),
+      p2_(from.p2_)
+{
+  distort_ = copyGrid(from.distort_);
+  undistort_ = copyGrid(from.undistort_);
+}
+
+CameraIntrinsics::~CameraIntrinsics() {
+  FreeLookupGrid();
+}
+
+/// Set the entire calibration matrix at once.
+void CameraIntrinsics::SetK(const Mat3 new_k) {
+  K_ = new_k;
+  FreeLookupGrid();
+}
+
+/// 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;
+  FreeLookupGrid();
+}
+
+void CameraIntrinsics::SetPrincipalPoint(double cx, double cy) {
+  K_(0, 2) = cx;
+  K_(1, 2) = cy;
+  FreeLookupGrid();
+}
+
+void CameraIntrinsics::SetImageSize(int width, int height) {
+  image_width_ = width;
+  image_height_ = height;
+  FreeLookupGrid();
+}
+
+void CameraIntrinsics::SetRadialDistortion(double k1, double k2, double k3) {
+  k1_ = k1;
+  k2_ = k2;
+  k3_ = k3;
+  FreeLookupGrid();
+}
+
+void CameraIntrinsics::SetTangentialDistortion(double p1, double p2) {
+  p1_ = p1;
+  p2_ = p2;
+  FreeLookupGrid();
+}
+
+void CameraIntrinsics::ApplyIntrinsics(double normalized_x,
+                                       double normalized_y,
+                                       double *image_x,
+                                       double *image_y) const {
+  double x = normalized_x;
+  double y = normalized_y;
+
+  // Apply distortion to the normalized points to get (xd, yd).
+  double r2 = x*x + y*y;
+  double r4 = r2 * r2;
+  double r6 = r4 * r2;
+  double r_coeff = (1 + k1_*r2 + k2_*r4 + k3_*r6);
+  double xd = x * r_coeff + 2*p1_*x*y + p2_*(r2 + 2*x*x);
+  double yd = y * r_coeff + 2*p2_*x*y + p1_*(r2 + 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();
+}
+
+struct InvertIntrinsicsCostFunction {
+ public:
+  typedef Vec2 FMatrixType;
+  typedef Vec2 XMatrixType;
+
+  InvertIntrinsicsCostFunction(const CameraIntrinsics &intrinsics,
+                               double image_x, double image_y)
+    : intrinsics(intrinsics), x(image_x), y(image_y) {}
+
+  Vec2 operator()(const Vec2 &u) const {
+    double xx, yy;
+    intrinsics.ApplyIntrinsics(u(0), u(1), &xx, &yy);
+    Vec2 fx;
+    fx << (xx - x), (yy - y);
+    return fx;
+  }
+  const CameraIntrinsics &intrinsics;
+  double x, y;
+};
+
+void CameraIntrinsics::InvertIntrinsics(double image_x,
+                                        double image_y,
+                                        double *normalized_x,
+                                        double *normalized_y) const {
+  // 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<InvertIntrinsicsCostFunction> Solver;
+
+  InvertIntrinsicsCostFunction intrinsics_cost(*this, 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);
+}
+
+// TODO(MatthiasF): downsample lookup
+template<typename WarpFunction>
+void CameraIntrinsics::ComputeLookupGrid(Grid* grid, int width, int height, double overscan) {
+  double w = (double)width / (1 + overscan);
+  double h = (double)height / (1 + overscan);
+  double aspx = (double)w / image_width_;
+  double aspy = (double)h / image_height_;
+
+  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(this,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++; }
+      if(fy == 256) { fy=0; iy++; }
+      // Use nearest border pixel
+      if( ix < 0 ) { ix = 0, fx = 0; }
+      if( iy < 0 ) { iy = 0, fy = 0; }
+      if( ix >= width-2 ) ix = width-2;
+      if( iy >= height-2 ) iy = height-2;
+      if ( ix-x > -128 && ix-x < 128 && iy-y > -128 && iy-y < 128 ) {
+        Offset offset = { ix-x, iy-y, fx, fy };
+        grid->offset[y*width+x] = offset;
+      } else {
+        Offset offset = { 0, 0, 0, 0 };
+        grid->offset[y*width+x] = offset;
+      }
+    }
+  }
+}
+
+// TODO(MatthiasF): cubic B-Spline image sampling, bilinear lookup
+template<typename T,int N>
+static void Warp(const Grid* grid, const T* src, T* dst,
+                 int width, int height) {
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      Offset offset = grid->offset[y*width+x];
+      const T* s = &src[((y+offset.iy)*width+(x+offset.ix))*N];
+      for (int i = 0; i < N; i++) {
+        dst[(y*width+x)*N+i] = ((s[        i] * (256-offset.fx) + s[        N+i] * offset.fx) * (256-offset.fy)
+                               +(s[width*N+i] * (256-offset.fx) + s[width*N+N+i] * offset.fx) * offset.fy) / (256*256);
+      }
+    }
+  }
+}
+
+void CameraIntrinsics::FreeLookupGrid() {
+  if(distort_) {
+    delete distort_->offset;
+    delete distort_;
+    distort_ = NULL;
+  }
+
+  if(undistort_) {
+    delete undistort_->offset;
+    delete undistort_;
+    undistort_ = NULL;
+  }
+}
+
+// FIXME: C++ templates limitations makes thing complicated, but maybe there is a simpler method.
+struct ApplyIntrinsicsFunction {
+  ApplyIntrinsicsFunction(CameraIntrinsics* intrinsics, double x, double y,
+                           double *warp_x, double *warp_y) {
+    intrinsics->ApplyIntrinsics(
+          (x-intrinsics->principal_point_x())/intrinsics->focal_length_x(),
+          (y-intrinsics->principal_point_y())/intrinsics->focal_length_y(),
+          warp_x, warp_y);
+  }
+};
+struct InvertIntrinsicsFunction {
+  InvertIntrinsicsFunction(CameraIntrinsics* intrinsics, double x, double y,
+                           double *warp_x, double *warp_y) {
+    intrinsics->InvertIntrinsics(x,y,warp_x,warp_y);
+    *warp_x = *warp_x*intrinsics->focal_length_x()+intrinsics->principal_point_x();
+    *warp_y = *warp_y*intrinsics->focal_length_y()+intrinsics->principal_point_y();
+  }
+};
+
+void CameraIntrinsics::CheckDistortLookupGrid(int width, int height, double overscan)
+{
+  if(distort_) {
+    if(distort_->width != width || distort_->height != height || distort_->overscan != overscan) {
+      delete [] distort_->offset;
+      distort_->offset = NULL;
+    }
+  } else {
+    distort_ = new Grid;
+    distort_->offset = NULL;
+  }
+
+  if(!distort_->offset) {
+      distort_->offset = new Offset[width*height];
+      ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height,overscan);
+  }
+
+  distort_->width = width;
+  distort_->height = height;
+  distort_->overscan = overscan;
+}
+
+void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height, double overscan)
+{
+  if(undistort_) {
+    if(undistort_->width != width || undistort_->height != height || undistort_->overscan != overscan) {
+      delete [] undistort_->offset;
+      undistort_->offset = NULL;
+    }
+  } else {
+    undistort_ = new Grid;
+    undistort_->offset = NULL;
+  }
+
+  if(!undistort_->offset) {
+      undistort_->offset = new Offset[width*height];
+      ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height,overscan);
+  }
+
+  undistort_->width = width;
+  undistort_->height = height;
+  undistort_->overscan = overscan;
+}
+
+void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, double overscan, int channels) {
+  CheckDistortLookupGrid(width, height, overscan);
+       if(channels==1) Warp<float,1>(distort_,src,dst,width,height);
+  else if(channels==2) Warp<float,2>(distort_,src,dst,width,height);
+  else if(channels==3) Warp<float,3>(distort_,src,dst,width,height);
+  else if(channels==4) Warp<float,4>(distort_,src,dst,width,height);
+  //else assert("channels must be between 1 and 4");
+}
+
+void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int width, int height, double overscan, int channels) {
+  CheckDistortLookupGrid(width, height, overscan);
+       if(channels==1) Warp<unsigned char,1>(distort_,src,dst,width,height);
+  else if(channels==2) Warp<unsigned char,2>(distort_,src,dst,width,height);
+  else if(channels==3) Warp<unsigned char,3>(distort_,src,dst,width,height);
+  else if(channels==4) Warp<unsigned char,4>(distort_,src,dst,width,height);
+  //else assert("channels must be between 1 and 4");
+}
+
+void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int height, double overscan, int channels) {
+  CheckUndistortLookupGrid(width, height, overscan);
+       if(channels==1) Warp<float,1>(undistort_,src,dst,width,height);
+  else if(channels==2) Warp<float,2>(undistort_,src,dst,width,height);
+  else if(channels==3) Warp<float,3>(undistort_,src,dst,width,height);
+  else if(channels==4) Warp<float,4>(undistort_,src,dst,width,height);
+  //else assert("channels must be between 1 and 4");
+}
+
+void CameraIntrinsics::Undistort(const unsigned char* src, unsigned char* dst, int width, int height, double overscan, int channels) {
+  CheckUndistortLookupGrid(width, height, overscan);
+       if(channels==1) Warp<unsigned char,1>(undistort_,src,dst,width,height);
+  else if(channels==2) Warp<unsigned char,2>(undistort_,src,dst,width,height);
+  else if(channels==3) Warp<unsigned char,3>(undistort_,src,dst,width,height);
+  else if(channels==4) Warp<unsigned char,4>(undistort_,src,dst,width,height);
+  //else assert("channels must be between 1 and 4");
+}
+
+}  // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
new file mode 100644 (file)
index 0000000..f4bf903
--- /dev/null
@@ -0,0 +1,152 @@
+// 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 <Eigen/Core>
+typedef Eigen::Matrix<double, 3, 3> Mat3;
+
+namespace libmv {
+
+struct Grid;
+
+class CameraIntrinsics {
+ public:
+  CameraIntrinsics();
+  CameraIntrinsics(const CameraIntrinsics &from);
+  ~CameraIntrinsics();
+
+  const Mat3 &K()                 const { return K_;            }
+  // FIXME(MatthiasF): these should be CamelCase methods
+  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);      }
+  int         image_width()       const { return image_width_;  }
+  int         image_height()      const { return image_height_; }
+  double      k1()                const { return k1_; }
+  double      k2()                const { return k2_; }
+  double      k3()                const { return k3_; }
+  double      p1()                const { return p1_; }
+  double      p2()                const { return p2_; }
+
+  /// 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);
+
+  void SetPrincipalPoint(double cx, double cy);
+
+  void SetImageSize(int width, int height);
+
+  void SetRadialDistortion(double k1, double k2, double k3 = 0);