Merging r41555 through r41563 from trunk into soc-2011-tomato
authorSergey Sharybin <sergey.vfx@gmail.com>
Sat, 5 Nov 2011 14:34:14 +0000 (14:34 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Sat, 5 Nov 2011 14:34:14 +0000 (14:34 +0000)
336 files changed:
CMakeLists.txt
build_files/scons/tools/Blender.py
build_files/scons/tools/btools.py
extern/CMakeLists.txt
extern/SConscript
extern/colamd/CMakeLists.txt
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/numeric/tinyvector.cc [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]
intern/ghost/GHOST_ISystem.h
intern/ghost/intern/GHOST_System.cpp
intern/ghost/intern/GHOST_System.h
release/datafiles/blender_icons.png
release/datafiles/splash.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_data_camera.py
release/scripts/startup/bl_ui/properties_object_constraint.py
release/scripts/startup/bl_ui/properties_particle.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_image.h
source/blender/blenkernel/BKE_main.h
source/blender/blenkernel/BKE_movieclip.h [new file with mode: 0644]
source/blender/blenkernel/BKE_node.h
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/DerivedMesh.c
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/image.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/movieclip.c [new file with mode: 0644]
source/blender/blenkernel/intern/node.c
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/datafiles/splash.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_image/image_ops.c
source/blender/editors/space_node/drawnode.c
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/imbuf/intern/filter.c
source/blender/imbuf/intern/moviecache.c
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_nodetree.c
source/blender/makesrna/intern/rna_nodetree_types.h
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/nodes/CMakeLists.txt
source/blender/nodes/NOD_composite.h
source/blender/nodes/composite/node_composite_tree.c
source/blender/nodes/composite/node_composite_util.h
source/blender/nodes/composite/nodes/node_composite_image.c
source/blender/nodes/composite/nodes/node_composite_movieclip.c [new file with mode: 0644]
source/blender/nodes/composite/nodes/node_composite_moviedistortion.c [new file with mode: 0644]
source/blender/nodes/composite/nodes/node_composite_scale.c
source/blender/nodes/composite/nodes/node_composite_stabilize2d.c [new file with mode: 0644]
source/blender/nodes/composite/nodes/node_composite_transform.c [new file with mode: 0644]
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
source/gameengine/GamePlayer/ghost/GPG_ghost.cpp

index 0e06f39..1b338fc 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)
 
+# 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 44f9a4c..ba15f1c 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 68054fe..5c78dc6 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 321ebc1..a5dd3b1 100644 (file)
@@ -63,3 +63,7 @@ endif()
 if(WITH_LZMA)
        add_subdirectory(lzma)
 endif()
+
+if(WITH_LIBMV)
+       add_subdirectory(libmv)
+endif()
index f363d75..031471a 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'])
index 5b56551..34389f5 100644 (file)
@@ -23,7 +23,7 @@
 # ***** END GPL LICENSE BLOCK *****
 
 set(INC
-       Include
+       ./Include
 )
 
 set(INC_SYS
@@ -34,8 +34,7 @@ set(SRC
        Source/colamd.c
        Source/colamd_global.c
 
-       Include/colamd.h
-       Include/UFconfig.h
+       Include//colamd.h
 )
 
 blender_add_lib(extern_colamd "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt
new file mode 100644 (file)
index 0000000..35d04c6
--- /dev/null
@@ -0,0 +1,211 @@
+# ***** 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/numeric/tinyvector.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/numeric/tinyvector.cc b/extern/libmv/libmv/numeric/tinyvector.cc
new file mode 100644 (file)
index 0000000..e69de29
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;