Merged changes in the trunk up to revision 41638.
Conflicts resolved: doc/python_api/sphinx_doc_gen.py source/blender/blenkernel/BKE_main.h source/blender/blenkernel/intern/library.c source/blender/blenloader/intern/readfile.c source/blender/blenloader/intern/writefile.c source/blender/editors/include/UI_resources.h source/blender/editors/interface/resources.c source/blender/makesdna/DNA_ID.h source/blender/makesdna/intern/makesdna.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_scene.c
This commit is contained in:
@@ -157,6 +157,8 @@ endif()
|
|||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
option(WITH_X11_XINPUT "Enable X11 Xinput (tablet support and unicode input)" ON)
|
option(WITH_X11_XINPUT "Enable X11 Xinput (tablet support and unicode input)" ON)
|
||||||
option(WITH_BUILTIN_GLEW "Use GLEW OpenGL wrapper library bundled with blender" ON)
|
option(WITH_BUILTIN_GLEW "Use GLEW OpenGL wrapper library bundled with blender" ON)
|
||||||
|
option(WITH_XDG_USER_DIRS "Build with XDG Base Directory Specification (only config and documents for now)" OFF)
|
||||||
|
mark_as_advanced(WITH_XDG_USER_DIRS)
|
||||||
else()
|
else()
|
||||||
# not an option for other OS's
|
# not an option for other OS's
|
||||||
set(WITH_BUILTIN_GLEW ON)
|
set(WITH_BUILTIN_GLEW ON)
|
||||||
@@ -200,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_LZO "Enable fast LZO compression (used for pointcache)" ON)
|
||||||
option(WITH_LZMA "Enable best LZMA compression, (used for pointcache)" ON)
|
option(WITH_LZMA "Enable best LZMA compression, (used for pointcache)" ON)
|
||||||
|
|
||||||
|
# Camera/motion tracking
|
||||||
|
option(WITH_LIBMV "Enable libmv structure from motion library" ON)
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ON)
|
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)
|
option(WITH_RAYOPTIMIZATION "Enable use of SIMD (SSE) optimizations for the raytracer" ON)
|
||||||
@@ -486,6 +491,36 @@ if(UNIX AND NOT APPLE)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_BOOST)
|
||||||
|
set(BOOST "/usr" CACHE PATH "Boost Directory")
|
||||||
|
|
||||||
|
if(NOT BOOST_CUSTOM)
|
||||||
|
set(BOOST_ROOT ${BOOST})
|
||||||
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
|
find_package(Boost 1.34 REQUIRED COMPONENTS filesystem regex system thread)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
|
||||||
|
set(BOOST_LIBRARIES ${Boost_LIBRARIES})
|
||||||
|
set(BOOST_LIBPATH ${Boost_LIBRARY_DIRS})
|
||||||
|
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_OPENIMAGEIO)
|
||||||
|
set(OPENIMAGEIO "/usr" CACHE PATH "OpenImageIO Directory")
|
||||||
|
|
||||||
|
set(OPENIMAGEIO_ROOT_DIR ${OPENIMAGEIO})
|
||||||
|
find_package(OpenImageIO REQUIRED)
|
||||||
|
|
||||||
|
set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARY} ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES} ${BOOST_LIBRARIES})
|
||||||
|
set(OPENIMAGEIO_LIBPATH) # TODO, remove and reference the absolute path everywhere
|
||||||
|
set(OPENIMAGEIO_DEFINITIONS)
|
||||||
|
|
||||||
|
if(NOT OPENIMAGEIO_FOUND)
|
||||||
|
set(WITH_OPENIMAGEIO OFF)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
|
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
|
||||||
set(PLATFORM_LINKLIBS "-lutil -lc -lm -lpthread -lstdc++")
|
set(PLATFORM_LINKLIBS "-lutil -lc -lm -lpthread -lstdc++")
|
||||||
|
|
||||||
@@ -772,6 +807,28 @@ elseif(WIN32)
|
|||||||
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
|
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_BOOST)
|
||||||
|
set(BOOST ${LIBDIR}/boost)
|
||||||
|
set(BOOST_INCLUDE_DIR ${BOOST}/include)
|
||||||
|
set(BOOST_POSTFIX "vc90-mt-s-1_47.lib")
|
||||||
|
set(BOOST_DEBUG_POSTFIX "vc90-mt-sgd-1_47.lib")
|
||||||
|
set(BOOST_LIBRARIES
|
||||||
|
optimized libboost_date_time-${BOOST_POSTFIX} libboost_filesystem-${BOOST_POSTFIX}
|
||||||
|
libboost_regex-${BOOST_POSTFIX} libboost_system-${BOOST_POSTFIX} libboost_thread-${BOOST_POSTFIX}
|
||||||
|
debug libboost_date_time-${BOOST_DEBUG_POSTFIX} libboost_filesystem-${BOOST_DEBUG_POSTFIX}
|
||||||
|
libboost_regex-${BOOST_DEBUG_POSTFIX} libboost_system-${BOOST_DEBUG_POSTFIX} libboost_thread-${BOOST_DEBUG_POSTFIX})
|
||||||
|
set(BOOST_LIBPATH ${BOOST}/lib)
|
||||||
|
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_OPENIMAGEIO)
|
||||||
|
set(OPENIMAGEIO ${LIBDIR}/openimageio)
|
||||||
|
set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
|
||||||
|
set(OPENIMAGEIO_LIBRARIES OpenImageIO)
|
||||||
|
set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
|
||||||
|
set(OPENIMAGEIO_DEFINITIONS)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(PLATFORM_LINKFLAGS "/SUBSYSTEM:CONSOLE /STACK:2097152 /INCREMENTAL:NO /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcmrt.lib /NODEFAULTLIB:msvcurt.lib /NODEFAULTLIB:msvcrtd.lib")
|
set(PLATFORM_LINKFLAGS "/SUBSYSTEM:CONSOLE /STACK:2097152 /INCREMENTAL:NO /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcmrt.lib /NODEFAULTLIB:msvcurt.lib /NODEFAULTLIB:msvcrtd.lib")
|
||||||
|
|
||||||
# MSVC only, Mingw doesnt need
|
# MSVC only, Mingw doesnt need
|
||||||
@@ -882,6 +939,28 @@ elseif(WIN32)
|
|||||||
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
|
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_BOOST)
|
||||||
|
set(BOOST ${LIBDIR}/boost)
|
||||||
|
set(BOOST_INCLUDE_DIR ${BOOST}/include)
|
||||||
|
set(BOOST_POSTFIX "vc90-mt-s-1_46_1")
|
||||||
|
set(BOOST_DEBUG_POSTFIX "vc90-mt-sgd-1_46_1")
|
||||||
|
set(BOOST_LIBRARIES
|
||||||
|
optimized libboost_date_time-${BOOST_POSTFIX} libboost_filesystem-${BOOST_POSTFIX}
|
||||||
|
libboost_regex-${BOOST_POSTFIX} libboost_system-${BOOST_POSTFIX} libboost_thread-${BOOST_POSTFIX}
|
||||||
|
debug libboost_date_time-${BOOST_DEBUG_POSTFIX} libboost_filesystem-${BOOST_DEBUG_POSTFIX}
|
||||||
|
libboost_regex-${BOOST_DEBUG_POSTFIX} libboost_system-${BOOST_DEBUG_POSTFIX} libboost_thread-${BOOST_DEBUG_POSTFIX})
|
||||||
|
set(BOOST_LIBPATH ${BOOST}/lib)
|
||||||
|
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_OPENIMAGEIO)
|
||||||
|
set(OPENIMAGEIO ${LIBDIR}/openimageio)
|
||||||
|
set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
|
||||||
|
set(OPENIMAGEIO_LIBRARIES OpenImageIO)
|
||||||
|
set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
|
||||||
|
set(OPENIMAGEIO_DEFINITIONS)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(PLATFORM_LINKFLAGS "--stack,2097152")
|
set(PLATFORM_LINKFLAGS "--stack,2097152")
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
@@ -1085,6 +1164,22 @@ elseif(APPLE)
|
|||||||
# linker needs "-weak_framework 3DconnexionClient"
|
# linker needs "-weak_framework 3DconnexionClient"
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_BOOST)
|
||||||
|
set(BOOST ${LIBDIR}/boost)
|
||||||
|
set(BOOST_INCLUDE_DIR ${BOOST}/include)
|
||||||
|
set(BOOST_LIBRARIES boost_date_time-mt boost_filesystem-mt boost_regex-mt boost_system-mt boost_thread-mt)
|
||||||
|
set(BOOST_LIBPATH ${BOOST}/lib)
|
||||||
|
set(BOOST_DEFINITIONS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_OPENIMAGEIO)
|
||||||
|
set(OPENIMAGEIO ${LIBDIR}/openimageio)
|
||||||
|
set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
|
||||||
|
set(OPENIMAGEIO_LIBRARIES OpenImageIO ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARY} ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES})
|
||||||
|
set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib ${JPEG_LIBPATH} ${PNG_LIBPATH} ${TIFF_LIBPATH} ${OPENEXR_LIBPATH} ${ZLIB_LIBPATH})
|
||||||
|
set(OPENIMAGEIO_DEFINITIONS "-DOIIO_STATIC_BUILD")
|
||||||
|
endif()
|
||||||
|
|
||||||
set(EXETYPE MACOSX_BUNDLE)
|
set(EXETYPE MACOSX_BUNDLE)
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
|
set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
|
||||||
@@ -1255,6 +1350,8 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
|||||||
|
|
||||||
# flags to undo strict flags
|
# flags to undo strict flags
|
||||||
ADD_CHECK_C_COMPILER_FLAG(CC_REMOVE_STRICT_FLAGS C_WARN_NO_DEPRECATED_DECLARATIONS -Wno-deprecated-declarations)
|
ADD_CHECK_C_COMPILER_FLAG(CC_REMOVE_STRICT_FLAGS C_WARN_NO_DEPRECATED_DECLARATIONS -Wno-deprecated-declarations)
|
||||||
|
ADD_CHECK_C_COMPILER_FLAG(CC_REMOVE_STRICT_FLAGS C_WARN_NO_UNUSED_PARAMETER -Wno-unused-parameter)
|
||||||
|
ADD_CHECK_C_COMPILER_FLAG(CC_REMOVE_STRICT_FLAGS C_WARN_NO_UNUSED_BUT_SET_VARIABLE -Wno-unused-but-set-variable)
|
||||||
|
|
||||||
elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
|
elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
|
||||||
|
|
||||||
|
|||||||
20
GNUmakefile
20
GNUmakefile
@@ -135,9 +135,6 @@ help:
|
|||||||
@echo " * package_pacman - build an arch linux pacmanpackage"
|
@echo " * package_pacman - build an arch linux pacmanpackage"
|
||||||
@echo " * package_archive - build an archive package"
|
@echo " * package_archive - build an archive package"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Other Targets (not assosiated with building blender)"
|
|
||||||
@echo " * translations - update blenders translation files in po/"
|
|
||||||
@echo ""
|
|
||||||
@echo "Testing Targets (not assosiated with building blender)"
|
@echo "Testing Targets (not assosiated with building blender)"
|
||||||
@echo " * test - run ctest, currently tests import/export, operator execution and that python modules load"
|
@echo " * test - run ctest, currently tests import/export, operator execution and that python modules load"
|
||||||
@echo " * test_cmake - runs our own cmake file checker which detects errors in the cmake file list definitions"
|
@echo " * test_cmake - runs our own cmake file checker which detects errors in the cmake file list definitions"
|
||||||
@@ -151,6 +148,7 @@ help:
|
|||||||
@echo ""
|
@echo ""
|
||||||
@echo "Documentation Targets (not assosiated with building blender)"
|
@echo "Documentation Targets (not assosiated with building blender)"
|
||||||
@echo " * doc_py - generate sphinx python api docs"
|
@echo " * doc_py - generate sphinx python api docs"
|
||||||
|
@echo " * doc_doxy - generate doxygen C/C++ docs"
|
||||||
@echo " * doc_dna - generate blender file format reference"
|
@echo " * doc_dna - generate blender file format reference"
|
||||||
@echo " * doc_man - generate manpage"
|
@echo " * doc_man - generate manpage"
|
||||||
@echo ""
|
@echo ""
|
||||||
@@ -169,16 +167,6 @@ package_archive:
|
|||||||
@echo archive in "$(BUILD_DIR)/release"
|
@echo archive in "$(BUILD_DIR)/release"
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Other Targets
|
|
||||||
#
|
|
||||||
translations:
|
|
||||||
$(BUILD_DIR)/bin/blender --background -noaudio --factory-startup --python po/update_msg.py
|
|
||||||
python3 po/update_pot.py
|
|
||||||
python3 po/update_po.py
|
|
||||||
python3 po/update_mo.py
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Tests
|
# Tests
|
||||||
#
|
#
|
||||||
@@ -238,9 +226,13 @@ check_sparse:
|
|||||||
# Simple version of ./doc/python_api/sphinx_doc_gen.sh with no PDF generation.
|
# Simple version of ./doc/python_api/sphinx_doc_gen.sh with no PDF generation.
|
||||||
doc_py:
|
doc_py:
|
||||||
$(BUILD_DIR)/bin/blender --background -noaudio --factory-startup --python doc/python_api/sphinx_doc_gen.py
|
$(BUILD_DIR)/bin/blender --background -noaudio --factory-startup --python doc/python_api/sphinx_doc_gen.py
|
||||||
cd doc/python_api ; sphinx-build -n -b html sphinx-in sphinx-out
|
cd doc/python_api ; sphinx-build -b html sphinx-in sphinx-out
|
||||||
@echo "docs written into: '$(BLENDER_DIR)/doc/python_api/sphinx-out/contents.html'"
|
@echo "docs written into: '$(BLENDER_DIR)/doc/python_api/sphinx-out/contents.html'"
|
||||||
|
|
||||||
|
doc_doxy:
|
||||||
|
cd doc/doxygen; doxygen
|
||||||
|
@echo "docs written into: '$(BLENDER_DIR)/doc/doxygen/html/index.html'"
|
||||||
|
|
||||||
doc_dna:
|
doc_dna:
|
||||||
$(BUILD_DIR)/bin/blender --background -noaudio --factory-startup --python doc/blender_file_format/BlendFileDnaExporter_25.py
|
$(BUILD_DIR)/bin/blender --background -noaudio --factory-startup --python doc/blender_file_format/BlendFileDnaExporter_25.py
|
||||||
@echo "docs written into: '$(BLENDER_DIR)/doc/blender_file_format/dna.html'"
|
@echo "docs written into: '$(BLENDER_DIR)/doc/blender_file_format/dna.html'"
|
||||||
|
|||||||
@@ -44,8 +44,19 @@ SET(PYTHON_LINKFLAGS "-Xlinker -export-dynamic" CACHE STRING "Linker flags for p
|
|||||||
MARK_AS_ADVANCED(PYTHON_LINKFLAGS)
|
MARK_AS_ADVANCED(PYTHON_LINKFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
# if the user passes these defines as args, we dont want to overwrite
|
||||||
|
SET(_IS_INC_DEF OFF)
|
||||||
|
SET(_IS_LIB_DEF OFF)
|
||||||
|
IF(DEFINED PYTHON_INCLUDE_DIR)
|
||||||
|
SET(_IS_INC_DEF ON)
|
||||||
|
ENDIF()
|
||||||
|
IF(DEFINED PYTHON_LIBRARY)
|
||||||
|
SET(_IS_LIB_DEF ON)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
|
||||||
# only search for the dirs if we havn't already
|
# only search for the dirs if we havn't already
|
||||||
IF((NOT DEFINED PYTHON_INCLUDE_DIR) OR (NOT DEFINED PYTHON_LIBRARY))
|
IF((NOT _IS_INC_DEF) OR (NOT _IS_LIB_DEF))
|
||||||
|
|
||||||
SET(_python_ABI_FLAGS
|
SET(_python_ABI_FLAGS
|
||||||
"m;mu;u; " # release
|
"m;mu;u; " # release
|
||||||
@@ -66,30 +77,38 @@ IF((NOT DEFINED PYTHON_INCLUDE_DIR) OR (NOT DEFINED PYTHON_LIBRARY))
|
|||||||
#ENDIF()
|
#ENDIF()
|
||||||
STRING(REPLACE " " "" _CURRENT_ABI_FLAGS ${_CURRENT_ABI_FLAGS})
|
STRING(REPLACE " " "" _CURRENT_ABI_FLAGS ${_CURRENT_ABI_FLAGS})
|
||||||
|
|
||||||
FIND_PATH(PYTHON_INCLUDE_DIR
|
IF(NOT DEFINED PYTHON_INCLUDE_DIR)
|
||||||
NAMES
|
FIND_PATH(PYTHON_INCLUDE_DIR
|
||||||
Python.h
|
NAMES
|
||||||
HINTS
|
Python.h
|
||||||
${_python_SEARCH_DIRS}
|
HINTS
|
||||||
PATH_SUFFIXES
|
${_python_SEARCH_DIRS}
|
||||||
include/python${PYTHON_VERSION}${_CURRENT_ABI_FLAGS}
|
PATH_SUFFIXES
|
||||||
)
|
include/python${PYTHON_VERSION}${_CURRENT_ABI_FLAGS}
|
||||||
|
)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
FIND_LIBRARY(PYTHON_LIBRARY
|
IF(NOT DEFINED PYTHON_LIBRARY)
|
||||||
NAMES
|
FIND_LIBRARY(PYTHON_LIBRARY
|
||||||
"python${PYTHON_VERSION}${_CURRENT_ABI_FLAGS}"
|
NAMES
|
||||||
HINTS
|
"python${PYTHON_VERSION}${_CURRENT_ABI_FLAGS}"
|
||||||
${_python_SEARCH_DIRS}
|
HINTS
|
||||||
PATH_SUFFIXES
|
${_python_SEARCH_DIRS}
|
||||||
lib64 lib
|
PATH_SUFFIXES
|
||||||
)
|
lib64 lib
|
||||||
|
)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
IF(PYTHON_LIBRARY AND PYTHON_INCLUDE_DIR)
|
IF(PYTHON_LIBRARY AND PYTHON_INCLUDE_DIR)
|
||||||
break()
|
break()
|
||||||
ELSE()
|
ELSE()
|
||||||
# ensure we dont find values from 2 different ABI versions
|
# ensure we dont find values from 2 different ABI versions
|
||||||
UNSET(PYTHON_INCLUDE_DIR CACHE)
|
IF(NOT _IS_INC_DEF)
|
||||||
UNSET(PYTHON_LIBRARY CACHE)
|
UNSET(PYTHON_INCLUDE_DIR CACHE)
|
||||||
|
ENDIF()
|
||||||
|
IF(NOT _IS_LIB_DEF)
|
||||||
|
UNSET(PYTHON_LIBRARY CACHE)
|
||||||
|
ENDIF()
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ENDFOREACH()
|
ENDFOREACH()
|
||||||
|
|
||||||
@@ -100,6 +119,9 @@ IF((NOT DEFINED PYTHON_INCLUDE_DIR) OR (NOT DEFINED PYTHON_LIBRARY))
|
|||||||
UNSET(_python_SEARCH_DIRS)
|
UNSET(_python_SEARCH_DIRS)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
UNSET(_IS_INC_DEF)
|
||||||
|
UNSET(_IS_LIB_DEF)
|
||||||
|
|
||||||
# handle the QUIETLY and REQUIRED arguments and SET PYTHONLIBSUNIX_FOUND to TRUE IF
|
# handle the QUIETLY and REQUIRED arguments and SET PYTHONLIBSUNIX_FOUND to TRUE IF
|
||||||
# all listed variables are TRUE
|
# all listed variables are TRUE
|
||||||
INCLUDE(FindPackageHandleStandardArgs)
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ IGNORE = (
|
|||||||
"source/blender/imbuf/intern/imbuf_cocoa.m",
|
"source/blender/imbuf/intern/imbuf_cocoa.m",
|
||||||
"extern/recastnavigation/Recast/Source/RecastLog.cpp",
|
"extern/recastnavigation/Recast/Source/RecastLog.cpp",
|
||||||
"extern/recastnavigation/Recast/Source/RecastTimer.cpp",
|
"extern/recastnavigation/Recast/Source/RecastTimer.cpp",
|
||||||
"entern/audaspace/SRC/AUD_SRCResampleFactory.cpp",
|
"intern/audaspace/SRC/AUD_SRCResampleFactory.cpp",
|
||||||
"entern/audaspace/SRC/AUD_SRCResampleReader.cpp",
|
"intern/audaspace/SRC/AUD_SRCResampleReader.cpp",
|
||||||
|
|
||||||
"extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h",
|
"extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h",
|
||||||
"extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h",
|
"extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h",
|
||||||
@@ -44,7 +44,7 @@ IGNORE = (
|
|||||||
"extern/eltopo/common/meshes/ObjLoader.hpp",
|
"extern/eltopo/common/meshes/ObjLoader.hpp",
|
||||||
"extern/eltopo/common/meshes/TriangleIndex.hpp",
|
"extern/eltopo/common/meshes/TriangleIndex.hpp",
|
||||||
"extern/eltopo/common/meshes/meshloader.h",
|
"extern/eltopo/common/meshes/meshloader.h",
|
||||||
"extern/eltopo/eltopo3d/broadphase_blenderbvh.h"
|
"extern/eltopo/eltopo3d/broadphase_blenderbvh.h",
|
||||||
"extern/recastnavigation/Recast/Include/RecastLog.h",
|
"extern/recastnavigation/Recast/Include/RecastLog.h",
|
||||||
"extern/recastnavigation/Recast/Include/RecastTimer.h",
|
"extern/recastnavigation/Recast/Include/RecastTimer.h",
|
||||||
"intern/audaspace/SRC/AUD_SRCResampleFactory.h",
|
"intern/audaspace/SRC/AUD_SRCResampleFactory.h",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ from project_info import (SIMPLE_PROJECTFILE,
|
|||||||
is_py,
|
is_py,
|
||||||
cmake_advanced_info,
|
cmake_advanced_info,
|
||||||
cmake_compiler_defines,
|
cmake_compiler_defines,
|
||||||
|
project_name_get,
|
||||||
)
|
)
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -59,7 +60,8 @@ def create_qtc_project_main():
|
|||||||
f.write("\n".join(files_rel))
|
f.write("\n".join(files_rel))
|
||||||
|
|
||||||
f = open(os.path.join(PROJECT_DIR, "%s.includes" % PROJECT_NAME), 'w')
|
f = open(os.path.join(PROJECT_DIR, "%s.includes" % PROJECT_NAME), 'w')
|
||||||
f.write("\n".join(sorted(list(set(os.path.dirname(f) for f in files_rel if is_c_header(f))))))
|
f.write("\n".join(sorted(list(set(os.path.dirname(f)
|
||||||
|
for f in files_rel if is_c_header(f))))))
|
||||||
|
|
||||||
qtc_prj = os.path.join(PROJECT_DIR, "%s.creator" % PROJECT_NAME)
|
qtc_prj = os.path.join(PROJECT_DIR, "%s.creator" % PROJECT_NAME)
|
||||||
f = open(qtc_prj, 'w')
|
f = open(qtc_prj, 'w')
|
||||||
@@ -73,10 +75,16 @@ def create_qtc_project_main():
|
|||||||
includes, defines = cmake_advanced_info()
|
includes, defines = cmake_advanced_info()
|
||||||
|
|
||||||
# for some reason it doesnt give all internal includes
|
# for some reason it doesnt give all internal includes
|
||||||
includes = list(set(includes) | set(os.path.dirname(f) for f in files_rel if is_c_header(f)))
|
includes = list(set(includes) | set(os.path.dirname(f)
|
||||||
|
for f in files_rel if is_c_header(f)))
|
||||||
includes.sort()
|
includes.sort()
|
||||||
|
|
||||||
PROJECT_NAME = "Blender"
|
if 0:
|
||||||
|
PROJECT_NAME = "Blender"
|
||||||
|
else:
|
||||||
|
# be tricky, get the project name from SVN if we can!
|
||||||
|
PROJECT_NAME = project_name_get(SOURCE_DIR)
|
||||||
|
|
||||||
FILE_NAME = PROJECT_NAME.lower()
|
FILE_NAME = PROJECT_NAME.lower()
|
||||||
f = open(os.path.join(PROJECT_DIR, "%s.files" % FILE_NAME), 'w')
|
f = open(os.path.join(PROJECT_DIR, "%s.files" % FILE_NAME), 'w')
|
||||||
f.write("\n".join(files_rel))
|
f.write("\n".join(files_rel))
|
||||||
@@ -93,7 +101,7 @@ def create_qtc_project_main():
|
|||||||
f.write("// ADD PREDEFINED MACROS HERE!\n")
|
f.write("// ADD PREDEFINED MACROS HERE!\n")
|
||||||
defines_final = [("#define %s %s" % item) for item in defines]
|
defines_final = [("#define %s %s" % item) for item in defines]
|
||||||
if sys.platform != "win32":
|
if sys.platform != "win32":
|
||||||
defines_final += cmake_compiler_defines() # defines from the compiler
|
defines_final += cmake_compiler_defines()
|
||||||
f.write("\n".join(defines_final))
|
f.write("\n".join(defines_final))
|
||||||
|
|
||||||
print("Blender project file written to: %s" % qtc_prj)
|
print("Blender project file written to: %s" % qtc_prj)
|
||||||
@@ -106,7 +114,12 @@ def create_qtc_project_python():
|
|||||||
files_rel.sort()
|
files_rel.sort()
|
||||||
|
|
||||||
# --- qtcreator specific, simple format
|
# --- qtcreator specific, simple format
|
||||||
PROJECT_NAME = "Blender_Python"
|
if 0:
|
||||||
|
PROJECT_NAME = "Blender_Python"
|
||||||
|
else:
|
||||||
|
# be tricky, get the project name from SVN if we can!
|
||||||
|
PROJECT_NAME = project_name_get(SOURCE_DIR) + "_Python"
|
||||||
|
|
||||||
FILE_NAME = PROJECT_NAME.lower()
|
FILE_NAME = PROJECT_NAME.lower()
|
||||||
f = open(os.path.join(PROJECT_DIR, "%s.files" % FILE_NAME), 'w')
|
f = open(os.path.join(PROJECT_DIR, "%s.files" % FILE_NAME), 'w')
|
||||||
f.write("\n".join(files_rel))
|
f.write("\n".join(files_rel))
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ set(WITH_BULLET OFF CACHE FORCE BOOL)
|
|||||||
set(WITH_CODEC_FFMPEG OFF CACHE FORCE BOOL)
|
set(WITH_CODEC_FFMPEG OFF CACHE FORCE BOOL)
|
||||||
set(WITH_CODEC_SNDFILE OFF CACHE FORCE BOOL)
|
set(WITH_CODEC_SNDFILE OFF CACHE FORCE BOOL)
|
||||||
set(WITH_FFTW3 OFF CACHE FORCE BOOL)
|
set(WITH_FFTW3 OFF CACHE FORCE BOOL)
|
||||||
|
set(WITH_LIBMV OFF CACHE FORCE BOOL)
|
||||||
set(WITH_GAMEENGINE OFF CACHE FORCE BOOL)
|
set(WITH_GAMEENGINE OFF CACHE FORCE BOOL)
|
||||||
set(WITH_IK_ITASC OFF CACHE FORCE BOOL)
|
set(WITH_IK_ITASC OFF CACHE FORCE BOOL)
|
||||||
set(WITH_IMAGE_CINEON OFF CACHE FORCE BOOL)
|
set(WITH_IMAGE_CINEON OFF CACHE FORCE BOOL)
|
||||||
|
|||||||
@@ -165,6 +165,12 @@ macro(SETUP_LIBDIRS)
|
|||||||
if(WITH_IMAGE_TIFF)
|
if(WITH_IMAGE_TIFF)
|
||||||
link_directories(${TIFF_LIBPATH})
|
link_directories(${TIFF_LIBPATH})
|
||||||
endif()
|
endif()
|
||||||
|
if(WITH_BOOST)
|
||||||
|
link_directories(${BOOST_LIBPATH})
|
||||||
|
endif()
|
||||||
|
if(WITH_OPENIMAGEIO)
|
||||||
|
link_directories(${OPENIMAGEIO_LIBPATH})
|
||||||
|
endif()
|
||||||
if(WITH_IMAGE_OPENJPEG AND UNIX AND NOT APPLE)
|
if(WITH_IMAGE_OPENJPEG AND UNIX AND NOT APPLE)
|
||||||
link_directories(${OPENJPEG_LIBPATH})
|
link_directories(${OPENJPEG_LIBPATH})
|
||||||
endif()
|
endif()
|
||||||
@@ -259,6 +265,12 @@ macro(setup_liblinks
|
|||||||
if(WITH_IMAGE_TIFF)
|
if(WITH_IMAGE_TIFF)
|
||||||
target_link_libraries(${target} ${TIFF_LIBRARY})
|
target_link_libraries(${target} ${TIFF_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
|
if(WITH_OPENIMAGEIO)
|
||||||
|
target_link_libraries(${target} ${OPENIMAGEIO_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
if(WITH_BOOST)
|
||||||
|
target_link_libraries(${target} ${BOOST_LIBRARIES})
|
||||||
|
endif()
|
||||||
if(WITH_IMAGE_OPENEXR)
|
if(WITH_IMAGE_OPENEXR)
|
||||||
if(WIN32 AND NOT UNIX)
|
if(WIN32 AND NOT UNIX)
|
||||||
file_list_suffix(OPENEXR_LIBRARIES_DEBUG "${OPENEXR_LIBRARIES}" "_d")
|
file_list_suffix(OPENEXR_LIBRARIES_DEBUG "${OPENEXR_LIBRARIES}" "_d")
|
||||||
@@ -413,8 +425,7 @@ macro(remove_strict_flags)
|
|||||||
remove_cc_flag("-Werror")
|
remove_cc_flag("-Werror")
|
||||||
|
|
||||||
# negate flags implied by '-Wall'
|
# negate flags implied by '-Wall'
|
||||||
add_cc_flag("-Wno-unused-parameter")
|
add_cc_flag("${CC_REMOVE_STRICT_FLAGS}")
|
||||||
add_cc_flag("-Wno-unused-but-set-variable")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
@@ -619,3 +630,38 @@ macro(blender_project_hack_post)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
# pair of macros to allow libraries to be specify files to install, but to
|
||||||
|
# only install them at the end so the directories don't get cleared with
|
||||||
|
# the files in them. used by cycles to install addon.
|
||||||
|
macro(delayed_install
|
||||||
|
base
|
||||||
|
files
|
||||||
|
destination)
|
||||||
|
|
||||||
|
foreach(f ${files})
|
||||||
|
set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_FILES ${base}/${f})
|
||||||
|
set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_DESTINATIONS ${destination})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# note this is a function instead of a macro so that ${BUILD_TYPE} in targetdir
|
||||||
|
# does not get expanded in calling but is preserved
|
||||||
|
function(delayed_do_install
|
||||||
|
targetdir)
|
||||||
|
|
||||||
|
get_property(files GLOBAL PROPERTY DELAYED_INSTALL_FILES)
|
||||||
|
get_property(destinations GLOBAL PROPERTY DELAYED_INSTALL_DESTINATIONS)
|
||||||
|
|
||||||
|
if(files)
|
||||||
|
list(LENGTH files n)
|
||||||
|
math(EXPR n "${n}-1")
|
||||||
|
|
||||||
|
foreach(i RANGE ${n})
|
||||||
|
list(GET files ${i} f)
|
||||||
|
list(GET destinations ${i} d)
|
||||||
|
install(FILES ${f} DESTINATION ${targetdir}/${d})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ __all__ = (
|
|||||||
"is_py",
|
"is_py",
|
||||||
"cmake_advanced_info",
|
"cmake_advanced_info",
|
||||||
"cmake_compiler_defines",
|
"cmake_compiler_defines",
|
||||||
|
"project_name_get"
|
||||||
)
|
)
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
@@ -215,3 +216,21 @@ def cmake_compiler_defines():
|
|||||||
os.remove(temp_c)
|
os.remove(temp_c)
|
||||||
os.remove(temp_def)
|
os.remove(temp_def)
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def project_name_get(path, fallback="Blender", prefix="Blender_"):
|
||||||
|
if not os.path.isdir(os.path.join(path, ".svn")):
|
||||||
|
return fallback
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
info = subprocess.Popen(["svn", "info", path],
|
||||||
|
stdout=subprocess.PIPE).communicate()[0].decode()
|
||||||
|
|
||||||
|
for l in info.split("\n"):
|
||||||
|
l = l.strip()
|
||||||
|
if l.startswith("URL"):
|
||||||
|
# https://svn.blender.org/svnroot/bf-blender/branches/bmesh/blender
|
||||||
|
# --> bmesh
|
||||||
|
if "/branches/" in l:
|
||||||
|
return prefix + l.rsplit("/branches/", 1)[-1].split("/", 1)[0]
|
||||||
|
return fallback
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ else:
|
|||||||
|
|
||||||
# some flags shuffling for different OS versions
|
# some flags shuffling for different OS versions
|
||||||
if MAC_MIN_VERS == '10.3':
|
if MAC_MIN_VERS == '10.3':
|
||||||
CCFLAGS = ['-fuse-cxa-atexit'] + CFLAGS
|
CCFLAGS = ['-fuse-cxa-atexit'] + CCFLAGS
|
||||||
PLATFORM_LINKFLAGS = ['-fuse-cxa-atexit'] + PLATFORM_LINKFLAGS
|
PLATFORM_LINKFLAGS = ['-fuse-cxa-atexit'] + PLATFORM_LINKFLAGS
|
||||||
LLIBS.append('crt3.o')
|
LLIBS.append('crt3.o')
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,20 @@ WITH_BF_3DMOUSE = True
|
|||||||
|
|
||||||
WITH_BF_OPENMP = True
|
WITH_BF_OPENMP = True
|
||||||
|
|
||||||
|
'''
|
||||||
|
WITH_BF_OIIO = True
|
||||||
|
BF_OIIO = LIBDIR + '/openimageio'
|
||||||
|
BF_OIIO_INC = '${BF_OIIO}/include'
|
||||||
|
BF_OIIO_LIB = 'OpenImageIO'
|
||||||
|
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
||||||
|
|
||||||
|
WITH_BF_BOOST = True
|
||||||
|
BF_BOOST = LIBDIR + '/boost'
|
||||||
|
BF_BOOST_INC = '${BF_BOOST}/include'
|
||||||
|
BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_46_1 libboost_filesystem-vc90-mt-s-1_46_1 libboost_regex-vc90-mt-s-1_46_1 libboost_system-vc90-mt-s-1_46_1 libboost_thread-vc90-mt-s-1_46_1'
|
||||||
|
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
||||||
|
'''
|
||||||
|
|
||||||
#Ray trace optimization
|
#Ray trace optimization
|
||||||
WITH_BF_RAYOPTIMIZATION = True
|
WITH_BF_RAYOPTIMIZATION = True
|
||||||
BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE']
|
BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE']
|
||||||
|
|||||||
@@ -153,6 +153,20 @@ WITH_BF_3DMOUSE = True
|
|||||||
|
|
||||||
WITH_BF_OPENMP = True
|
WITH_BF_OPENMP = True
|
||||||
|
|
||||||
|
'''
|
||||||
|
WITH_BF_OIIO = True
|
||||||
|
BF_OIIO = LIBDIR + '/openimageio'
|
||||||
|
BF_OIIO_INC = '${BF_OIIO}/include'
|
||||||
|
BF_OIIO_LIB = 'OpenImageIO'
|
||||||
|
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
||||||
|
|
||||||
|
WITH_BF_BOOST = True
|
||||||
|
BF_BOOST = LIBDIR + '/boost'
|
||||||
|
BF_BOOST_INC = '${BF_BOOST}/include'
|
||||||
|
BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_45 libboost_filesystem-vc90-mt-s-1_45 libboost_regex-vc90-mt-s-1_45 libboost_system-vc90-mt-s-1_45 libboost_thread-vc90-mt-s-1_45'
|
||||||
|
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
||||||
|
'''
|
||||||
|
|
||||||
#Ray trace optimization
|
#Ray trace optimization
|
||||||
WITH_BF_RAYOPTIMIZATION = True
|
WITH_BF_RAYOPTIMIZATION = True
|
||||||
BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE','/arch:SSE2']
|
BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE','/arch:SSE2']
|
||||||
|
|||||||
@@ -192,6 +192,11 @@ def setup_staticlibs(lenv):
|
|||||||
if lenv['WITH_BF_OPENMP']:
|
if lenv['WITH_BF_OPENMP']:
|
||||||
if lenv['OURPLATFORM'] == 'linuxcross':
|
if lenv['OURPLATFORM'] == 'linuxcross':
|
||||||
libincs += Split(lenv['BF_OPENMP_LIBPATH'])
|
libincs += Split(lenv['BF_OPENMP_LIBPATH'])
|
||||||
|
|
||||||
|
if lenv['WITH_BF_OIIO']:
|
||||||
|
libincs += Split(lenv['BF_OIIO_LIBPATH'])
|
||||||
|
if lenv['WITH_BF_BOOST']:
|
||||||
|
libincs += Split(lenv['BF_BOOST_LIBPATH'])
|
||||||
|
|
||||||
# setting this last so any overriding of manually libs could be handled
|
# setting this last so any overriding of manually libs could be handled
|
||||||
if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
|
if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
|
||||||
@@ -275,6 +280,11 @@ def setup_syslibs(lenv):
|
|||||||
if not lenv['WITH_BF_STATIC3DMOUSE']:
|
if not lenv['WITH_BF_STATIC3DMOUSE']:
|
||||||
syslibs += Split(lenv['BF_3DMOUSE_LIB'])
|
syslibs += Split(lenv['BF_3DMOUSE_LIB'])
|
||||||
|
|
||||||
|
if lenv['WITH_BF_OIIO']:
|
||||||
|
syslibs += Split(lenv['BF_OIIO_LIB'])
|
||||||
|
if lenv['WITH_BF_BOOST']:
|
||||||
|
syslibs += Split(lenv['BF_BOOST_LIB'])
|
||||||
|
|
||||||
syslibs += lenv['LLIBS']
|
syslibs += lenv['LLIBS']
|
||||||
|
|
||||||
return syslibs
|
return syslibs
|
||||||
@@ -319,6 +329,10 @@ def creator(env):
|
|||||||
if env['WITH_BF_SDL']:
|
if env['WITH_BF_SDL']:
|
||||||
defs.append('WITH_SDL')
|
defs.append('WITH_SDL')
|
||||||
|
|
||||||
|
if env['WITH_BF_LIBMV']:
|
||||||
|
incs.append('#/extern/libmv')
|
||||||
|
defs.append('WITH_LIBMV')
|
||||||
|
|
||||||
if env['WITH_BF_PYTHON']:
|
if env['WITH_BF_PYTHON']:
|
||||||
incs.append('#/source/blender/python')
|
incs.append('#/source/blender/python')
|
||||||
defs.append('WITH_PYTHON')
|
defs.append('WITH_PYTHON')
|
||||||
|
|||||||
@@ -116,7 +116,9 @@ def validate_arguments(args, bc):
|
|||||||
'WITH_BF_INTERNATIONAL',
|
'WITH_BF_INTERNATIONAL',
|
||||||
'BF_GETTEXT', 'BF_GETTEXT_INC', 'BF_GETTEXT_LIB', 'WITH_BF_GETTEXT_STATIC', 'BF_GETTEXT_LIB_STATIC', 'BF_GETTEXT_LIBPATH',
|
'BF_GETTEXT', 'BF_GETTEXT_INC', 'BF_GETTEXT_LIB', 'WITH_BF_GETTEXT_STATIC', 'BF_GETTEXT_LIB_STATIC', 'BF_GETTEXT_LIBPATH',
|
||||||
'WITH_BF_ICONV', 'BF_ICONV', 'BF_ICONV_INC', 'BF_ICONV_LIB', 'BF_ICONV_LIBPATH',
|
'WITH_BF_ICONV', 'BF_ICONV', 'BF_ICONV_INC', 'BF_ICONV_LIB', 'BF_ICONV_LIBPATH',
|
||||||
'WITH_BF_GAMEENGINE', 'WITH_BF_BULLET', 'WITH_BF_ELTOPO', 'BF_BULLET', 'BF_BULLET_INC', 'BF_BULLET_LIB',
|
'WITH_BF_GAMEENGINE',
|
||||||
|
'WITH_BF_BULLET', 'BF_BULLET', 'BF_BULLET_INC', 'BF_BULLET_LIB',
|
||||||
|
'WITH_BF_ELTOPO',
|
||||||
'BF_WINTAB', 'BF_WINTAB_INC',
|
'BF_WINTAB', 'BF_WINTAB_INC',
|
||||||
'BF_FREETYPE', 'BF_FREETYPE_INC', 'BF_FREETYPE_LIB', 'BF_FREETYPE_LIBPATH', 'BF_FREETYPE_LIB_STATIC', 'WITH_BF_FREETYPE_STATIC',
|
'BF_FREETYPE', 'BF_FREETYPE_INC', 'BF_FREETYPE_LIB', 'BF_FREETYPE_LIBPATH', 'BF_FREETYPE_LIB_STATIC', 'WITH_BF_FREETYPE_STATIC',
|
||||||
'WITH_BF_QUICKTIME', 'BF_QUICKTIME', 'BF_QUICKTIME_INC', 'BF_QUICKTIME_LIB', 'BF_QUICKTIME_LIBPATH',
|
'WITH_BF_QUICKTIME', 'BF_QUICKTIME', 'BF_QUICKTIME_INC', 'BF_QUICKTIME_LIB', 'BF_QUICKTIME_LIBPATH',
|
||||||
@@ -133,12 +135,10 @@ def validate_arguments(args, bc):
|
|||||||
'WITHOUT_BF_INSTALL',
|
'WITHOUT_BF_INSTALL',
|
||||||
'WITHOUT_BF_PYTHON_INSTALL',
|
'WITHOUT_BF_PYTHON_INSTALL',
|
||||||
'WITHOUT_BF_OVERWRITE_INSTALL',
|
'WITHOUT_BF_OVERWRITE_INSTALL',
|
||||||
'WITH_BF_OPENMP',
|
'WITH_BF_OPENMP', 'BF_OPENMP', 'BF_OPENMP_LIBPATH',
|
||||||
'BF_OPENMP',
|
|
||||||
'BF_OPENMP_INC',
|
|
||||||
'BF_OPENMP_LIBPATH',
|
|
||||||
'WITH_GHOST_COCOA',
|
'WITH_GHOST_COCOA',
|
||||||
'WITH_GHOST_SDL',
|
'WITH_GHOST_SDL',
|
||||||
|
'BF_GHOST_DEBUG',
|
||||||
'USE_QTKIT',
|
'USE_QTKIT',
|
||||||
'BF_FANCY', 'BF_QUIET', 'BF_LINE_OVERWRITE',
|
'BF_FANCY', 'BF_QUIET', 'BF_LINE_OVERWRITE',
|
||||||
'BF_X264_CONFIG',
|
'BF_X264_CONFIG',
|
||||||
@@ -147,7 +147,6 @@ def validate_arguments(args, bc):
|
|||||||
'BF_NUMJOBS',
|
'BF_NUMJOBS',
|
||||||
'BF_MSVS',
|
'BF_MSVS',
|
||||||
'BF_VERSION',
|
'BF_VERSION',
|
||||||
'BF_GHOST_DEBUG',
|
|
||||||
'WITH_BF_RAYOPTIMIZATION',
|
'WITH_BF_RAYOPTIMIZATION',
|
||||||
'BF_RAYOPTIMIZATION_SSE_FLAGS',
|
'BF_RAYOPTIMIZATION_SSE_FLAGS',
|
||||||
'WITH_BF_FLUID',
|
'WITH_BF_FLUID',
|
||||||
@@ -155,7 +154,10 @@ def validate_arguments(args, bc):
|
|||||||
'WITH_BF_BOOLEAN',
|
'WITH_BF_BOOLEAN',
|
||||||
'WITH_BF_CXX_GUARDEDALLOC',
|
'WITH_BF_CXX_GUARDEDALLOC',
|
||||||
'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
|
'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
|
||||||
'BUILDBOT_BRANCH', 'WITH_BF_3DMOUSE', 'WITH_BF_STATIC3DMOUSE', 'BF_3DMOUSE', 'BF_3DMOUSE_INC', 'BF_3DMOUSE_LIB', 'BF_3DMOUSE_LIBPATH', 'BF_3DMOUSE_LIB_STATIC'
|
'BUILDBOT_BRANCH',
|
||||||
|
'WITH_BF_3DMOUSE', 'WITH_BF_STATIC3DMOUSE', 'BF_3DMOUSE', 'BF_3DMOUSE_INC', 'BF_3DMOUSE_LIB', 'BF_3DMOUSE_LIBPATH', 'BF_3DMOUSE_LIB_STATIC',
|
||||||
|
'WITH_BF_OIIO', 'BF_OIIO', 'BF_OIIO_INC', 'BF_OIIO_LIB', 'BF_OIIO_LIBPATH',
|
||||||
|
'WITH_BF_BOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIBPATH'
|
||||||
]
|
]
|
||||||
|
|
||||||
# Have options here that scons expects to be lists
|
# Have options here that scons expects to be lists
|
||||||
@@ -239,9 +241,9 @@ def read_opts(env, cfg, args):
|
|||||||
('LCGDIR', 'location of cvs lib dir'),
|
('LCGDIR', 'location of cvs lib dir'),
|
||||||
(BoolVariable('WITH_BF_PYTHON', 'Compile with python', True)),
|
(BoolVariable('WITH_BF_PYTHON', 'Compile with python', True)),
|
||||||
(BoolVariable('WITH_BF_PYTHON_SAFETY', 'Internal API error checking to track invalid data to prevent crash on access (at the expense of some effeciency)', False)),
|
(BoolVariable('WITH_BF_PYTHON_SAFETY', 'Internal API error checking to track invalid data to prevent crash on access (at the expense of some effeciency)', False)),
|
||||||
('BF_PYTHON', 'base path for python', ''),
|
('BF_PYTHON', 'Base path for python', ''),
|
||||||
('BF_PYTHON_VERSION', 'Python version to use', ''),
|
('BF_PYTHON_VERSION', 'Python version to use', ''),
|
||||||
('BF_PYTHON_INC', 'include path for Python headers', ''),
|
('BF_PYTHON_INC', 'Include path for Python headers', ''),
|
||||||
('BF_PYTHON_BINARY', 'Path to the Python interpreter', ''),
|
('BF_PYTHON_BINARY', 'Path to the Python interpreter', ''),
|
||||||
('BF_PYTHON_LIB', 'Python library', ''),
|
('BF_PYTHON_LIB', 'Python library', ''),
|
||||||
('BF_PYTHON_DLL', 'Python dll - used on Windows only', ''),
|
('BF_PYTHON_DLL', 'Python dll - used on Windows only', ''),
|
||||||
@@ -257,8 +259,8 @@ def read_opts(env, cfg, args):
|
|||||||
(BoolVariable('WITH_BF_BOOLEAN', 'Build with boolean modifier', True)),
|
(BoolVariable('WITH_BF_BOOLEAN', 'Build with boolean modifier', True)),
|
||||||
('BF_PROFILE_FLAGS', 'Profiling compiler flags', ''),
|
('BF_PROFILE_FLAGS', 'Profiling compiler flags', ''),
|
||||||
(BoolVariable('WITH_BF_OPENAL', 'Use OpenAL if true', False)),
|
(BoolVariable('WITH_BF_OPENAL', 'Use OpenAL if true', False)),
|
||||||
('BF_OPENAL', 'base path for OpenAL', ''),
|
('BF_OPENAL', 'Base path for OpenAL', ''),
|
||||||
('BF_OPENAL_INC', 'include path for python headers', ''),
|
('BF_OPENAL_INC', 'Include path for python headers', ''),
|
||||||
('BF_OPENAL_LIB', 'Path to OpenAL library', ''),
|
('BF_OPENAL_LIB', 'Path to OpenAL library', ''),
|
||||||
('BF_OPENAL_LIB_STATIC', 'Path to OpenAL static library', ''),
|
('BF_OPENAL_LIB_STATIC', 'Path to OpenAL static library', ''),
|
||||||
('BF_OPENAL_LIBPATH', 'Path to OpenAL library', ''),
|
('BF_OPENAL_LIBPATH', 'Path to OpenAL library', ''),
|
||||||
@@ -513,6 +515,8 @@ def read_opts(env, cfg, args):
|
|||||||
(BoolVariable('WITH_BF_LZO', 'Enable fast LZO pointcache compression', True)),
|
(BoolVariable('WITH_BF_LZO', 'Enable fast LZO pointcache compression', True)),
|
||||||
(BoolVariable('WITH_BF_LZMA', 'Enable best LZMA 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_X264_CONFIG', 'configuration flags for x264', ''),
|
||||||
('BF_XVIDCORE_CONFIG', 'configuration flags for xvidcore', ''),
|
('BF_XVIDCORE_CONFIG', 'configuration flags for xvidcore', ''),
|
||||||
# (BoolVariable('WITH_BF_DOCS', 'Generate API documentation', False)),
|
# (BoolVariable('WITH_BF_DOCS', 'Generate API documentation', False)),
|
||||||
@@ -532,6 +536,16 @@ def read_opts(env, cfg, args):
|
|||||||
(BoolVariable('WITH_BF_CXX_GUARDEDALLOC', 'Enable GuardedAlloc for C++ memory allocation tracking.', False)),
|
(BoolVariable('WITH_BF_CXX_GUARDEDALLOC', 'Enable GuardedAlloc for C++ memory allocation tracking.', False)),
|
||||||
|
|
||||||
('BUILDBOT_BRANCH', 'Buildbot branch name', ''),
|
('BUILDBOT_BRANCH', 'Buildbot branch name', ''),
|
||||||
|
|
||||||
|
(BoolVariable('WITH_BF_OIIO', 'Build with OpenImageIO', False)),
|
||||||
|
('BF_OIIO_INC', 'OIIO include path', ''),
|
||||||
|
('BF_OIIO_LIB', 'OIIO library', ''),
|
||||||
|
('BF_OIIO_LIBPATH', 'OIIO library path', ''),
|
||||||
|
|
||||||
|
(BoolVariable('WITH_BF_BOOST', 'Build with Boost', False)),
|
||||||
|
('BF_BOOST_INC', 'Boost include path', ''),
|
||||||
|
('BF_BOOST_LIB', 'Boost library', ''),
|
||||||
|
('BF_BOOST_LIBPATH', 'Boost library path', '')
|
||||||
) # end of opts.AddOptions()
|
) # end of opts.AddOptions()
|
||||||
|
|
||||||
return localopts
|
return localopts
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ PROJECT_BRIEF =
|
|||||||
# exceed 55 pixels and the maximum width should not exceed 200 pixels.
|
# exceed 55 pixels and the maximum width should not exceed 200 pixels.
|
||||||
# Doxygen will copy the logo to the output directory.
|
# Doxygen will copy the logo to the output directory.
|
||||||
|
|
||||||
PROJECT_LOGO = ../../release/freedesktop/icons/48x48/blender.png
|
PROJECT_LOGO = ../../release/freedesktop/icons/48x48/apps/blender.png
|
||||||
|
|
||||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||||
# base path where the generated documentation will be put.
|
# base path where the generated documentation will be put.
|
||||||
@@ -193,7 +193,7 @@ SEPARATE_MEMBER_PAGES = NO
|
|||||||
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
|
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
|
||||||
# Doxygen uses this value to replace tabs by spaces in code fragments.
|
# Doxygen uses this value to replace tabs by spaces in code fragments.
|
||||||
|
|
||||||
TAB_SIZE = 8
|
TAB_SIZE = 4
|
||||||
|
|
||||||
# This tag can be used to specify a number of aliases that acts
|
# This tag can be used to specify a number of aliases that acts
|
||||||
# as commands in the documentation. An alias has the form "name=value".
|
# as commands in the documentation. An alias has the form "name=value".
|
||||||
|
|||||||
@@ -22,6 +22,10 @@
|
|||||||
* \ingroup python
|
* \ingroup python
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** \defgroup pymathutils Python Mathutils
|
||||||
|
* \ingroup python
|
||||||
|
*/
|
||||||
|
|
||||||
/** \defgroup pythonintern Python RNA and Operators
|
/** \defgroup pythonintern Python RNA and Operators
|
||||||
* \ingroup python
|
* \ingroup python
|
||||||
*/
|
*/
|
||||||
|
|||||||
20
doc/python_api/examples/bpy.app.handlers.1.py
Normal file
20
doc/python_api/examples/bpy.app.handlers.1.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
"""
|
||||||
|
Persistent Handler Example
|
||||||
|
++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
By default handlers are freed when loading new files, in some cases you may
|
||||||
|
wan't the handler stay running across multiple files (when the handler is
|
||||||
|
part of an addon for example).
|
||||||
|
|
||||||
|
For this the :data:`bpy.app.handlers.persistent` decorator needs to be used.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
from bpy.app.handlers import persistent
|
||||||
|
|
||||||
|
|
||||||
|
@persistent
|
||||||
|
def load_handler(dummy):
|
||||||
|
print("Load Handler:", bpy.data.filepath)
|
||||||
|
|
||||||
|
bpy.app.handlers.load_post.append(load_handler)
|
||||||
13
doc/python_api/examples/bpy.app.handlers.py
Normal file
13
doc/python_api/examples/bpy.app.handlers.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
"""
|
||||||
|
Basic Handler Example
|
||||||
|
+++++++++++++++++++++
|
||||||
|
This script shows the most simple example of adding a handler.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
|
||||||
|
def my_handler(scene):
|
||||||
|
print("Frame Change", scene.frame_current)
|
||||||
|
|
||||||
|
bpy.app.handlers.frame_change_pre.append(my_handler)
|
||||||
@@ -50,7 +50,7 @@ For PDF generation
|
|||||||
|
|
||||||
# Check we're running in blender
|
# Check we're running in blender
|
||||||
if __import__("sys").modules.get("bpy") is None:
|
if __import__("sys").modules.get("bpy") is None:
|
||||||
print("\nError, this script must run from inside blender2.5")
|
print("\nError, this script must run from inside blender")
|
||||||
print(script_help_msg)
|
print(script_help_msg)
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
@@ -70,13 +70,14 @@ else:
|
|||||||
# for testing so doc-builds dont take so long.
|
# for testing so doc-builds dont take so long.
|
||||||
EXCLUDE_MODULES = (
|
EXCLUDE_MODULES = (
|
||||||
"bpy.context",
|
"bpy.context",
|
||||||
"bpy.app",
|
#"bpy.app",
|
||||||
|
#"bpy.app.handlers",
|
||||||
"bpy.path",
|
"bpy.path",
|
||||||
"bpy.data",
|
"bpy.data",
|
||||||
"bpy.props",
|
"bpy.props",
|
||||||
"bpy.utils",
|
"bpy.utils",
|
||||||
"bpy.context",
|
"bpy.context",
|
||||||
# "bpy.types", # supports filtering
|
"bpy.types", # supports filtering
|
||||||
"bpy.ops", # supports filtering
|
"bpy.ops", # supports filtering
|
||||||
"bpy_extras",
|
"bpy_extras",
|
||||||
"bge",
|
"bge",
|
||||||
@@ -110,8 +111,18 @@ INFO_DOCS = (
|
|||||||
("info_gotcha.rst", "Gotcha's: some of the problems you may come up against when writing scripts"),
|
("info_gotcha.rst", "Gotcha's: some of the problems you may come up against when writing scripts"),
|
||||||
)
|
)
|
||||||
|
|
||||||
# import rpdb2; rpdb2.start_embedded_debugger('test')
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# configure compile time options
|
||||||
|
|
||||||
|
try:
|
||||||
|
__import__("aud")
|
||||||
|
except ImportError:
|
||||||
|
print("Warning: Built without 'aud' module, docs incomplete...")
|
||||||
|
EXCLUDE_MODULES = EXCLUDE_MODULES + ("aud", )
|
||||||
|
|
||||||
|
|
||||||
|
# import rpdb2; rpdb2.start_embedded_debugger('test')
|
||||||
import os
|
import os
|
||||||
import inspect
|
import inspect
|
||||||
import bpy
|
import bpy
|
||||||
@@ -122,6 +133,7 @@ ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
|
|||||||
MethodDescriptorType = type(dict.get)
|
MethodDescriptorType = type(dict.get)
|
||||||
GetSetDescriptorType = type(int.real)
|
GetSetDescriptorType = type(int.real)
|
||||||
StaticMethodType = type(staticmethod(lambda: None))
|
StaticMethodType = type(staticmethod(lambda: None))
|
||||||
|
from types import MemberDescriptorType
|
||||||
|
|
||||||
EXAMPLE_SET = set()
|
EXAMPLE_SET = set()
|
||||||
EXAMPLE_SET_USED = set()
|
EXAMPLE_SET_USED = set()
|
||||||
@@ -136,6 +148,10 @@ else:
|
|||||||
_BPY_PROP_COLLECTION_ID = "collection"
|
_BPY_PROP_COLLECTION_ID = "collection"
|
||||||
|
|
||||||
|
|
||||||
|
def is_struct_seq(value):
|
||||||
|
return isinstance(value, tuple) and type(tuple) != tuple and hasattr(value, "n_fields")
|
||||||
|
|
||||||
|
|
||||||
def undocumented_message(module_name, type_name, identifier):
|
def undocumented_message(module_name, type_name, identifier):
|
||||||
if str(type_name).startswith('<module'):
|
if str(type_name).startswith('<module'):
|
||||||
preloadtitle = '%s.%s' % (module_name, identifier)
|
preloadtitle = '%s.%s' % (module_name, identifier)
|
||||||
@@ -307,6 +323,10 @@ def py_descr2sphinx(ident, fw, descr, module_name, type_name, identifier):
|
|||||||
fw(ident + ".. attribute:: %s\n\n" % identifier)
|
fw(ident + ".. attribute:: %s\n\n" % identifier)
|
||||||
write_indented_lines(ident + " ", fw, doc, False)
|
write_indented_lines(ident + " ", fw, doc, False)
|
||||||
fw("\n")
|
fw("\n")
|
||||||
|
elif type(descr) == MemberDescriptorType: # same as above but use 'data'
|
||||||
|
fw(ident + ".. data:: %s\n\n" % identifier)
|
||||||
|
write_indented_lines(ident + " ", fw, doc, False)
|
||||||
|
fw("\n")
|
||||||
elif type(descr) in (MethodDescriptorType, ClassMethodDescriptorType):
|
elif type(descr) in (MethodDescriptorType, ClassMethodDescriptorType):
|
||||||
write_indented_lines(ident, fw, doc, False)
|
write_indented_lines(ident, fw, doc, False)
|
||||||
fw("\n")
|
fw("\n")
|
||||||
@@ -413,59 +433,90 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
|
|||||||
if key.startswith("__"):
|
if key.startswith("__"):
|
||||||
continue
|
continue
|
||||||
# naughty, we also add getset's into PyStructs, this is not typical py but also not incorrect.
|
# naughty, we also add getset's into PyStructs, this is not typical py but also not incorrect.
|
||||||
if type(descr) == types.GetSetDescriptorType: # 'bpy_app_type' name is only used for examples and messages
|
|
||||||
py_descr2sphinx("", fw, descr, module_name, "bpy_app_type", key)
|
# type_name is only used for examples and messages
|
||||||
|
type_name = str(type(module)).strip("<>").split(" ", 1)[-1][1:-1] # "<class 'bpy.app.handlers'>" --> bpy.app.handlers
|
||||||
|
if type(descr) == types.GetSetDescriptorType:
|
||||||
|
py_descr2sphinx("", fw, descr, module_name, type_name, key)
|
||||||
attribute_set.add(key)
|
attribute_set.add(key)
|
||||||
|
descr_sorted = []
|
||||||
for key, descr in sorted(type(module).__dict__.items()):
|
for key, descr in sorted(type(module).__dict__.items()):
|
||||||
if key.startswith("__"):
|
if key.startswith("__"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if type(descr) == types.MemberDescriptorType:
|
if type(descr) == MemberDescriptorType:
|
||||||
if descr.__doc__:
|
if descr.__doc__:
|
||||||
fw(".. data:: %s\n\n" % key)
|
value = getattr(module, key, None)
|
||||||
write_indented_lines(" ", fw, descr.__doc__, False)
|
|
||||||
fw("\n")
|
|
||||||
attribute_set.add(key)
|
|
||||||
|
|
||||||
del key, descr
|
value_type = type(value)
|
||||||
|
descr_sorted.append((key, descr, value, type(value)))
|
||||||
|
# sort by the valye type
|
||||||
|
descr_sorted.sort(key=lambda descr_data: str(descr_data[3]))
|
||||||
|
for key, descr, value, value_type in descr_sorted:
|
||||||
|
|
||||||
|
# must be documented as a submodule
|
||||||
|
if is_struct_seq(value):
|
||||||
|
continue
|
||||||
|
|
||||||
|
type_name = value_type.__name__
|
||||||
|
py_descr2sphinx("", fw, descr, module_name, type_name, key)
|
||||||
|
|
||||||
|
attribute_set.add(key)
|
||||||
|
|
||||||
|
del key, descr, descr_sorted
|
||||||
|
|
||||||
classes = []
|
classes = []
|
||||||
submodules = []
|
submodules = []
|
||||||
|
|
||||||
|
# use this list so we can sort by type
|
||||||
|
module_dir_value_type = []
|
||||||
|
|
||||||
for attribute in module_dir:
|
for attribute in module_dir:
|
||||||
if not attribute.startswith("_"):
|
if attribute.startswith("_"):
|
||||||
if attribute in attribute_set:
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
if attribute.startswith("n_"): # annoying exception, needed for bpy.app
|
if attribute in attribute_set:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
value = getattr(module, attribute)
|
if attribute.startswith("n_"): # annoying exception, needed for bpy.app
|
||||||
|
continue
|
||||||
|
|
||||||
value_type = type(value)
|
# workaround for bpy.app documenting .index() and .count()
|
||||||
|
if isinstance(module, tuple) and hasattr(tuple, attribute):
|
||||||
|
continue
|
||||||
|
|
||||||
if value_type == types.FunctionType:
|
value = getattr(module, attribute)
|
||||||
pyfunc2sphinx("", fw, attribute, value, is_class=False)
|
|
||||||
elif value_type in (types.BuiltinMethodType, types.BuiltinFunctionType): # both the same at the moment but to be future proof
|
|
||||||
# note: can't get args from these, so dump the string as is
|
|
||||||
# this means any module used like this must have fully formatted docstrings.
|
|
||||||
py_c_func2sphinx("", fw, module_name, None, attribute, value, is_class=False)
|
|
||||||
elif value_type == type:
|
|
||||||
classes.append((attribute, value))
|
|
||||||
elif issubclass(value_type, types.ModuleType):
|
|
||||||
submodules.append((attribute, value))
|
|
||||||
elif value_type in (bool, int, float, str, tuple):
|
|
||||||
# constant, not much fun we can do here except to list it.
|
|
||||||
# TODO, figure out some way to document these!
|
|
||||||
fw(".. data:: %s\n\n" % attribute)
|
|
||||||
write_indented_lines(" ", fw, "constant value %s" % repr(value), False)
|
|
||||||
fw("\n")
|
|
||||||
else:
|
|
||||||
print("\tnot documenting %s.%s of %r type" % (module_name, attribute, value_type.__name__))
|
|
||||||
continue
|
|
||||||
|
|
||||||
attribute_set.add(attribute)
|
module_dir_value_type.append((attribute, value, type(value)))
|
||||||
# TODO, more types...
|
|
||||||
|
# sort by str of each type
|
||||||
|
# this way lists, functions etc are grouped.
|
||||||
|
module_dir_value_type.sort(key=lambda triple: str(triple[2]))
|
||||||
|
|
||||||
|
for attribute, value, value_type in module_dir_value_type:
|
||||||
|
if value_type == types.FunctionType:
|
||||||
|
pyfunc2sphinx("", fw, attribute, value, is_class=False)
|
||||||
|
elif value_type in (types.BuiltinMethodType, types.BuiltinFunctionType): # both the same at the moment but to be future proof
|
||||||
|
# note: can't get args from these, so dump the string as is
|
||||||
|
# this means any module used like this must have fully formatted docstrings.
|
||||||
|
py_c_func2sphinx("", fw, module_name, None, attribute, value, is_class=False)
|
||||||
|
elif value_type == type:
|
||||||
|
classes.append((attribute, value))
|
||||||
|
elif issubclass(value_type, types.ModuleType):
|
||||||
|
submodules.append((attribute, value))
|
||||||
|
elif value_type in (bool, int, float, str, tuple):
|
||||||
|
# constant, not much fun we can do here except to list it.
|
||||||
|
# TODO, figure out some way to document these!
|
||||||
|
#fw(".. data:: %s\n\n" % attribute)
|
||||||
|
write_indented_lines(" ", fw, "constant value %s" % repr(value), False)
|
||||||
|
fw("\n")
|
||||||
|
else:
|
||||||
|
print("\tnot documenting %s.%s of %r type" % (module_name, attribute, value_type.__name__))
|
||||||
|
continue
|
||||||
|
|
||||||
|
attribute_set.add(attribute)
|
||||||
|
# TODO, more types...
|
||||||
|
del module_dir_value_type
|
||||||
|
|
||||||
# TODO, bpy_extras does this already, mathutils not.
|
# TODO, bpy_extras does this already, mathutils not.
|
||||||
"""
|
"""
|
||||||
@@ -1111,6 +1162,8 @@ def rna2sphinx(BASEPATH):
|
|||||||
fw(" bpy.path.rst\n\n")
|
fw(" bpy.path.rst\n\n")
|
||||||
if "bpy.app" not in EXCLUDE_MODULES:
|
if "bpy.app" not in EXCLUDE_MODULES:
|
||||||
fw(" bpy.app.rst\n\n")
|
fw(" bpy.app.rst\n\n")
|
||||||
|
if "bpy.app.handlers" not in EXCLUDE_MODULES:
|
||||||
|
fw(" bpy.app.handlers.rst\n\n")
|
||||||
|
|
||||||
# C modules
|
# C modules
|
||||||
if "bpy.props" not in EXCLUDE_MODULES:
|
if "bpy.props" not in EXCLUDE_MODULES:
|
||||||
@@ -1252,6 +1305,10 @@ def rna2sphinx(BASEPATH):
|
|||||||
from bpy import app as module
|
from bpy import app as module
|
||||||
pymodule2sphinx(BASEPATH, "bpy.app", module, "Application Data")
|
pymodule2sphinx(BASEPATH, "bpy.app", module, "Application Data")
|
||||||
|
|
||||||
|
if "bpy.app.handlers" not in EXCLUDE_MODULES:
|
||||||
|
from bpy.app import handlers as module
|
||||||
|
pymodule2sphinx(BASEPATH, "bpy.app.handlers", module, "Application Handlers")
|
||||||
|
|
||||||
if "bpy.props" not in EXCLUDE_MODULES:
|
if "bpy.props" not in EXCLUDE_MODULES:
|
||||||
from bpy import props as module
|
from bpy import props as module
|
||||||
pymodule2sphinx(BASEPATH, "bpy.props", module, "Property Definitions")
|
pymodule2sphinx(BASEPATH, "bpy.props", module, "Property Definitions")
|
||||||
|
|||||||
4
extern/CMakeLists.txt
vendored
4
extern/CMakeLists.txt
vendored
@@ -63,3 +63,7 @@ endif()
|
|||||||
if(WITH_LZMA)
|
if(WITH_LZMA)
|
||||||
add_subdirectory(lzma)
|
add_subdirectory(lzma)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_LIBMV)
|
||||||
|
add_subdirectory(libmv)
|
||||||
|
endif()
|
||||||
|
|||||||
3
extern/SConscript
vendored
3
extern/SConscript
vendored
@@ -28,3 +28,6 @@ if env['WITH_BF_LZO']:
|
|||||||
|
|
||||||
if env['WITH_BF_LZMA']:
|
if env['WITH_BF_LZMA']:
|
||||||
SConscript(['lzma/SConscript'])
|
SConscript(['lzma/SConscript'])
|
||||||
|
|
||||||
|
if env['WITH_BF_LIBMV']:
|
||||||
|
SConscript(['libmv/SConscript'])
|
||||||
|
|||||||
215
extern/libmv/CMakeLists.txt
vendored
Normal file
215
extern/libmv/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# The Original Code is Copyright (C) 2011, Blender Foundation
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Contributor(s): Blender Foundation,
|
||||||
|
# Sergey Sharybin
|
||||||
|
#
|
||||||
|
# ***** END GPL LICENSE BLOCK *****
|
||||||
|
|
||||||
|
set(INC
|
||||||
|
.
|
||||||
|
../Eigen3
|
||||||
|
third_party/ssba
|
||||||
|
third_party/ldl/Include
|
||||||
|
../colamd/Include
|
||||||
|
)
|
||||||
|
|
||||||
|
set(INC_SYS
|
||||||
|
${PNG_INCLUDE_DIR}
|
||||||
|
${ZLIB_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC
|
||||||
|
libmv-capi.cpp
|
||||||
|
libmv/numeric/numeric.cc
|
||||||
|
libmv/numeric/poly.cc
|
||||||
|
libmv/simple_pipeline/reconstruction.cc
|
||||||
|
libmv/simple_pipeline/resect.cc
|
||||||
|
libmv/simple_pipeline/intersect.cc
|
||||||
|
libmv/simple_pipeline/initialize_reconstruction.cc
|
||||||
|
libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
|
libmv/simple_pipeline/pipeline.cc
|
||||||
|
libmv/simple_pipeline/detect.cc
|
||||||
|
libmv/simple_pipeline/tracks.cc
|
||||||
|
libmv/simple_pipeline/bundle.cc
|
||||||
|
libmv/image/convolve.cc
|
||||||
|
libmv/image/array_nd.cc
|
||||||
|
libmv/tracking/pyramid_region_tracker.cc
|
||||||
|
libmv/tracking/sad.cc
|
||||||
|
libmv/tracking/trklt_region_tracker.cc
|
||||||
|
libmv/tracking/klt_region_tracker.cc
|
||||||
|
libmv/tracking/retrack_region_tracker.cc
|
||||||
|
libmv/multiview/projection.cc
|
||||||
|
libmv/multiview/conditioning.cc
|
||||||
|
libmv/multiview/fundamental.cc
|
||||||
|
libmv/multiview/euclidean_resection.cc
|
||||||
|
libmv/multiview/triangulation.cc
|
||||||
|
|
||||||
|
third_party/ssba/Geometry/v3d_metricbundle.cpp
|
||||||
|
third_party/ssba/Math/v3d_optimization.cpp
|
||||||
|
third_party/gflags/gflags.cc
|
||||||
|
third_party/gflags/gflags_reporting.cc
|
||||||
|
third_party/gflags/gflags_completions.cc
|
||||||
|
third_party/fast/fast_9.c
|
||||||
|
third_party/fast/fast_10.c
|
||||||
|
third_party/fast/fast_11.c
|
||||||
|
third_party/fast/fast_12.c
|
||||||
|
third_party/fast/fast.c
|
||||||
|
third_party/fast/nonmax.c
|
||||||
|
third_party/ldl/Source/ldl.c
|
||||||
|
|
||||||
|
libmv-capi.h
|
||||||
|
libmv/logging/logging.h
|
||||||
|
libmv/numeric/dogleg.h
|
||||||
|
libmv/numeric/levenberg_marquardt.h
|
||||||
|
libmv/numeric/poly.h
|
||||||
|
libmv/numeric/function_derivative.h
|
||||||
|
libmv/numeric/numeric.h
|
||||||
|
libmv/simple_pipeline/resect.h
|
||||||
|
libmv/simple_pipeline/reconstruction.h
|
||||||
|
libmv/simple_pipeline/camera_intrinsics.h
|
||||||
|
libmv/simple_pipeline/tracks.h
|
||||||
|
libmv/simple_pipeline/detect.h
|
||||||
|
libmv/simple_pipeline/pipeline.h
|
||||||
|
libmv/simple_pipeline/intersect.h
|
||||||
|
libmv/simple_pipeline/bundle.h
|
||||||
|
libmv/simple_pipeline/initialize_reconstruction.h
|
||||||
|
libmv/image/convolve.h
|
||||||
|
libmv/image/tuple.h
|
||||||
|
libmv/image/array_nd.h
|
||||||
|
libmv/image/sample.h
|
||||||
|
libmv/image/image.h
|
||||||
|
libmv/tracking/region_tracker.h
|
||||||
|
libmv/tracking/retrack_region_tracker.h
|
||||||
|
libmv/tracking/sad.h
|
||||||
|
libmv/tracking/pyramid_region_tracker.h
|
||||||
|
libmv/tracking/trklt_region_tracker.h
|
||||||
|
libmv/tracking/klt_region_tracker.h
|
||||||
|
libmv/base/id_generator.h
|
||||||
|
libmv/base/vector.h
|
||||||
|
libmv/base/scoped_ptr.h
|
||||||
|
libmv/base/vector_utils.h
|
||||||
|
libmv/multiview/nviewtriangulation.h
|
||||||
|
libmv/multiview/resection.h
|
||||||
|
libmv/multiview/euclidean_resection.h
|
||||||
|
libmv/multiview/triangulation.h
|
||||||
|
libmv/multiview/projection.h
|
||||||
|
libmv/multiview/fundamental.h
|
||||||
|
libmv/multiview/conditioning.h
|
||||||
|
|
||||||
|
third_party/ssba/Geometry/v3d_metricbundle.h
|
||||||
|
third_party/ssba/Geometry/v3d_cameramatrix.h
|
||||||
|
third_party/ssba/Geometry/v3d_distortion.h
|
||||||
|
third_party/ssba/Math/v3d_linear_utils.h
|
||||||
|
third_party/ssba/Math/v3d_optimization.h
|
||||||
|
third_party/ssba/Math/v3d_mathutilities.h
|
||||||
|
third_party/ssba/Math/v3d_linear.h
|
||||||
|
third_party/gflags/gflags_completions.h
|
||||||
|
third_party/gflags/mutex.h
|
||||||
|
third_party/gflags/config.h
|
||||||
|
third_party/gflags/gflags.h
|
||||||
|
third_party/fast/fast.h
|
||||||
|
third_party/ldl/Include/ldl.h
|
||||||
|
third_party/msinttypes/stdint.h
|
||||||
|
third_party/msinttypes/inttypes.h
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND SRC
|
||||||
|
third_party/glog/src/logging.cc
|
||||||
|
third_party/glog/src/raw_logging.cc
|
||||||
|
third_party/glog/src/utilities.cc
|
||||||
|
third_party/glog/src/vlog_is_on.cc
|
||||||
|
third_party/glog/src/windows/port.cc
|
||||||
|
|
||||||
|
third_party/glog/src/utilities.h
|
||||||
|
third_party/glog/src/stacktrace_generic-inl.h
|
||||||
|
third_party/glog/src/stacktrace.h
|
||||||
|
third_party/glog/src/stacktrace_x86_64-inl.h
|
||||||
|
third_party/glog/src/base/googleinit.h
|
||||||
|
third_party/glog/src/base/mutex.h
|
||||||
|
third_party/glog/src/base/commandlineflags.h
|
||||||
|
third_party/glog/src/stacktrace_powerpc-inl.h
|
||||||
|
third_party/glog/src/stacktrace_x86-inl.h
|
||||||
|
third_party/glog/src/config.h
|
||||||
|
third_party/glog/src/stacktrace_libunwind-inl.h
|
||||||
|
third_party/glog/src/windows/glog/raw_logging.h
|
||||||
|
third_party/glog/src/windows/glog/vlog_is_on.h
|
||||||
|
third_party/glog/src/windows/glog/logging.h
|
||||||
|
third_party/glog/src/windows/glog/log_severity.h
|
||||||
|
third_party/glog/src/windows/port.h
|
||||||
|
third_party/glog/src/windows/config.h
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND INC
|
||||||
|
third_party/glog/src/windows
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT MINGW)
|
||||||
|
list(APPEND INC
|
||||||
|
third_party/msinttypes
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
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()
|
||||||
|
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()
|
||||||
|
|
||||||
|
add_definitions(-DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL=)
|
||||||
|
|
||||||
|
blender_add_lib(extern_libmv "${SRC}" "${INC}" "${INC_SYS}")
|
||||||
312
extern/libmv/ChangeLog
vendored
Normal file
312
extern/libmv/ChangeLog
vendored
Normal file
@@ -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).
|
||||||
62
extern/libmv/SConscript
vendored
Normal file
62
extern/libmv/SConscript
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#!/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'
|
||||||
|
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
|
||||||
|
incs += ' ./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 )
|
||||||
263
extern/libmv/bundle.sh
vendored
Executable file
263
extern/libmv/bundle.sh
vendored
Executable file
@@ -0,0 +1,263 @@
|
|||||||
|
#!/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
|
||||||
|
)
|
||||||
|
|
||||||
|
IF(NOT MINGW)
|
||||||
|
list(APPEND INC
|
||||||
|
./third_party/msinttypes
|
||||||
|
)
|
||||||
|
ENDIF(MINGW)
|
||||||
|
|
||||||
|
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'
|
||||||
|
incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog'
|
||||||
|
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
|
||||||
|
incs += ' ./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
|
||||||
141
extern/libmv/files.txt
vendored
Normal file
141
extern/libmv/files.txt
vendored
Normal file
@@ -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
|
||||||
770
extern/libmv/libmv-capi.cpp
vendored
Normal file
770
extern/libmv/libmv-capi.cpp
vendored
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
128
extern/libmv/libmv-capi.h
vendored
Normal file
128
extern/libmv/libmv-capi.h
vendored
Normal file
@@ -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
|
||||||
37
extern/libmv/libmv/base/id_generator.h
vendored
Normal file
37
extern/libmv/libmv/base/id_generator.h
vendored
Normal file
@@ -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
|
||||||
60
extern/libmv/libmv/base/scoped_ptr.h
vendored
Normal file
60
extern/libmv/libmv/base/scoped_ptr.h
vendored
Normal file
@@ -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
|
||||||
172
extern/libmv/libmv/base/vector.h
vendored
Normal file
172
extern/libmv/libmv/base/vector.h
vendored
Normal file
@@ -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
|
||||||
34
extern/libmv/libmv/base/vector_utils.h
vendored
Normal file
34
extern/libmv/libmv/base/vector_utils.h
vendored
Normal file
@@ -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_
|
||||||
108
extern/libmv/libmv/image/array_nd.cc
vendored
Normal file
108
extern/libmv/libmv/image/array_nd.cc
vendored
Normal file
@@ -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
|
||||||
473
extern/libmv/libmv/image/array_nd.h
vendored
Normal file
473
extern/libmv/libmv/image/array_nd.h
vendored
Normal file
@@ -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
|
||||||
305
extern/libmv/libmv/image/convolve.cc
vendored
Normal file
305
extern/libmv/libmv/image/convolve.cc
vendored
Normal file
@@ -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
|
||||||
93
extern/libmv/libmv/image/convolve.h
vendored
Normal file
93
extern/libmv/libmv/image/convolve.h
vendored
Normal file
@@ -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_
|
||||||
|
|
||||||
158
extern/libmv/libmv/image/image.h
vendored
Normal file
158
extern/libmv/libmv/image/image.h
vendored
Normal file
@@ -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
|
||||||
103
extern/libmv/libmv/image/sample.h
vendored
Normal file
103
extern/libmv/libmv/image/sample.h
vendored
Normal file
@@ -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_
|
||||||
90
extern/libmv/libmv/image/tuple.h
vendored
Normal file
90
extern/libmv/libmv/image/tuple.h
vendored
Normal file
@@ -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
|
||||||
31
extern/libmv/libmv/logging/logging.h
vendored
Normal file
31
extern/libmv/libmv/logging/logging.h
vendored
Normal file
@@ -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
|
||||||
99
extern/libmv/libmv/multiview/conditioning.cc
vendored
Normal file
99
extern/libmv/libmv/multiview/conditioning.cc
vendored
Normal file
@@ -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
|
||||||
60
extern/libmv/libmv/multiview/conditioning.h
vendored
Normal file
60
extern/libmv/libmv/multiview/conditioning.h
vendored
Normal file
@@ -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_
|
||||||
663
extern/libmv/libmv/multiview/euclidean_resection.cc
vendored
Normal file
663
extern/libmv/libmv/multiview/euclidean_resection.cc
vendored
Normal file
@@ -0,0 +1,663 @@
|
|||||||
|
// 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 {
|
||||||
|
|
||||||
|
typedef unsigned int uint;
|
||||||
|
|
||||||
|
bool EuclideanResection(const Mat2X &x_camera,
|
||||||
|
const Mat3X &X_world,
|
||||||
|
Mat3 *R, Vec3 *t,
|
||||||
|
ResectionMethod method) {
|
||||||
|
switch (method) {
|
||||||
|
case RESECTION_ANSAR_DANIILIDIS:
|
||||||
|
EuclideanResectionAnsarDaniilidis(x_camera, X_world, R, t);
|
||||||
|
break;
|
||||||
|
case RESECTION_EPNP:
|
||||||
|
return EuclideanResectionEPnP(x_camera, X_world, R, t);
|
||||||
|
break;
|
||||||
|
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
|
||||||
124
extern/libmv/libmv/multiview/euclidean_resection.h
vendored
Normal file
124
extern/libmv/libmv/multiview/euclidean_resection.h
vendored
Normal file
@@ -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_ */
|
||||||
391
extern/libmv/libmv/multiview/fundamental.cc
vendored
Normal file
391
extern/libmv/libmv/multiview/fundamental.cc
vendored
Normal file
@@ -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
|
||||||
144
extern/libmv/libmv/multiview/fundamental.h
vendored
Normal file
144
extern/libmv/libmv/multiview/fundamental.h
vendored
Normal file
@@ -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_
|
||||||
80
extern/libmv/libmv/multiview/nviewtriangulation.h
vendored
Normal file
80
extern/libmv/libmv/multiview/nviewtriangulation.h
vendored
Normal file
@@ -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
|
||||||
221
extern/libmv/libmv/multiview/projection.cc
vendored
Normal file
221
extern/libmv/libmv/multiview/projection.cc
vendored
Normal file
@@ -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
|
||||||
231
extern/libmv/libmv/multiview/projection.h
vendored
Normal file
231
extern/libmv/libmv/multiview/projection.h
vendored
Normal file
@@ -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_
|
||||||
62
extern/libmv/libmv/multiview/resection.h
vendored
Normal file
62
extern/libmv/libmv/multiview/resection.h
vendored
Normal file
@@ -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
|
||||||
49
extern/libmv/libmv/multiview/triangulation.cc
vendored
Normal file
49
extern/libmv/libmv/multiview/triangulation.cc
vendored
Normal file
@@ -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
|
||||||
38
extern/libmv/libmv/multiview/triangulation.h
vendored
Normal file
38
extern/libmv/libmv/multiview/triangulation.h
vendored
Normal file
@@ -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_
|
||||||
261
extern/libmv/libmv/numeric/dogleg.h
vendored
Normal file
261
extern/libmv/libmv/numeric/dogleg.h
vendored
Normal file
@@ -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 ¶ms,
|
||||||
|
JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) {
|
||||||
|
*J = df_(x);
|
||||||
|
// TODO(keir): In the case of m = n, avoid computing A and just do J^-1 directly.
|
||||||
|
*A = (*J).transpose() * (*J);
|
||||||
|
*error = f_(x);
|
||||||
|
*g = (*J).transpose() * *error;
|
||||||
|
if (g->array().abs().maxCoeff() < params.gradient_threshold) {
|
||||||
|
return GRADIENT_TOO_SMALL;
|
||||||
|
} else if (error->array().abs().maxCoeff() < params.error_threshold) {
|
||||||
|
return ERROR_TOO_SMALL;
|
||||||
|
}
|
||||||
|
return RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
Step SolveDoglegDirection(const Parameters &dx_sd,
|
||||||
|
const Parameters &dx_gn,
|
||||||
|
Scalar radius,
|
||||||
|
Scalar alpha,
|
||||||
|
Parameters *dx_dl,
|
||||||
|
Scalar *beta) {
|
||||||
|
Parameters a, b_minus_a;
|
||||||
|
// Solve for Dogleg step dx_dl.
|
||||||
|
if (dx_gn.norm() < radius) {
|
||||||
|
*dx_dl = dx_gn;
|
||||||
|
return GAUSS_NEWTON;
|
||||||
|
|
||||||
|
} else if (alpha * dx_sd.norm() > radius) {
|
||||||
|
*dx_dl = (radius / dx_sd.norm()) * dx_sd;
|
||||||
|
return STEEPEST_DESCENT;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Parameters a = alpha * dx_sd;
|
||||||
|
const Parameters &b = dx_gn;
|
||||||
|
b_minus_a = a - b;
|
||||||
|
Scalar Mbma2 = b_minus_a.squaredNorm();
|
||||||
|
Scalar Ma2 = a.squaredNorm();
|
||||||
|
Scalar c = a.dot(b_minus_a);
|
||||||
|
Scalar radius2 = radius*radius;
|
||||||
|
if (c <= 0) {
|
||||||
|
*beta = (-c + sqrt(c*c + Mbma2*(radius2 - Ma2)))/(Mbma2);
|
||||||
|
} else {
|
||||||
|
*beta = (radius2 - Ma2) /
|
||||||
|
(c + sqrt(c*c + Mbma2*(radius2 - Ma2)));
|
||||||
|
}
|
||||||
|
*dx_dl = alpha * dx_sd + (*beta) * (dx_gn - alpha*dx_sd);
|
||||||
|
return DOGLEG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Results minimize(Parameters *x_and_min) {
|
||||||
|
SolverParameters params;
|
||||||
|
return minimize(params, x_and_min);
|
||||||
|
}
|
||||||
|
|
||||||
|
Results minimize(const SolverParameters ¶ms, Parameters *x_and_min) {
|
||||||
|
Parameters &x = *x_and_min;
|
||||||
|
JMatrixType J;
|
||||||
|
AMatrixType A;
|
||||||
|
FVec error;
|
||||||
|
Parameters g;
|
||||||
|
|
||||||
|
Results results;
|
||||||
|
results.status = Update(x, params, &J, &A, &error, &g);
|
||||||
|
|
||||||
|
Scalar radius = params.initial_trust_radius;
|
||||||
|
bool x_updated = true;
|
||||||
|
|
||||||
|
Parameters x_new;
|
||||||
|
Parameters dx_sd; // Steepest descent step.
|
||||||
|
Parameters dx_dl; // Dogleg step.
|
||||||
|
Parameters dx_gn; // Gauss-Newton step.
|
||||||
|
printf("iteration ||f(x)|| max(g) radius\n");
|
||||||
|
int i = 0;
|
||||||
|
for (; results.status == RUNNING && i < params.max_iterations; ++i) {
|
||||||
|
printf("%9d %12g %12g %12g",
|
||||||
|
i, f_(x).norm(), g.array().abs().maxCoeff(), radius);
|
||||||
|
|
||||||
|
//LG << "iteration: " << i;
|
||||||
|
//LG << "||f(x)||: " << f_(x).norm();
|
||||||
|
//LG << "max(g): " << g.cwise().abs().maxCoeff();
|
||||||
|
//LG << "radius: " << radius;
|
||||||
|
// Eqn 3.19 from [1]
|
||||||
|
Scalar alpha = g.squaredNorm() / (J*g).squaredNorm();
|
||||||
|
|
||||||
|
// Solve for steepest descent direction dx_sd.
|
||||||
|
dx_sd = -g;
|
||||||
|
|
||||||
|
// Solve for Gauss-Newton direction dx_gn.
|
||||||
|
if (x_updated) {
|
||||||
|
// TODO(keir): See Appendix B of [1] for discussion of when A is
|
||||||
|
// singular and there are many solutions. Solving that involves the SVD
|
||||||
|
// and is slower, but should still work.
|
||||||
|
Solver solver(A);
|
||||||
|
dx_gn = solver.solve(-g);
|
||||||
|
if (!(A * dx_gn).isApprox(-g)) {
|
||||||
|
LOG(ERROR) << "Failed to solve normal eqns. TODO: Solve via SVD.";
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
x_updated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solve for dogleg direction dx_dl.
|
||||||
|
Scalar beta = 0;
|
||||||
|
Step step = SolveDoglegDirection(dx_sd, dx_gn, radius, alpha,
|
||||||
|
&dx_dl, &beta);
|
||||||
|
|
||||||
|
Scalar e3 = params.relative_step_threshold;
|
||||||
|
if (dx_dl.norm() < e3*(x.norm() + e3)) {
|
||||||
|
results.status = RELATIVE_STEP_SIZE_TOO_SMALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
x_new = x + dx_dl;
|
||||||
|
Scalar actual = f_(x).squaredNorm() - f_(x_new).squaredNorm();
|
||||||
|
Scalar predicted = 0;
|
||||||
|
if (step == GAUSS_NEWTON) {
|
||||||
|
predicted = f_(x).squaredNorm();
|
||||||
|
} else if (step == STEEPEST_DESCENT) {
|
||||||
|
predicted = radius * (2*alpha*g.norm() - radius) / 2 / alpha;
|
||||||
|
} else if (step == DOGLEG) {
|
||||||
|
predicted = 0.5 * alpha * (1-beta)*(1-beta)*g.squaredNorm() +
|
||||||
|
beta*(2-beta)*f_(x).squaredNorm();
|
||||||
|
}
|
||||||
|
Scalar rho = actual / predicted;
|
||||||
|
|
||||||
|
if (step == GAUSS_NEWTON) printf(" GAUSS");
|
||||||
|
if (step == STEEPEST_DESCENT) printf(" STEE");
|
||||||
|
if (step == DOGLEG) printf(" DOGL");
|
||||||
|
|
||||||
|
printf(" %12g %12g %12g\n", rho, actual, predicted);
|
||||||
|
|
||||||
|
if (rho > 0) {
|
||||||
|
// Accept update because the linear model is a good fit.
|
||||||
|
x = x_new;
|
||||||
|
results.status = Update(x, params, &J, &A, &error, &g);
|
||||||
|
x_updated = true;
|
||||||
|
}
|
||||||
|
if (rho > 0.75) {
|
||||||
|
radius = std::max(radius, 3*dx_dl.norm());
|
||||||
|
} else if (rho < 0.25) {
|
||||||
|
radius /= 2;
|
||||||
|
if (radius < e3 * (x.norm() + e3)) {
|
||||||
|
results.status = TRUST_REGION_TOO_SMALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (results.status == RUNNING) {
|
||||||
|
results.status = HIT_MAX_ITERATIONS;
|
||||||
|
}
|
||||||
|
results.error_magnitude = error.norm();
|
||||||
|
results.gradient_magnitude = g.norm();
|
||||||
|
results.iterations = i;
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Function &f_;
|
||||||
|
Jacobian df_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mv
|
||||||
|
|
||||||
|
#endif // LIBMV_NUMERIC_DOGLEG_H
|
||||||
107
extern/libmv/libmv/numeric/function_derivative.h
vendored
Normal file
107
extern/libmv/libmv/numeric/function_derivative.h
vendored
Normal file
@@ -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
|
||||||
183
extern/libmv/libmv/numeric/levenberg_marquardt.h
vendored
Normal file
183
extern/libmv/libmv/numeric/levenberg_marquardt.h
vendored
Normal file
@@ -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 ¶ms,
|
||||||
|
JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) {
|
||||||
|
*J = df_(x);
|
||||||
|
*A = (*J).transpose() * (*J);
|
||||||
|
*error = -f_(x);
|
||||||
|
*g = (*J).transpose() * *error;
|
||||||
|
if (g->array().abs().maxCoeff() < params.gradient_threshold) {
|
||||||
|
return GRADIENT_TOO_SMALL;
|
||||||
|
} else if (error->norm() < params.error_threshold) {
|
||||||
|
return ERROR_TOO_SMALL;
|
||||||
|
}
|
||||||
|
return RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
Results minimize(Parameters *x_and_min) {
|
||||||
|
SolverParameters params;
|
||||||
|
minimize(params, x_and_min);
|
||||||
|
}
|
||||||
|
|
||||||
|
Results minimize(const SolverParameters ¶ms, Parameters *x_and_min) {
|
||||||
|
Parameters &x = *x_and_min;
|
||||||
|
JMatrixType J;
|
||||||
|
AMatrixType A;
|
||||||
|
FVec error;
|
||||||
|
Parameters g;
|
||||||
|
|
||||||
|
Results results;
|
||||||
|
results.status = Update(x, params, &J, &A, &error, &g);
|
||||||
|
|
||||||
|
Scalar u = Scalar(params.initial_scale_factor*A.diagonal().maxCoeff());
|
||||||
|
Scalar v = 2;
|
||||||
|
|
||||||
|
Parameters dx, x_new;
|
||||||
|
int i;
|
||||||
|
for (i = 0; results.status == RUNNING && i < params.max_iterations; ++i) {
|
||||||
|
VLOG(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
|
||||||
136
extern/libmv/libmv/numeric/numeric.cc
vendored
Normal file
136
extern/libmv/libmv/numeric/numeric.cc
vendored
Normal file
@@ -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
|
||||||
|
|
||||||
479
extern/libmv/libmv/numeric/numeric.h
vendored
Normal file
479
extern/libmv/libmv/numeric/numeric.h
vendored
Normal file
@@ -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
|
||||||
23
extern/libmv/libmv/numeric/poly.cc
vendored
Normal file
23
extern/libmv/libmv/numeric/poly.cc
vendored
Normal file
@@ -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.
|
||||||
123
extern/libmv/libmv/numeric/poly.h
vendored
Normal file
123
extern/libmv/libmv/numeric/poly.h
vendored
Normal file
@@ -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_
|
||||||
184
extern/libmv/libmv/simple_pipeline/bundle.cc
vendored
Normal file
184
extern/libmv/libmv/simple_pipeline/bundle.cc
vendored
Normal file
@@ -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
|
||||||
72
extern/libmv/libmv/simple_pipeline/bundle.h
vendored
Normal file
72
extern/libmv/libmv/simple_pipeline/bundle.h
vendored
Normal file
@@ -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
|
||||||
351
extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
vendored
Normal file
351
extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
vendored
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/camera_intrinsics.h"
|
||||||
|
#include "libmv/numeric/levenberg_marquardt.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
struct Offset {
|
||||||
|
signed char ix, iy;
|
||||||
|
unsigned char fx,fy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Grid {
|
||||||
|
struct Offset *offset;
|
||||||
|
int width, height;
|
||||||
|
double overscan;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct Grid *copyGrid(struct Grid *from)
|
||||||
|
{
|
||||||
|
struct Grid *to = NULL;
|
||||||
|
|
||||||
|
if (from) {
|
||||||
|
to = new Grid;
|
||||||
|
|
||||||
|
to->width = from->width;
|
||||||
|
to->height = from->height;
|
||||||
|
to->overscan = from->overscan;
|
||||||
|
|
||||||
|
to->offset = new Offset[to->width*to->height];
|
||||||
|
memcpy(to->offset, from->offset, sizeof(struct Offset)*to->width*to->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
CameraIntrinsics::CameraIntrinsics()
|
||||||
|
: K_(Mat3::Identity()),
|
||||||
|
image_width_(0),
|
||||||
|
image_height_(0),
|
||||||
|
k1_(0),
|
||||||
|
k2_(0),
|
||||||
|
k3_(0),
|
||||||
|
p1_(0),
|
||||||
|
p2_(0),
|
||||||
|
distort_(0),
|
||||||
|
undistort_(0) {}
|
||||||
|
|
||||||
|
CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics &from)
|
||||||
|
: K_(from.K_),
|
||||||
|
image_width_(from.image_width_),
|
||||||
|
image_height_(from.image_height_),
|
||||||
|
k1_(from.k1_),
|
||||||
|
k2_(from.k2_),
|
||||||
|
k3_(from.k3_),
|
||||||
|
p1_(from.p1_),
|
||||||
|
p2_(from.p2_)
|
||||||
|
{
|
||||||
|
distort_ = copyGrid(from.distort_);
|
||||||
|
undistort_ = copyGrid(from.undistort_);
|
||||||
|
}
|
||||||
|
|
||||||
|
CameraIntrinsics::~CameraIntrinsics() {
|
||||||
|
FreeLookupGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the entire calibration matrix at once.
|
||||||
|
void CameraIntrinsics::SetK(const Mat3 new_k) {
|
||||||
|
K_ = new_k;
|
||||||
|
FreeLookupGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set both x and y focal length in pixels.
|
||||||
|
void CameraIntrinsics::SetFocalLength(double focal_x, double focal_y) {
|
||||||
|
K_(0, 0) = focal_x;
|
||||||
|
K_(1, 1) = focal_y;
|
||||||
|
FreeLookupGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::SetPrincipalPoint(double cx, double cy) {
|
||||||
|
K_(0, 2) = cx;
|
||||||
|
K_(1, 2) = cy;
|
||||||
|
FreeLookupGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::SetImageSize(int width, int height) {
|
||||||
|
image_width_ = width;
|
||||||
|
image_height_ = height;
|
||||||
|
FreeLookupGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::SetRadialDistortion(double k1, double k2, double k3) {
|
||||||
|
k1_ = k1;
|
||||||
|
k2_ = k2;
|
||||||
|
k3_ = k3;
|
||||||
|
FreeLookupGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::SetTangentialDistortion(double p1, double p2) {
|
||||||
|
p1_ = p1;
|
||||||
|
p2_ = p2;
|
||||||
|
FreeLookupGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::ApplyIntrinsics(double normalized_x,
|
||||||
|
double normalized_y,
|
||||||
|
double *image_x,
|
||||||
|
double *image_y) const {
|
||||||
|
double x = normalized_x;
|
||||||
|
double y = normalized_y;
|
||||||
|
|
||||||
|
// Apply distortion to the normalized points to get (xd, yd).
|
||||||
|
double r2 = x*x + y*y;
|
||||||
|
double r4 = r2 * r2;
|
||||||
|
double r6 = r4 * r2;
|
||||||
|
double r_coeff = (1 + k1_*r2 + k2_*r4 + k3_*r6);
|
||||||
|
double xd = x * r_coeff + 2*p1_*x*y + p2_*(r2 + 2*x*x);
|
||||||
|
double yd = y * r_coeff + 2*p2_*x*y + p1_*(r2 + 2*y*y);
|
||||||
|
|
||||||
|
// Apply focal length and principal point to get the final image coordinates.
|
||||||
|
*image_x = focal_length_x() * xd + principal_point_x();
|
||||||
|
*image_y = focal_length_y() * yd + principal_point_y();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InvertIntrinsicsCostFunction {
|
||||||
|
public:
|
||||||
|
typedef Vec2 FMatrixType;
|
||||||
|
typedef Vec2 XMatrixType;
|
||||||
|
|
||||||
|
InvertIntrinsicsCostFunction(const CameraIntrinsics &intrinsics,
|
||||||
|
double image_x, double image_y)
|
||||||
|
: intrinsics(intrinsics), x(image_x), y(image_y) {}
|
||||||
|
|
||||||
|
Vec2 operator()(const Vec2 &u) const {
|
||||||
|
double xx, yy;
|
||||||
|
intrinsics.ApplyIntrinsics(u(0), u(1), &xx, &yy);
|
||||||
|
Vec2 fx;
|
||||||
|
fx << (xx - x), (yy - y);
|
||||||
|
return fx;
|
||||||
|
}
|
||||||
|
const CameraIntrinsics &intrinsics;
|
||||||
|
double x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CameraIntrinsics::InvertIntrinsics(double image_x,
|
||||||
|
double image_y,
|
||||||
|
double *normalized_x,
|
||||||
|
double *normalized_y) const {
|
||||||
|
// Compute the initial guess. For a camera with no distortion, this will also
|
||||||
|
// be the final answer; the LM iteration will terminate immediately.
|
||||||
|
Vec2 normalized;
|
||||||
|
normalized(0) = (image_x - principal_point_x()) / focal_length_x();
|
||||||
|
normalized(1) = (image_y - principal_point_y()) / focal_length_y();
|
||||||
|
|
||||||
|
typedef LevenbergMarquardt<InvertIntrinsicsCostFunction> Solver;
|
||||||
|
|
||||||
|
InvertIntrinsicsCostFunction intrinsics_cost(*this, image_x, image_y);
|
||||||
|
Solver::SolverParameters params;
|
||||||
|
Solver solver(intrinsics_cost);
|
||||||
|
|
||||||
|
/*Solver::Results results =*/ solver.minimize(params, &normalized);
|
||||||
|
|
||||||
|
// TODO(keir): Better error handling.
|
||||||
|
|
||||||
|
*normalized_x = normalized(0);
|
||||||
|
*normalized_y = normalized(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(MatthiasF): downsample lookup
|
||||||
|
template<typename WarpFunction>
|
||||||
|
void CameraIntrinsics::ComputeLookupGrid(Grid* grid, int width, int height, double overscan) {
|
||||||
|
double w = (double)width / (1 + overscan);
|
||||||
|
double h = (double)height / (1 + overscan);
|
||||||
|
double aspx = (double)w / image_width_;
|
||||||
|
double aspy = (double)h / image_height_;
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
double src_x = (x - 0.5 * overscan * w) / aspx, src_y = (y - 0.5 * overscan * h) / aspy;
|
||||||
|
double warp_x, warp_y;
|
||||||
|
WarpFunction(this,src_x,src_y,&warp_x,&warp_y);
|
||||||
|
warp_x = warp_x*aspx + 0.5 * overscan * w;
|
||||||
|
warp_y = warp_y*aspy + 0.5 * overscan * h;
|
||||||
|
int ix = int(warp_x), iy = int(warp_y);
|
||||||
|
int fx = round((warp_x-ix)*256), fy = round((warp_y-iy)*256);
|
||||||
|
if(fx == 256) { fx=0; ix++; }
|
||||||
|
if(fy == 256) { fy=0; iy++; }
|
||||||
|
// Use nearest border pixel
|
||||||
|
if( ix < 0 ) { ix = 0, fx = 0; }
|
||||||
|
if( iy < 0 ) { iy = 0, fy = 0; }
|
||||||
|
if( ix >= width-2 ) ix = width-2;
|
||||||
|
if( iy >= height-2 ) iy = height-2;
|
||||||
|
if ( ix-x > -128 && ix-x < 128 && iy-y > -128 && iy-y < 128 ) {
|
||||||
|
Offset offset = { ix-x, iy-y, fx, fy };
|
||||||
|
grid->offset[y*width+x] = offset;
|
||||||
|
} else {
|
||||||
|
Offset offset = { 0, 0, 0, 0 };
|
||||||
|
grid->offset[y*width+x] = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(MatthiasF): cubic B-Spline image sampling, bilinear lookup
|
||||||
|
template<typename T,int N>
|
||||||
|
static void Warp(const Grid* grid, const T* src, T* dst,
|
||||||
|
int width, int height) {
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
Offset offset = grid->offset[y*width+x];
|
||||||
|
const T* s = &src[((y+offset.iy)*width+(x+offset.ix))*N];
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
dst[(y*width+x)*N+i] = ((s[ i] * (256-offset.fx) + s[ N+i] * offset.fx) * (256-offset.fy)
|
||||||
|
+(s[width*N+i] * (256-offset.fx) + s[width*N+N+i] * offset.fx) * offset.fy) / (256*256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::FreeLookupGrid() {
|
||||||
|
if(distort_) {
|
||||||
|
delete distort_->offset;
|
||||||
|
delete distort_;
|
||||||
|
distort_ = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(undistort_) {
|
||||||
|
delete undistort_->offset;
|
||||||
|
delete undistort_;
|
||||||
|
undistort_ = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: C++ templates limitations makes thing complicated, but maybe there is a simpler method.
|
||||||
|
struct ApplyIntrinsicsFunction {
|
||||||
|
ApplyIntrinsicsFunction(CameraIntrinsics* intrinsics, double x, double y,
|
||||||
|
double *warp_x, double *warp_y) {
|
||||||
|
intrinsics->ApplyIntrinsics(
|
||||||
|
(x-intrinsics->principal_point_x())/intrinsics->focal_length_x(),
|
||||||
|
(y-intrinsics->principal_point_y())/intrinsics->focal_length_y(),
|
||||||
|
warp_x, warp_y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct InvertIntrinsicsFunction {
|
||||||
|
InvertIntrinsicsFunction(CameraIntrinsics* intrinsics, double x, double y,
|
||||||
|
double *warp_x, double *warp_y) {
|
||||||
|
intrinsics->InvertIntrinsics(x,y,warp_x,warp_y);
|
||||||
|
*warp_x = *warp_x*intrinsics->focal_length_x()+intrinsics->principal_point_x();
|
||||||
|
*warp_y = *warp_y*intrinsics->focal_length_y()+intrinsics->principal_point_y();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void CameraIntrinsics::CheckDistortLookupGrid(int width, int height, double overscan)
|
||||||
|
{
|
||||||
|
if(distort_) {
|
||||||
|
if(distort_->width != width || distort_->height != height || distort_->overscan != overscan) {
|
||||||
|
delete [] distort_->offset;
|
||||||
|
distort_->offset = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
distort_ = new Grid;
|
||||||
|
distort_->offset = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!distort_->offset) {
|
||||||
|
distort_->offset = new Offset[width*height];
|
||||||
|
ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height,overscan);
|
||||||
|
}
|
||||||
|
|
||||||
|
distort_->width = width;
|
||||||
|
distort_->height = height;
|
||||||
|
distort_->overscan = overscan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height, double overscan)
|
||||||
|
{
|
||||||
|
if(undistort_) {
|
||||||
|
if(undistort_->width != width || undistort_->height != height || undistort_->overscan != overscan) {
|
||||||
|
delete [] undistort_->offset;
|
||||||
|
undistort_->offset = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
undistort_ = new Grid;
|
||||||
|
undistort_->offset = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!undistort_->offset) {
|
||||||
|
undistort_->offset = new Offset[width*height];
|
||||||
|
ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height,overscan);
|
||||||
|
}
|
||||||
|
|
||||||
|
undistort_->width = width;
|
||||||
|
undistort_->height = height;
|
||||||
|
undistort_->overscan = overscan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, double overscan, int channels) {
|
||||||
|
CheckDistortLookupGrid(width, height, overscan);
|
||||||
|
if(channels==1) Warp<float,1>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<float,2>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<float,3>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==4) Warp<float,4>(distort_,src,dst,width,height);
|
||||||
|
//else assert("channels must be between 1 and 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int width, int height, double overscan, int channels) {
|
||||||
|
CheckDistortLookupGrid(width, height, overscan);
|
||||||
|
if(channels==1) Warp<unsigned char,1>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<unsigned char,2>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<unsigned char,3>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==4) Warp<unsigned char,4>(distort_,src,dst,width,height);
|
||||||
|
//else assert("channels must be between 1 and 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int height, double overscan, int channels) {
|
||||||
|
CheckUndistortLookupGrid(width, height, overscan);
|
||||||
|
if(channels==1) Warp<float,1>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<float,2>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<float,3>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==4) Warp<float,4>(undistort_,src,dst,width,height);
|
||||||
|
//else assert("channels must be between 1 and 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::Undistort(const unsigned char* src, unsigned char* dst, int width, int height, double overscan, int channels) {
|
||||||
|
CheckUndistortLookupGrid(width, height, overscan);
|
||||||
|
if(channels==1) Warp<unsigned char,1>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<unsigned char,2>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<unsigned char,3>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==4) Warp<unsigned char,4>(undistort_,src,dst,width,height);
|
||||||
|
//else assert("channels must be between 1 and 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
152
extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
vendored
Normal file
152
extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
vendored
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_
|
||||||
|
#define LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_
|
||||||
|
|
||||||
|
#include <Eigen/Core>
|
||||||
|
typedef Eigen::Matrix<double, 3, 3> Mat3;
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
struct Grid;
|
||||||
|
|
||||||
|
class CameraIntrinsics {
|
||||||
|
public:
|
||||||
|
CameraIntrinsics();
|
||||||
|
CameraIntrinsics(const CameraIntrinsics &from);
|
||||||
|
~CameraIntrinsics();
|
||||||
|
|
||||||
|
const Mat3 &K() const { return K_; }
|
||||||
|
// FIXME(MatthiasF): these should be CamelCase methods
|
||||||
|
double focal_length() const { return K_(0, 0); }
|
||||||
|
double focal_length_x() const { return K_(0, 0); }
|
||||||
|
double focal_length_y() const { return K_(1, 1); }
|
||||||
|
double principal_point_x() const { return K_(0, 2); }
|
||||||
|
double principal_point_y() const { return K_(1, 2); }
|
||||||
|
int image_width() const { return image_width_; }
|
||||||
|
int image_height() const { return image_height_; }
|
||||||
|
double k1() const { return k1_; }
|
||||||
|
double k2() const { return k2_; }
|
||||||
|
double k3() const { return k3_; }
|
||||||
|
double p1() const { return p1_; }
|
||||||
|
double p2() const { return p2_; }
|
||||||
|
|
||||||
|
/// Set the entire calibration matrix at once.
|
||||||
|
void SetK(const Mat3 new_k);
|
||||||
|
|
||||||
|
/// Set both x and y focal length in pixels.
|
||||||
|
void SetFocalLength(double focal_x, double focal_y);
|
||||||
|
|
||||||
|
void SetPrincipalPoint(double cx, double cy);
|
||||||
|
|
||||||
|
void SetImageSize(int width, int height);
|
||||||
|
|
||||||
|
void SetRadialDistortion(double k1, double k2, double k3 = 0);
|
||||||
|
|
||||||
|
void SetTangentialDistortion(double p1, double p2);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Apply camera intrinsics to the normalized point to get image coordinates.
|
||||||
|
|
||||||
|
This applies the lens distortion to a point which is in normalized
|
||||||
|
camera coordinates (i.e. the principal point is at (0, 0)) to get image
|
||||||
|
coordinates in pixels.
|
||||||
|
*/
|
||||||
|
void ApplyIntrinsics(double normalized_x, double normalized_y,
|
||||||
|
double *image_x, double *image_y) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Invert camera intrinsics on the image point to get normalized coordinates.
|
||||||
|
|
||||||
|
This reverses the effect of lens distortion on a point which is in image
|
||||||
|
coordinates to get normalized camera coordinates.
|
||||||
|
*/
|
||||||
|
void InvertIntrinsics(double image_x, double image_y,
|
||||||
|
double *normalized_x, double *normalized_y) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Distort an image using the current camera instrinsics
|
||||||
|
|
||||||
|
The distorted image is computed in \a dst using samples from \a src.
|
||||||
|
both buffers should be \a width x \a height x \a channels sized.
|
||||||
|
|
||||||
|
\note This is the reference implementation using floating point images.
|
||||||
|
*/
|
||||||
|
void Distort(const float* src, float* dst,
|
||||||
|
int width, int height, double overscan, int channels);
|
||||||
|
/*!
|
||||||
|
Distort an image using the current camera instrinsics
|
||||||
|
|
||||||
|
The distorted image is computed in \a dst using samples from \a src.
|
||||||
|
both buffers should be \a width x \a height x \a channels sized.
|
||||||
|
|
||||||
|
\note This version is much faster.
|
||||||
|
*/
|
||||||
|
void Distort(const unsigned char* src, unsigned char* dst,
|
||||||
|
int width, int height, double overscan, int channels);
|
||||||
|
/*!
|
||||||
|
Undistort an image using the current camera instrinsics
|
||||||
|
|
||||||
|
The undistorted image is computed in \a dst using samples from \a src.
|
||||||
|
both buffers should be \a width x \a height x \a channels sized.
|
||||||
|
|
||||||
|
\note This is the reference implementation using floating point images.
|
||||||
|
*/
|
||||||
|
void Undistort(const float* src, float* dst,
|
||||||
|
int width, int height, double overscan, int channels);
|
||||||
|
/*!
|
||||||
|
Undistort an image using the current camera instrinsics
|
||||||
|
|
||||||
|
The undistorted image is computed in \a dst using samples from \a src.
|
||||||
|
both buffers should be \a width x \a height x \a channels sized.
|
||||||
|
|
||||||
|
\note This version is much faster.
|
||||||
|
*/
|
||||||
|
void Undistort(const unsigned char* src, unsigned char* dst,
|
||||||
|
int width, int height, double overscan, int channels);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename WarpFunction> void ComputeLookupGrid(struct Grid* grid, int width, int height, double overscan);
|
||||||
|
void CheckUndistortLookupGrid(int width, int height, double overscan);
|
||||||
|
void CheckDistortLookupGrid(int width, int height, double overscan);
|
||||||
|
void FreeLookupGrid();
|
||||||
|
|
||||||
|
// The traditional intrinsics matrix from x = K[R|t]X.
|
||||||
|
Mat3 K_;
|
||||||
|
|
||||||
|
// This is the size of the image. This is necessary to, for example, handle
|
||||||
|
// the case of processing a scaled image.
|
||||||
|
int image_width_;
|
||||||
|
int image_height_;
|
||||||
|
|
||||||
|
// OpenCV's distortion model with third order polynomial radial distortion
|
||||||
|
// terms and second order tangential distortion. The distortion is applied to
|
||||||
|
// the normalized coordinates before the focal length, which makes them
|
||||||
|
// independent of image size.
|
||||||
|
double k1_, k2_, k3_, p1_, p2_;
|
||||||
|
|
||||||
|
struct Grid *distort_;
|
||||||
|
struct Grid *undistort_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_
|
||||||
184
extern/libmv/libmv/simple_pipeline/detect.cc
vendored
Normal file
184
extern/libmv/libmv/simple_pipeline/detect.cc
vendored
Normal file
@@ -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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/detect.h"
|
||||||
|
#include <third_party/fast/fast.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
#ifdef __SSE2__
|
||||||
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
typedef unsigned int uint;
|
||||||
|
|
||||||
|
int featurecmp(const void *a_v, const void *b_v)
|
||||||
|
{
|
||||||
|
Feature *a = (Feature*)a_v;
|
||||||
|
Feature *b = (Feature*)b_v;
|
||||||
|
|
||||||
|
return b->score - a->score;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Feature> DetectFAST(const unsigned char* data, int width, int height, int stride,
|
||||||
|
int min_trackness, int min_distance) {
|
||||||
|
std::vector<Feature> features;
|
||||||
|
// TODO(MatthiasF): Support targetting a feature count (binary search trackness)
|
||||||
|
int num_features;
|
||||||
|
xy* all = fast9_detect(data, width, height,
|
||||||
|
stride, min_trackness, &num_features);
|
||||||
|
if(num_features == 0) {
|
||||||
|
free(all);
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
int* scores = fast9_score(data, stride, all, num_features, min_trackness);
|
||||||
|
// TODO: merge with close feature suppression
|
||||||
|
xy* nonmax = nonmax_suppression(all, scores, num_features, &num_features);
|
||||||
|
free(all);
|
||||||
|
// Remove too close features
|
||||||
|
// TODO(MatthiasF): A resolution independent parameter would be better than distance
|
||||||
|
// e.g. a coefficient going from 0 (no minimal distance) to 1 (optimal circle packing)
|
||||||
|
// FIXME(MatthiasF): this method will not necessarily give all maximum markers
|
||||||
|
if(num_features) {
|
||||||
|
Feature *all_features = new Feature[num_features];
|
||||||
|
|
||||||
|
for(int i = 0; i < num_features; ++i) {
|
||||||
|
Feature a = { nonmax[i].x, nonmax[i].y, scores[i], 0 };
|
||||||
|
all_features[i] = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort((void *)all_features, num_features, sizeof(Feature), featurecmp);
|
||||||
|
|
||||||
|
features.reserve(num_features);
|
||||||
|
|
||||||
|
int prev_score = all_features[0].score;
|
||||||
|
for(int i = 0; i < num_features; ++i) {
|
||||||
|
bool ok = true;
|
||||||
|
Feature a = all_features[i];
|
||||||
|
if(a.score>prev_score)
|
||||||
|
abort();
|
||||||
|
prev_score = a.score;
|
||||||
|
|
||||||
|
// compare each feature against filtered set
|
||||||
|
for(int j = 0; j < features.size(); j++) {
|
||||||
|
Feature& b = features[j];
|
||||||
|
if ( (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) < min_distance*min_distance ) {
|
||||||
|
// already a nearby feature
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ok) {
|
||||||
|
// add the new feature
|
||||||
|
features.push_back(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] all_features;
|
||||||
|
}
|
||||||
|
free(scores);
|
||||||
|
free(nonmax);
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __SSE2__
|
||||||
|
static uint SAD(const ubyte* imageA, const ubyte* imageB, int strideA, int strideB) {
|
||||||
|
__m128i a = _mm_setzero_si128();
|
||||||
|
for(int i = 0; i < 16; i++) {
|
||||||
|
a = _mm_adds_epu16(a, _mm_sad_epu8( _mm_loadu_si128((__m128i*)(imageA+i*strideA)),
|
||||||
|
_mm_loadu_si128((__m128i*)(imageB+i*strideB))));
|
||||||
|
}
|
||||||
|
return _mm_extract_epi16(a,0) + _mm_extract_epi16(a,4);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static uint SAD(const ubyte* imageA, const ubyte* imageB, int strideA, int strideB) {
|
||||||
|
uint sad=0;
|
||||||
|
for(int i = 0; i < 16; i++) {
|
||||||
|
for(int j = 0; j < 16; j++) {
|
||||||
|
sad += abs((int)imageA[i*strideA+j] - imageB[i*strideB+j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sad;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void DetectMORAVEC(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance, ubyte* pattern) {
|
||||||
|
unsigned short histogram[256];
|
||||||
|
memset(histogram,0,sizeof(histogram));
|
||||||
|
ubyte* scores = new ubyte[width*height];
|
||||||
|
memset(scores,0,width*height);
|
||||||
|
const int r = 1; //radius for self similarity comparison
|
||||||
|
for(int y=distance; y<height-distance; y++) {
|
||||||
|
for(int x=distance; x<width-distance; x++) {
|
||||||
|
ubyte* s = &image[y*stride+x];
|
||||||
|
int score = // low self-similarity with overlapping patterns //OPTI: load pattern once
|
||||||
|
SAD(s, s-r*stride-r, stride, stride)+SAD(s, s-r*stride, stride, stride)+SAD(s, s-r*stride+r, stride, stride)+
|
||||||
|
SAD(s, s -r, stride, stride)+ SAD(s, s +r, stride, stride)+
|
||||||
|
SAD(s, s+r*stride-r, stride, stride)+SAD(s, s+r*stride, stride, stride)+SAD(s, s+r*stride+r, stride, stride);
|
||||||
|
score /= 256; // normalize
|
||||||
|
if(pattern) score -= SAD(s, pattern, stride, 16); // find only features similar to pattern
|
||||||
|
if(score<=16) continue; // filter very self-similar features
|
||||||
|
score -= 16; // translate to score/histogram values
|
||||||
|
if(score>255) score=255; // clip
|
||||||
|
ubyte* c = &scores[y*width+x];
|
||||||
|
for(int i=-distance; i<0; i++) {
|
||||||
|
for(int j=-distance; j<distance; j++) {
|
||||||
|
int s = c[i*width+j];
|
||||||
|
if(s == 0) continue;
|
||||||
|
if(s >= score) goto nonmax;
|
||||||
|
c[i*width+j]=0, histogram[s]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int i=0, j=-distance; j<0; j++) {
|
||||||
|
int s = c[i*width+j];
|
||||||
|
if(s == 0) continue;
|
||||||
|
if(s >= score) goto nonmax;
|
||||||
|
c[i*width+j]=0, histogram[s]--;
|
||||||
|
}
|
||||||
|
c[0] = score, histogram[score]++;
|
||||||
|
nonmax:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int min=255, total=0;
|
||||||
|
for(; min>0; min--) {
|
||||||
|
int h = histogram[min];
|
||||||
|
if(total+h > *count) break;
|
||||||
|
total += h;
|
||||||
|
}
|
||||||
|
int i=0;
|
||||||
|
for(int y=16; y<height-16; y++) {
|
||||||
|
for(int x=16; x<width-16; x++) {
|
||||||
|
int s = scores[y*width+x];
|
||||||
|
Feature f = { x+8, y+8, s, 16 };
|
||||||
|
if(s>min) detected[i++] = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*count = i;
|
||||||
|
delete[] scores;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
95
extern/libmv/libmv/simple_pipeline/detect.h
vendored
Normal file
95
extern/libmv/libmv/simple_pipeline/detect.h
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (c) 2011 libmv authors.
|
||||||
|
**
|
||||||
|
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
** of this software and associated documentation files (the "Software"), to
|
||||||
|
** deal in the Software without restriction, including without limitation the
|
||||||
|
** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
** sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
** furnished to do so, subject to the following conditions:
|
||||||
|
**
|
||||||
|
** The above copyright notice and this permission notice shall be included in
|
||||||
|
** all copies or substantial portions of the Software.
|
||||||
|
**
|
||||||
|
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
** IN THE SOFTWARE.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LIBMV_SIMPLE_PIPELINE_DETECT_H_
|
||||||
|
#define LIBMV_SIMPLE_PIPELINE_DETECT_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
typedef unsigned char ubyte;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A Feature is the 2D location of a detected feature in an image.
|
||||||
|
|
||||||
|
\a x, \a y is the position of the feature in pixels from the top left corner.
|
||||||
|
\a score is an estimate of how well the feature will be tracked.
|
||||||
|
\a size can be used as an initial pattern size to track the feature.
|
||||||
|
|
||||||
|
\sa Detect
|
||||||
|
*/
|
||||||
|
struct Feature {
|
||||||
|
/// Position in pixels (from top-left corner)
|
||||||
|
/// \note libmv might eventually support subpixel precision.
|
||||||
|
float x, y;
|
||||||
|
/// Trackness of the feature
|
||||||
|
float score;
|
||||||
|
/// Size of the feature in pixels
|
||||||
|
float size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Detect features in an image.
|
||||||
|
|
||||||
|
You need to input a single channel 8-bit image using pointer to image \a data,
|
||||||
|
\a width, \a height and \a stride (i.e bytes per line).
|
||||||
|
|
||||||
|
You can tweak the count of detected features using \a min_trackness, which is
|
||||||
|
the minimum score to add a feature, and \a min_distance which is the minimal
|
||||||
|
distance accepted between two featuress.
|
||||||
|
|
||||||
|
\note You can binary search over \a min_trackness to get a given feature count.
|
||||||
|
|
||||||
|
\note a way to get an uniform distribution of a given feature count is:
|
||||||
|
\a min_distance = \a width * \a height / desired_feature_count ^ 2
|
||||||
|
|
||||||
|
\return All detected feartures matching given parameters
|
||||||
|
*/
|
||||||
|
std::vector<Feature> DetectFAST(const unsigned char* data, int width, int height,
|
||||||
|
int stride, int min_trackness = 128,
|
||||||
|
int min_distance = 120);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Detect features in an image.
|
||||||
|
|
||||||
|
\a image is a single channel 8-bit image of size \a width x \a height
|
||||||
|
|
||||||
|
\a detected is an array with space to hold \a *count features.
|
||||||
|
\a *count is the maximum count to detect on input and the actual
|
||||||
|
detected count on output.
|
||||||
|
|
||||||
|
\a distance is the minimal distance between detected features.
|
||||||
|
|
||||||
|
if \a pattern is null all good features will be found.
|
||||||
|
if \a pattern is not null only features similar to \a pattern will be found.
|
||||||
|
|
||||||
|
\note \a You can crop the image (to avoid detecting markers near the borders) without copying:
|
||||||
|
image += marginY*stride+marginX, width -= 2*marginX, height -= 2*marginY;
|
||||||
|
*/
|
||||||
|
void DetectMORAVEC(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance /*=32*/, ubyte* pattern /*=0*/);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
218
extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
vendored
Normal file
218
extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
vendored
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
// 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/base/vector.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/multiview/fundamental.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/numeric/levenberg_marquardt.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/simple_pipeline/reconstruction.h"
|
||||||
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void CoordinatesForMarkersInImage(const vector<Marker> &markers,
|
||||||
|
int image,
|
||||||
|
Mat *coordinates) {
|
||||||
|
vector<Vec2> coords;
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
const Marker &marker = markers[i];
|
||||||
|
if (markers[i].image == image) {
|
||||||
|
coords.push_back(Vec2(marker.x, marker.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
coordinates->resize(2, coords.size());
|
||||||
|
for (int i = 0; i < coords.size(); i++) {
|
||||||
|
coordinates->col(i) = coords[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetImagesInMarkers(const vector<Marker> &markers,
|
||||||
|
int *image1, int *image2) {
|
||||||
|
if (markers.size() < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*image1 = markers[0].image;
|
||||||
|
for (int i = 1; i < markers.size(); ++i) {
|
||||||
|
if (markers[i].image != *image1) {
|
||||||
|
*image2 = markers[i].image;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*image2 = -1;
|
||||||
|
LOG(FATAL) << "Only one image in the markers.";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
|
||||||
|
EuclideanReconstruction *reconstruction) {
|
||||||
|
if (markers.size() < 16) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int image1, image2;
|
||||||
|
GetImagesInMarkers(markers, &image1, &image2);
|
||||||
|
|
||||||
|
Mat x1, x2;
|
||||||
|
CoordinatesForMarkersInImage(markers, image1, &x1);
|
||||||
|
CoordinatesForMarkersInImage(markers, image2, &x2);
|
||||||
|
|
||||||
|
Mat3 F;
|
||||||
|
NormalizedEightPointSolver(x1, x2, &F);
|
||||||
|
|
||||||
|
// The F matrix should be an E matrix, but squash it just to be sure.
|
||||||
|
Eigen::JacobiSVD<Mat3> svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
||||||
|
|
||||||
|
// See Hartley & Zisserman page 294, result 11.1, which shows how to get the
|
||||||
|
// closest essential matrix to a matrix that is "almost" an essential matrix.
|
||||||
|
double a = svd.singularValues()(0);
|
||||||
|
double b = svd.singularValues()(1);
|
||||||
|
double s = (a + b) / 2.0;
|
||||||
|
LG << "Initial reconstruction's rotation is non-euclidean by "
|
||||||
|
<< (((a - b) / std::max(a, b)) * 100) << "%; singular values:"
|
||||||
|
<< svd.singularValues().transpose();
|
||||||
|
|
||||||
|
Vec3 diag;
|
||||||
|
diag << s, s, 0;
|
||||||
|
Mat3 E = svd.matrixU() * diag.asDiagonal() * svd.matrixV().transpose();
|
||||||
|
|
||||||
|
// Recover motion between the two images. Since this function assumes a
|
||||||
|
// calibrated camera, use the identity for K.
|
||||||
|
Mat3 R;
|
||||||
|
Vec3 t;
|
||||||
|
Mat3 K = Mat3::Identity();
|
||||||
|
if (!MotionFromEssentialAndCorrespondence(E,
|
||||||
|
K, x1.col(0),
|
||||||
|
K, x2.col(0),
|
||||||
|
&R, &t)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image 1 gets the reference frame, image 2 gets the relative motion.
|
||||||
|
reconstruction->InsertCamera(image1, Mat3::Identity(), Vec3::Zero());
|
||||||
|
reconstruction->InsertCamera(image2, R, t);
|
||||||
|
|
||||||
|
LG << "From two frame reconstruction got:\nR:\n" << R
|
||||||
|
<< "\nt:" << t.transpose();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Mat3 DecodeF(const Vec9 &encoded_F) {
|
||||||
|
// Decode F and force it to be rank 2.
|
||||||
|
Map<const Mat3> full_rank_F(encoded_F.data(), 3, 3);
|
||||||
|
Eigen::JacobiSVD<Mat3> svd(full_rank_F, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
||||||
|
Vec3 diagonal = svd.singularValues();
|
||||||
|
diagonal(2) = 0;
|
||||||
|
Mat3 F = svd.matrixU() * diagonal.asDiagonal() * svd.matrixV().transpose();
|
||||||
|
return F;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the stupidest way to refine F known to mankind, since it requires
|
||||||
|
// doing a full SVD of F at each iteration. This uses sampson error.
|
||||||
|
struct FundamentalSampsonCostFunction {
|
||||||
|
public:
|
||||||
|
typedef Vec FMatrixType;
|
||||||
|
typedef Vec9 XMatrixType;
|
||||||
|
|
||||||
|
// Assumes markers are ordered by track.
|
||||||
|
FundamentalSampsonCostFunction(const vector<Marker> &markers)
|
||||||
|
: markers(markers) {}
|
||||||
|
|
||||||
|
Vec operator()(const Vec9 &encoded_F) const {
|
||||||
|
// Decode F and force it to be rank 2.
|
||||||
|
Mat3 F = DecodeF(encoded_F);
|
||||||
|
|
||||||
|
Vec residuals(markers.size() / 2);
|
||||||
|
residuals.setZero();
|
||||||
|
for (int i = 0; i < markers.size() / 2; ++i) {
|
||||||
|
const Marker &marker1 = markers[2*i + 0];
|
||||||
|
const Marker &marker2 = markers[2*i + 1];
|
||||||
|
CHECK_EQ(marker1.track, marker2.track);
|
||||||
|
Vec2 x1(marker1.x, marker1.y);
|
||||||
|
Vec2 x2(marker2.x, marker2.y);
|
||||||
|
|
||||||
|
residuals[i] = SampsonDistance(F, x1, x2);
|
||||||
|
}
|
||||||
|
return residuals;
|
||||||
|
}
|
||||||
|
const vector<Marker> &markers;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool ProjectiveReconstructTwoFrames(const vector<Marker> &markers,
|
||||||
|
ProjectiveReconstruction *reconstruction) {
|
||||||
|
if (markers.size() < 16) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int image1, image2;
|
||||||
|
GetImagesInMarkers(markers, &image1, &image2);
|
||||||
|
|
||||||
|
Mat x1, x2;
|
||||||
|
CoordinatesForMarkersInImage(markers, image1, &x1);
|
||||||
|
CoordinatesForMarkersInImage(markers, image2, &x2);
|
||||||
|
|
||||||
|
Mat3 F;
|
||||||
|
NormalizedEightPointSolver(x1, x2, &F);
|
||||||
|
|
||||||
|
// XXX Verify sampson distance.
|
||||||
|
#if 0
|
||||||
|
// Refine the resulting projection fundamental matrix using Sampson's
|
||||||
|
// approximation of geometric error. This avoids having to do a full bundle
|
||||||
|
// at the cost of some accuracy.
|
||||||
|
//
|
||||||
|
// TODO(keir): After switching to a better bundling library, use a proper
|
||||||
|
// full bundle adjust here instead of this lame bundle adjustment.
|
||||||
|
typedef LevenbergMarquardt<FundamentalSampsonCostFunction> Solver;
|
||||||
|
|
||||||
|
FundamentalSampsonCostFunction fundamental_cost(markers);
|
||||||
|
|
||||||
|
// Pack the initial P matrix into a size-12 vector..
|
||||||
|
Vec9 encoded_F = Map<Vec9>(F.data(), 3, 3);
|
||||||
|
|
||||||
|
Solver solver(fundamental_cost);
|
||||||
|
|
||||||
|
Solver::SolverParameters params;
|
||||||
|
Solver::Results results = solver.minimize(params, &encoded_F);
|
||||||
|
// TODO(keir): Check results to ensure clean termination.
|
||||||
|
|
||||||
|
// Recover F from the minimization.
|
||||||
|
F = DecodeF(encoded_F);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Image 1 gets P = [I|0], image 2 gets arbitrary P.
|
||||||
|
Mat34 P1 = Mat34::Zero();
|
||||||
|
P1.block<3, 3>(0, 0) = Mat3::Identity();
|
||||||
|
Mat34 P2;
|
||||||
|
ProjectionsFromFundamental(F, &P1, &P2);
|
||||||
|
|
||||||
|
reconstruction->InsertCamera(image1, P1);
|
||||||
|
reconstruction->InsertCamera(image2, P2);
|
||||||
|
|
||||||
|
LG << "From two frame reconstruction got P2:\n" << P2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace libmv
|
||||||
74
extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
vendored
Normal file
74
extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H
|
||||||
|
#define LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
struct Marker;
|
||||||
|
class EuclideanReconstruction;
|
||||||
|
class ProjectiveReconstruction;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Initialize the \link EuclideanReconstruction reconstruction \endlink using
|
||||||
|
two frames.
|
||||||
|
|
||||||
|
\a markers should contain all \l Marker markers \endlink belonging to
|
||||||
|
tracks visible in both frames. The pose estimation of the camera for
|
||||||
|
these frames will be inserted into \a *reconstruction.
|
||||||
|
|
||||||
|
\note The two frames need to have both enough parallax and enough common tracks
|
||||||
|
for accurate reconstruction. At least 8 tracks are suggested.
|
||||||
|
\note The origin of the coordinate system is defined to be the camera of
|
||||||
|
the first keyframe.
|
||||||
|
\note This assumes a calibrated reconstruction, e.g. the markers are
|
||||||
|
already corrected for camera intrinsics and radial distortion.
|
||||||
|
\note This assumes an outlier-free set of markers.
|
||||||
|
|
||||||
|
\sa EuclideanResect, EuclideanIntersect, EuclideanBundle
|
||||||
|
*/
|
||||||
|
bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
|
||||||
|
EuclideanReconstruction *reconstruction);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Initialize the \link ProjectiveReconstruction reconstruction \endlink using
|
||||||
|
two frames.
|
||||||
|
|
||||||
|
\a markers should contain all \l Marker markers \endlink belonging to
|
||||||
|
tracks visible in both frames. An estimate of the projection matrices for
|
||||||
|
the two frames will get added to the reconstruction.
|
||||||
|
|
||||||
|
\note The two frames need to have both enough parallax and enough common tracks
|
||||||
|
for accurate reconstruction. At least 8 tracks are suggested.
|
||||||
|
\note The origin of the coordinate system is defined to be the camera of
|
||||||
|
the first keyframe.
|
||||||
|
\note This assumes the markers are already corrected for radial distortion.
|
||||||
|
\note This assumes an outlier-free set of markers.
|
||||||
|
|
||||||
|
\sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle
|
||||||
|
*/
|
||||||
|
bool ProjectiveReconstructTwoFrames(const vector<Marker> &markers,
|
||||||
|
ProjectiveReconstruction *reconstruction);
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H
|
||||||
205
extern/libmv/libmv/simple_pipeline/intersect.cc
vendored
Normal file
205
extern/libmv/libmv/simple_pipeline/intersect.cc
vendored
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
// 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/base/vector.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/multiview/triangulation.h"
|
||||||
|
#include "libmv/multiview/nviewtriangulation.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/numeric/levenberg_marquardt.h"
|
||||||
|
#include "libmv/simple_pipeline/reconstruction.h"
|
||||||
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct EuclideanIntersectCostFunction {
|
||||||
|
public:
|
||||||
|
typedef Vec FMatrixType;
|
||||||
|
typedef Vec3 XMatrixType;
|
||||||
|
|
||||||
|
EuclideanIntersectCostFunction(const vector<Marker> &markers,
|
||||||
|
const EuclideanReconstruction &reconstruction)
|
||||||
|
: markers(markers),
|
||||||
|
reconstruction(reconstruction) {}
|
||||||
|
|
||||||
|
Vec operator()(const Vec3 &X) const {
|
||||||
|
Vec residuals(2 * markers.size());
|
||||||
|
residuals.setZero();
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
const EuclideanCamera &camera =
|
||||||
|
*reconstruction.CameraForImage(markers[i].image);
|
||||||
|
Vec3 projected = camera.R * X + camera.t;
|
||||||
|
projected /= projected(2);
|
||||||
|
residuals[2*i + 0] = projected(0) - markers[i].x;
|
||||||
|
residuals[2*i + 1] = projected(1) - markers[i].y;
|
||||||
|
}
|
||||||
|
return residuals;
|
||||||
|
}
|
||||||
|
const vector<Marker> &markers;
|
||||||
|
const EuclideanReconstruction &reconstruction;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool EuclideanIntersect(const vector<Marker> &markers,
|
||||||
|
EuclideanReconstruction *reconstruction) {
|
||||||
|
if (markers.size() < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute projective camera matrices for the cameras the intersection is
|
||||||
|
// going to use.
|
||||||
|
Mat3 K = Mat3::Identity();
|
||||||
|
vector<Mat34> cameras;
|
||||||
|
Mat34 P;
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
|
||||||
|
P_From_KRt(K, camera->R, camera->t, &P);
|
||||||
|
cameras.push_back(P);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stack the 2D coordinates together as required by NViewTriangulate.
|
||||||
|
Mat2X points(2, markers.size());
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
points(0, i) = markers[i].x;
|
||||||
|
points(1, i) = markers[i].y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec4 Xp;
|
||||||
|
LG << "Intersecting with " << markers.size() << " markers.";
|
||||||
|
NViewTriangulateAlgebraic(points, cameras, &Xp);
|
||||||
|
|
||||||
|
// Get euclidean version of the homogeneous point.
|
||||||
|
Xp /= Xp(3);
|
||||||
|
Vec3 X = Xp.head<3>();
|
||||||
|
|
||||||
|
typedef LevenbergMarquardt<EuclideanIntersectCostFunction> Solver;
|
||||||
|
|
||||||
|
EuclideanIntersectCostFunction triangulate_cost(markers, *reconstruction);
|
||||||
|
Solver::SolverParameters params;
|
||||||
|
Solver solver(triangulate_cost);
|
||||||
|
|
||||||
|
Solver::Results results = solver.minimize(params, &X);
|
||||||
|
|
||||||
|
// Try projecting the point; make sure it's in front of everyone.
|
||||||
|
for (int i = 0; i < cameras.size(); ++i) {
|
||||||
|
const EuclideanCamera &camera =
|
||||||
|
*reconstruction->CameraForImage(markers[i].image);
|
||||||
|
Vec3 x = camera.R * X + camera.t;
|
||||||
|
if (x(2) < 0) {
|
||||||
|
LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
|
||||||
|
<< ": " << x.transpose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 point = X.head<3>();
|
||||||
|
reconstruction->InsertPoint(markers[0].track, point);
|
||||||
|
|
||||||
|
// TODO(keir): Add proper error checking.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct ProjectiveIntersectCostFunction {
|
||||||
|
public:
|
||||||
|
typedef Vec FMatrixType;
|
||||||
|
typedef Vec4 XMatrixType;
|
||||||
|
|
||||||
|
ProjectiveIntersectCostFunction(
|
||||||
|
const vector<Marker> &markers,
|
||||||
|
const ProjectiveReconstruction &reconstruction)
|
||||||
|
: markers(markers), reconstruction(reconstruction) {}
|
||||||
|
|
||||||
|
Vec operator()(const Vec4 &X) const {
|
||||||
|
Vec residuals(2 * markers.size());
|
||||||
|
residuals.setZero();
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
const ProjectiveCamera &camera =
|
||||||
|
*reconstruction.CameraForImage(markers[i].image);
|
||||||
|
Vec3 projected = camera.P * X;
|
||||||
|
projected /= projected(2);
|
||||||
|
residuals[2*i + 0] = projected(0) - markers[i].x;
|
||||||
|
residuals[2*i + 1] = projected(1) - markers[i].y;
|
||||||
|
}
|
||||||
|
return residuals;
|
||||||
|
}
|
||||||
|
const vector<Marker> &markers;
|
||||||
|
const ProjectiveReconstruction &reconstruction;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool ProjectiveIntersect(const vector<Marker> &markers,
|
||||||
|
ProjectiveReconstruction *reconstruction) {
|
||||||
|
if (markers.size() < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the cameras to use for the intersection.
|
||||||
|
vector<Mat34> cameras;
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
ProjectiveCamera *camera = reconstruction->CameraForImage(markers[i].image);
|
||||||
|
cameras.push_back(camera->P);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stack the 2D coordinates together as required by NViewTriangulate.
|
||||||
|
Mat2X points(2, markers.size());
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
points(0, i) = markers[i].x;
|
||||||
|
points(1, i) = markers[i].y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec4 X;
|
||||||
|
LG << "Intersecting with " << markers.size() << " markers.";
|
||||||
|
NViewTriangulateAlgebraic(points, cameras, &X);
|
||||||
|
X /= X(3);
|
||||||
|
|
||||||
|
typedef LevenbergMarquardt<ProjectiveIntersectCostFunction> Solver;
|
||||||
|
|
||||||
|
ProjectiveIntersectCostFunction triangulate_cost(markers, *reconstruction);
|
||||||
|
Solver::SolverParameters params;
|
||||||
|
Solver solver(triangulate_cost);
|
||||||
|
|
||||||
|
Solver::Results results = solver.minimize(params, &X);
|
||||||
|
(void) results; // TODO(keir): Ensure results are good.
|
||||||
|
|
||||||
|
// Try projecting the point; make sure it's in front of everyone.
|
||||||
|
for (int i = 0; i < cameras.size(); ++i) {
|
||||||
|
const ProjectiveCamera &camera =
|
||||||
|
*reconstruction->CameraForImage(markers[i].image);
|
||||||
|
Vec3 x = camera.P * X;
|
||||||
|
if (x(2) < 0) {
|
||||||
|
LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
|
||||||
|
<< ": " << x.transpose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reconstruction->InsertPoint(markers[0].track, X);
|
||||||
|
|
||||||
|
// TODO(keir): Add proper error checking.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
77
extern/libmv/libmv/simple_pipeline/intersect.h
vendored
Normal file
77
extern/libmv/libmv/simple_pipeline/intersect.h
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_SIMPLE_PIPELINE_INTERSECT_H
|
||||||
|
#define LIBMV_SIMPLE_PIPELINE_INTERSECT_H
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
|
#include "libmv/simple_pipeline/reconstruction.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Estimate the 3D coordinates of a track by intersecting rays from images.
|
||||||
|
|
||||||
|
This takes a set of markers, where each marker is for the same track but
|
||||||
|
different images, and reconstructs the 3D position of that track. Each of
|
||||||
|
the frames for which there is a marker for that track must have a
|
||||||
|
corresponding reconstructed camera in \a *reconstruction.
|
||||||
|
|
||||||
|
\a markers should contain all \l Marker markers \endlink belonging to
|
||||||
|
tracks visible in all frames.
|
||||||
|
\a reconstruction should contain the cameras for all frames.
|
||||||
|
The new \l Point points \endlink will be inserted in \a reconstruction.
|
||||||
|
|
||||||
|
\note This assumes a calibrated reconstruction, e.g. the markers are
|
||||||
|
already corrected for camera intrinsics and radial distortion.
|
||||||
|
\note This assumes an outlier-free set of markers.
|
||||||
|
|
||||||
|
\sa EuclideanResect
|
||||||
|
*/
|
||||||
|
bool EuclideanIntersect(const vector<Marker> &markers,
|
||||||
|
EuclideanReconstruction *reconstruction);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Estimate the homogeneous coordinates of a track by intersecting rays.
|
||||||
|
|
||||||
|
This takes a set of markers, where each marker is for the same track but
|
||||||
|
different images, and reconstructs the homogeneous 3D position of that
|
||||||
|
track. Each of the frames for which there is a marker for that track must
|
||||||
|
have a corresponding reconstructed camera in \a *reconstruction.
|
||||||
|
|
||||||
|
\a markers should contain all \l Marker markers \endlink belonging to
|
||||||
|
tracks visible in all frames.
|
||||||
|
\a reconstruction should contain the cameras for all frames.
|
||||||
|
The new \l Point points \endlink will be inserted in \a reconstruction.
|
||||||
|
|
||||||
|
\note This assumes that radial distortion is already corrected for, but
|
||||||
|
does not assume that e.g. focal length and principal point are
|
||||||
|
accounted for.
|
||||||
|
\note This assumes an outlier-free set of markers.
|
||||||
|
|
||||||
|
\sa Resect
|
||||||
|
*/
|
||||||
|
bool ProjectiveIntersect(const vector<Marker> &markers,
|
||||||
|
ProjectiveReconstruction *reconstruction);
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_SIMPLE_PIPELINE_INTERSECT_H
|
||||||
317
extern/libmv/libmv/simple_pipeline/pipeline.cc
vendored
Normal file
317
extern/libmv/libmv/simple_pipeline/pipeline.cc
vendored
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
// 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 <cstdio>
|
||||||
|
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/simple_pipeline/bundle.h"
|
||||||
|
#include "libmv/simple_pipeline/intersect.h"
|
||||||
|
#include "libmv/simple_pipeline/resect.h"
|
||||||
|
#include "libmv/simple_pipeline/reconstruction.h"
|
||||||
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
|
#include "libmv/simple_pipeline/camera_intrinsics.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// These are "strategy" classes which make it possible to use the same code for
|
||||||
|
// both projective and euclidean reconstruction.
|
||||||
|
// FIXME(MatthiasF): OOP would achieve the same goal while avoiding
|
||||||
|
// template bloat and making interface changes much easier.
|
||||||
|
struct EuclideanPipelineRoutines {
|
||||||
|
typedef EuclideanReconstruction Reconstruction;
|
||||||
|
typedef EuclideanCamera Camera;
|
||||||
|
typedef EuclideanPoint Point;
|
||||||
|
|
||||||
|
static void Bundle(const Tracks &tracks,
|
||||||
|
EuclideanReconstruction *reconstruction) {
|
||||||
|
EuclideanBundle(tracks, reconstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Resect(const vector<Marker> &markers,
|
||||||
|
EuclideanReconstruction *reconstruction, bool final_pass) {
|
||||||
|
return EuclideanResect(markers, reconstruction, final_pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Intersect(const vector<Marker> &markers,
|
||||||
|
EuclideanReconstruction *reconstruction) {
|
||||||
|
return EuclideanIntersect(markers, reconstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Marker ProjectMarker(const EuclideanPoint &point,
|
||||||
|
const EuclideanCamera &camera,
|
||||||
|
const CameraIntrinsics &intrinsics) {
|
||||||
|
Vec3 projected = camera.R * point.X + camera.t;
|
||||||
|
projected /= projected(2);
|
||||||
|
|
||||||
|
Marker reprojected_marker;
|
||||||
|
intrinsics.ApplyIntrinsics(projected(0),
|
||||||
|
projected(1),
|
||||||
|
&reprojected_marker.x,
|
||||||
|
&reprojected_marker.y);
|
||||||
|
|
||||||
|
reprojected_marker.image = camera.image;
|
||||||
|
reprojected_marker.track = point.track;
|
||||||
|
return reprojected_marker;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProjectivePipelineRoutines {
|
||||||
|
typedef ProjectiveReconstruction Reconstruction;
|
||||||
|
typedef ProjectiveCamera Camera;
|
||||||
|
typedef ProjectivePoint Point;
|
||||||
|
|
||||||
|
static void Bundle(const Tracks &tracks,
|
||||||
|
ProjectiveReconstruction *reconstruction) {
|
||||||
|
ProjectiveBundle(tracks, reconstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Resect(const vector<Marker> &markers,
|
||||||
|
ProjectiveReconstruction *reconstruction, bool final_pass) {
|
||||||
|
return ProjectiveResect(markers, reconstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Intersect(const vector<Marker> &markers,
|
||||||
|
ProjectiveReconstruction *reconstruction) {
|
||||||
|
return ProjectiveIntersect(markers, reconstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Marker ProjectMarker(const ProjectivePoint &point,
|
||||||
|
const ProjectiveCamera &camera,
|
||||||
|
const CameraIntrinsics &intrinsics) {
|
||||||
|
Vec3 projected = camera.P * point.X;
|
||||||
|
projected /= projected(2);
|
||||||
|
|
||||||
|
Marker reprojected_marker;
|
||||||
|
intrinsics.ApplyIntrinsics(projected(0),
|
||||||
|
projected(1),
|
||||||
|
&reprojected_marker.x,
|
||||||
|
&reprojected_marker.y);
|
||||||
|
|
||||||
|
reprojected_marker.image = camera.image;
|
||||||
|
reprojected_marker.track = point.track;
|
||||||
|
return reprojected_marker;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
template<typename PipelineRoutines>
|
||||||
|
void InternalCompleteReconstruction(
|
||||||
|
const Tracks &tracks,
|
||||||
|
typename PipelineRoutines::Reconstruction *reconstruction) {
|
||||||
|
int max_track = tracks.MaxTrack();
|
||||||
|
int max_image = tracks.MaxImage();
|
||||||
|
int num_resects = -1;
|
||||||
|
int num_intersects = -1;
|
||||||
|
LG << "Max track: " << max_track;
|
||||||
|
LG << "Max image: " << max_image;
|
||||||
|
LG << "Number of markers: " << tracks.NumMarkers();
|
||||||
|
while (num_resects != 0 || num_intersects != 0) {
|
||||||
|
// Do all possible intersections.
|
||||||
|
num_intersects = 0;
|
||||||
|
for (int track = 0; track <= max_track; ++track) {
|
||||||
|
if (reconstruction->PointForTrack(track)) {
|
||||||
|
LG << "Skipping point: " << track;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vector<Marker> all_markers = tracks.MarkersForTrack(track);
|
||||||
|
LG << "Got " << all_markers.size() << " markers for track " << track;
|
||||||
|
|
||||||
|
vector<Marker> reconstructed_markers;
|
||||||
|
for (int i = 0; i < all_markers.size(); ++i) {
|
||||||
|
if (reconstruction->CameraForImage(all_markers[i].image)) {
|
||||||
|
reconstructed_markers.push_back(all_markers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LG << "Got " << reconstructed_markers.size()
|
||||||
|
<< " reconstructed markers for track " << track;
|
||||||
|
if (reconstructed_markers.size() >= 2) {
|
||||||
|
PipelineRoutines::Intersect(reconstructed_markers, reconstruction);
|
||||||
|
num_intersects++;
|
||||||
|
LG << "Ran Intersect() for track " << track;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_intersects) {
|
||||||
|
PipelineRoutines::Bundle(tracks, reconstruction);
|
||||||
|
LG << "Ran Bundle() after intersections.";
|
||||||
|
}
|
||||||
|
LG << "Did " << num_intersects << " intersects.";
|
||||||
|
|
||||||
|
// Do all possible resections.
|
||||||
|
num_resects = 0;
|
||||||
|
for (int image = 0; image <= max_image; ++image) {
|
||||||
|
if (reconstruction->CameraForImage(image)) {
|
||||||
|
LG << "Skipping frame: " << image;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vector<Marker> all_markers = tracks.MarkersInImage(image);
|
||||||
|
LG << "Got " << all_markers.size() << " markers for image " << image;
|
||||||
|
|
||||||
|
vector<Marker> reconstructed_markers;
|
||||||
|
for (int i = 0; i < all_markers.size(); ++i) {
|
||||||
|
if (reconstruction->PointForTrack(all_markers[i].track)) {
|
||||||
|
reconstructed_markers.push_back(all_markers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LG << "Got " << reconstructed_markers.size()
|
||||||
|
<< " reconstructed markers for image " << image;
|
||||||
|
if (reconstructed_markers.size() >= 5) {
|
||||||
|
if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, false)) {
|
||||||
|
num_resects++;
|
||||||
|
LG << "Ran Resect() for image " << image;
|
||||||
|
} else {
|
||||||
|
LG << "Failed Resect() for image " << image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_resects) {
|
||||||
|
PipelineRoutines::Bundle(tracks, reconstruction);
|
||||||
|
}
|
||||||
|
LG << "Did " << num_resects << " resects.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// One last pass...
|
||||||
|
num_resects = 0;
|
||||||
|
for (int image = 0; image <= max_image; ++image) {
|
||||||
|
if (reconstruction->CameraForImage(image)) {
|
||||||
|
LG << "Skipping frame: " << image;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vector<Marker> all_markers = tracks.MarkersInImage(image);
|
||||||
|
|
||||||
|
vector<Marker> reconstructed_markers;
|
||||||
|
for (int i = 0; i < all_markers.size(); ++i) {
|
||||||
|
if (reconstruction->PointForTrack(all_markers[i].track)) {
|
||||||
|
reconstructed_markers.push_back(all_markers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reconstructed_markers.size() >= 5) {
|
||||||
|
if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, true)) {
|
||||||
|
num_resects++;
|
||||||
|
LG << "Ran Resect() for image " << image;
|
||||||
|
} else {
|
||||||
|
LG << "Failed Resect() for image " << image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_resects) {
|
||||||
|
PipelineRoutines::Bundle(tracks, reconstruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename PipelineRoutines>
|
||||||
|
double InternalReprojectionError(const Tracks &image_tracks,
|
||||||
|
const typename PipelineRoutines::Reconstruction &reconstruction,
|
||||||
|
const CameraIntrinsics &intrinsics) {
|
||||||
|
int num_skipped = 0;
|
||||||
|
int num_reprojected = 0;
|
||||||
|
double total_error = 0.0;
|
||||||
|
vector<Marker> markers = image_tracks.AllMarkers();
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
const typename PipelineRoutines::Camera *camera =
|
||||||
|
reconstruction.CameraForImage(markers[i].image);
|
||||||
|
const typename PipelineRoutines::Point *point =
|
||||||
|
reconstruction.PointForTrack(markers[i].track);
|
||||||
|
if (!camera || !point) {
|
||||||
|
num_skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
num_reprojected++;
|
||||||
|
|
||||||
|
Marker reprojected_marker =
|
||||||
|
PipelineRoutines::ProjectMarker(*point, *camera, intrinsics);
|
||||||
|
double ex = reprojected_marker.x - markers[i].x;
|
||||||
|
double ey = reprojected_marker.y - markers[i].y;
|
||||||
|
|
||||||
|
const int N = 100;
|
||||||
|
char line[N];
|
||||||
|
snprintf(line, N,
|
||||||
|
"image %-3d track %-3d "
|
||||||
|
"x %7.1f y %7.1f "
|
||||||
|
"rx %7.1f ry %7.1f "
|
||||||
|
"ex %7.1f ey %7.1f"
|
||||||
|
" e %7.1f",
|
||||||
|
markers[i].image,
|
||||||
|
markers[i].track,
|
||||||
|
markers[i].x,
|
||||||
|
markers[i].y,
|
||||||
|
reprojected_marker.x,
|
||||||
|
reprojected_marker.y,
|
||||||
|
ex,
|
||||||
|
ey,
|
||||||
|
sqrt(ex*ex + ey*ey));
|
||||||
|
//LG << line;
|
||||||
|
total_error += sqrt(ex*ex + ey*ey);
|
||||||
|
}
|
||||||
|
LG << "Skipped " << num_skipped << " markers.";
|
||||||
|
LG << "Reprojected " << num_reprojected << " markers.";
|
||||||
|
LG << "Total error: " << total_error;
|
||||||
|
LG << "Average error: " << (total_error / num_reprojected) << " [pixels].";
|
||||||
|
return total_error / num_reprojected;
|
||||||
|
}
|
||||||
|
|
||||||
|
double EuclideanReprojectionError(const Tracks &image_tracks,
|
||||||
|
const EuclideanReconstruction &reconstruction,
|
||||||
|
const CameraIntrinsics &intrinsics) {
|
||||||
|
return InternalReprojectionError<EuclideanPipelineRoutines>(image_tracks,
|
||||||
|
reconstruction,
|
||||||
|
intrinsics);
|
||||||
|
}
|
||||||
|
|
||||||
|
double ProjectiveReprojectionError(
|
||||||
|
const Tracks &image_tracks,
|
||||||
|
const ProjectiveReconstruction &reconstruction,
|
||||||
|
const CameraIntrinsics &intrinsics) {
|
||||||
|
return InternalReprojectionError<ProjectivePipelineRoutines>(image_tracks,
|
||||||
|
reconstruction,
|
||||||
|
intrinsics);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EuclideanCompleteReconstruction(const Tracks &tracks,
|
||||||
|
EuclideanReconstruction *reconstruction) {
|
||||||
|
InternalCompleteReconstruction<EuclideanPipelineRoutines>(tracks,
|
||||||
|
reconstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectiveCompleteReconstruction(const Tracks &tracks,
|
||||||
|
ProjectiveReconstruction *reconstruction) {
|
||||||
|
InternalCompleteReconstruction<ProjectivePipelineRoutines>(tracks,
|
||||||
|
reconstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
|
||||||
|
const CameraIntrinsics &camera_intrinsics,
|
||||||
|
Tracks *calibrated_tracks) {
|
||||||
|
vector<Marker> markers = raw_tracks.AllMarkers();
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
camera_intrinsics.InvertIntrinsics(markers[i].x,
|
||||||
|
markers[i].y,
|
||||||
|
&(markers[i].x),
|
||||||
|
&(markers[i].y));
|
||||||
|
}
|
||||||
|
*calibrated_tracks = Tracks(markers);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
95
extern/libmv/libmv/simple_pipeline/pipeline.h
vendored
Normal file
95
extern/libmv/libmv/simple_pipeline/pipeline.h
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
|
||||||
|
#define LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
|
#include "libmv/simple_pipeline/reconstruction.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Estimate camera poses and scene 3D coordinates for all frames and tracks.
|
||||||
|
|
||||||
|
This method should be used once there is an initial reconstruction in
|
||||||
|
place, for example by reconstructing from two frames that have a sufficient
|
||||||
|
baseline and number of tracks in common. This function iteratively
|
||||||
|
triangulates points that are visible by cameras that have their pose
|
||||||
|
estimated, then resections (i.e. estimates the pose) of cameras that are
|
||||||
|
not estimated yet that can see triangulated points. This process is
|
||||||
|
repeated until all points and cameras are estimated. Periodically, bundle
|
||||||
|
adjustment is run to ensure a quality reconstruction.
|
||||||
|
|
||||||
|
\a tracks should contain markers used in the reconstruction.
|
||||||
|
\a reconstruction should contain at least some 3D points or some estimated
|
||||||
|
cameras. The minimum number of cameras is two (with no 3D points) and the
|
||||||
|
minimum number of 3D points (with no estimated cameras) is 5.
|
||||||
|
|
||||||
|
\sa EuclideanResect, EuclideanIntersect, EuclideanBundle
|
||||||
|
*/
|
||||||
|
void EuclideanCompleteReconstruction(const Tracks &tracks,
|
||||||
|
EuclideanReconstruction *reconstruction);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Estimate camera matrices and homogeneous 3D coordinates for all frames and
|
||||||
|
tracks.
|
||||||
|
|
||||||
|
This method should be used once there is an initial reconstruction in
|
||||||
|
place, for example by reconstructing from two frames that have a sufficient
|
||||||
|
baseline and number of tracks in common. This function iteratively
|
||||||
|
triangulates points that are visible by cameras that have their pose
|
||||||
|
estimated, then resections (i.e. estimates the pose) of cameras that are
|
||||||
|
not estimated yet that can see triangulated points. This process is
|
||||||
|
repeated until all points and cameras are estimated. Periodically, bundle
|
||||||
|
adjustment is run to ensure a quality reconstruction.
|
||||||
|
|
||||||
|
\a tracks should contain markers used in the reconstruction.
|
||||||
|
\a reconstruction should contain at least some 3D points or some estimated
|
||||||
|
cameras. The minimum number of cameras is two (with no 3D points) and the
|
||||||
|
minimum number of 3D points (with no estimated cameras) is 5.
|
||||||
|
|
||||||
|
\sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle
|
||||||
|
*/
|
||||||
|
void ProjectiveCompleteReconstruction(const Tracks &tracks,
|
||||||
|
ProjectiveReconstruction *reconstruction);
|
||||||
|
|
||||||
|
|
||||||
|
class CameraIntrinsics;
|
||||||
|
|
||||||
|
// TODO(keir): Decide if we want these in the public API, and if so, what the
|
||||||
|
// appropriate include file is.
|
||||||
|
|
||||||
|
double EuclideanReprojectionError(const Tracks &image_tracks,
|
||||||
|
const EuclideanReconstruction &reconstruction,
|
||||||
|
const CameraIntrinsics &intrinsics);
|
||||||
|
|
||||||
|
double ProjectiveReprojectionError(
|
||||||
|
const Tracks &image_tracks,
|
||||||
|
const ProjectiveReconstruction &reconstruction,
|
||||||
|
const CameraIntrinsics &intrinsics);
|
||||||
|
|
||||||
|
void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
|
||||||
|
const CameraIntrinsics &camera_intrinsics,
|
||||||
|
Tracks *calibrated_tracks);
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
|
||||||
191
extern/libmv/libmv/simple_pipeline/reconstruction.cc
vendored
Normal file
191
extern/libmv/libmv/simple_pipeline/reconstruction.cc
vendored
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/reconstruction.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
EuclideanReconstruction::EuclideanReconstruction() {}
|
||||||
|
EuclideanReconstruction::EuclideanReconstruction(
|
||||||
|
const EuclideanReconstruction &other) {
|
||||||
|
cameras_ = other.cameras_;
|
||||||
|
points_ = other.points_;
|
||||||
|
}
|
||||||
|
|
||||||
|
EuclideanReconstruction &EuclideanReconstruction::operator=(
|
||||||
|
const EuclideanReconstruction &other) {
|
||||||
|
if (&other != this) {
|
||||||
|
cameras_ = other.cameras_;
|
||||||
|
points_ = other.points_;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EuclideanReconstruction::InsertCamera(int image,
|
||||||
|
const Mat3 &R,
|
||||||
|
const Vec3 &t) {
|
||||||
|
LG << "InsertCamera " << image << ":\nR:\n"<< R << "\nt:\n" << t;
|
||||||
|
if (image >= cameras_.size()) {
|
||||||
|
cameras_.resize(image + 1);
|
||||||
|
}
|
||||||
|
cameras_[image].image = image;
|
||||||
|
cameras_[image].R = R;
|
||||||
|
cameras_[image].t = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) {
|
||||||
|
LG << "InsertPoint " << track << ":\n" << X;
|
||||||
|
if (track >= points_.size()) {
|
||||||
|
points_.resize(track + 1);
|
||||||
|
}
|
||||||
|
points_[track].track = track;
|
||||||
|
points_[track].X = X;
|
||||||
|
}
|
||||||
|
|
||||||
|
EuclideanCamera *EuclideanReconstruction::CameraForImage(int image) {
|
||||||
|
return const_cast<EuclideanCamera *>(
|
||||||
|
static_cast<const EuclideanReconstruction *>(
|
||||||
|
this)->CameraForImage(image));
|
||||||
|
}
|
||||||
|
|
||||||
|
const EuclideanCamera *EuclideanReconstruction::CameraForImage(
|
||||||
|
int image) const {
|
||||||
|
if (image < 0 || image >= cameras_.size()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const EuclideanCamera *camera = &cameras_[image];
|
||||||
|
if (camera->image == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<EuclideanCamera> EuclideanReconstruction::AllCameras() const {
|
||||||
|
vector<EuclideanCamera> cameras;
|
||||||
|
for (int i = 0; i < cameras_.size(); ++i) {
|
||||||
|
if (cameras_[i].image != -1) {
|
||||||
|
cameras.push_back(cameras_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cameras;
|
||||||
|
}
|
||||||
|
|
||||||
|
EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) {
|
||||||
|
return const_cast<EuclideanPoint *>(
|
||||||
|
static_cast<const EuclideanReconstruction *>(this)->PointForTrack(track));
|
||||||
|
}
|
||||||
|
|
||||||
|
const EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) const {
|
||||||
|
if (track < 0 || track >= points_.size()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const EuclideanPoint *point = &points_[track];
|
||||||
|
if (point->track == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<EuclideanPoint> EuclideanReconstruction::AllPoints() const {
|
||||||
|
vector<EuclideanPoint> points;
|
||||||
|
for (int i = 0; i < points_.size(); ++i) {
|
||||||
|
if (points_[i].track != -1) {
|
||||||
|
points.push_back(points_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectiveReconstruction::InsertCamera(int image,
|
||||||
|
const Mat34 &P) {
|
||||||
|
LG << "InsertCamera " << image << ":\nP:\n"<< P;
|
||||||
|
if (image >= cameras_.size()) {
|
||||||
|
cameras_.resize(image + 1);
|
||||||
|
}
|
||||||
|
cameras_[image].image = image;
|
||||||
|
cameras_[image].P = P;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) {
|
||||||
|
LG << "InsertPoint " << track << ":\n" << X;
|
||||||
|
if (track >= points_.size()) {
|
||||||
|
points_.resize(track + 1);
|
||||||
|
}
|
||||||
|
points_[track].track = track;
|
||||||
|
points_[track].X = X;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectiveCamera *ProjectiveReconstruction::CameraForImage(int image) {
|
||||||
|
return const_cast<ProjectiveCamera *>(
|
||||||
|
static_cast<const ProjectiveReconstruction *>(
|
||||||
|
this)->CameraForImage(image));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectiveCamera *ProjectiveReconstruction::CameraForImage(
|
||||||
|
int image) const {
|
||||||
|
if (image < 0 || image >= cameras_.size()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const ProjectiveCamera *camera = &cameras_[image];
|
||||||
|
if (camera->image == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<ProjectiveCamera> ProjectiveReconstruction::AllCameras() const {
|
||||||
|
vector<ProjectiveCamera> cameras;
|
||||||
|
for (int i = 0; i < cameras_.size(); ++i) {
|
||||||
|
if (cameras_[i].image != -1) {
|
||||||
|
cameras.push_back(cameras_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cameras;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) {
|
||||||
|
return const_cast<ProjectivePoint *>(
|
||||||
|
static_cast<const ProjectiveReconstruction *>(this)->PointForTrack(track));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) const {
|
||||||
|
if (track < 0 || track >= points_.size()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const ProjectivePoint *point = &points_[track];
|
||||||
|
if (point->track == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<ProjectivePoint> ProjectiveReconstruction::AllPoints() const {
|
||||||
|
vector<ProjectivePoint> points;
|
||||||
|
for (int i = 0; i < points_.size(); ++i) {
|
||||||
|
if (points_[i].track != -1) {
|
||||||
|
points.push_back(points_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
217
extern/libmv/libmv/simple_pipeline/reconstruction.h
vendored
Normal file
217
extern/libmv/libmv/simple_pipeline/reconstruction.h
vendored
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
|
||||||
|
#define LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A EuclideanCamera is the location and rotation of the camera viewing \a image.
|
||||||
|
|
||||||
|
\a image identify which image from \l Tracks this camera represents.
|
||||||
|
\a R is a 3x3 matrix representing the rotation of the camera.
|
||||||
|
\a t is a translation vector representing its positions.
|
||||||
|
|
||||||
|
\sa Reconstruction
|
||||||
|
*/
|
||||||
|
struct EuclideanCamera {
|
||||||
|
EuclideanCamera() : image(-1) {}
|
||||||
|
EuclideanCamera(const EuclideanCamera &c) : image(c.image), R(c.R), t(c.t) {}
|
||||||
|
|
||||||
|
int image;
|
||||||
|
Mat3 R;
|
||||||
|
Vec3 t;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A Point is the 3D location of a track.
|
||||||
|
|
||||||
|
\a track identify which track from \l Tracks this point corresponds to.
|
||||||
|
\a X represents the 3D position of the track.
|
||||||
|
|
||||||
|
\sa Reconstruction
|
||||||
|
*/
|
||||||
|
struct EuclideanPoint {
|
||||||
|
EuclideanPoint() : track(-1) {}
|
||||||
|
EuclideanPoint(const EuclideanPoint &p) : track(p.track), X(p.X) {}
|
||||||
|
int track;
|
||||||
|
Vec3 X;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The EuclideanReconstruction class stores \link EuclideanCamera cameras
|
||||||
|
\endlink and \link EuclideanPoint points \endlink.
|
||||||
|
|
||||||
|
The EuclideanReconstruction container is intended as the store of 3D
|
||||||
|
reconstruction data to be used with the MultiView API.
|
||||||
|
|
||||||
|
The container has lookups to query a \a EuclideanCamera from an \a image or
|
||||||
|
a \a EuclideanPoint from a \a track.
|
||||||
|
|
||||||
|
\sa Camera, Point
|
||||||
|
*/
|
||||||
|
class EuclideanReconstruction {
|
||||||
|
public:
|
||||||
|
// Default constructor starts with no cameras.
|
||||||
|
EuclideanReconstruction();
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
EuclideanReconstruction(const EuclideanReconstruction &other);
|
||||||
|
|
||||||
|
EuclideanReconstruction &operator=(const EuclideanReconstruction &other);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Insert a camera into the set. If there is already a camera for the given
|
||||||
|
\a image, the existing camera is replaced. If there is no camera for the
|
||||||
|
given \a image, a new one is added.
|
||||||
|
|
||||||
|
\a image is the key used to retrieve the cameras with the other methods
|
||||||
|
in this class.
|
||||||
|
|
||||||
|
\note You should use the same \a image identifier as in \l Tracks.
|
||||||
|
*/
|
||||||
|
void InsertCamera(int image, const Mat3 &R, const Vec3 &t);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Insert a point into the reconstruction. If there is already a point for
|
||||||
|
the given \a track, the existing point is replaced. If there is no point
|
||||||
|
for the given \a track, a new one is added.
|
||||||
|
|
||||||
|
\a track is the key used to retrieve the points with the
|
||||||
|
other methods in this class.
|
||||||
|
|
||||||
|
\note You should use the same \a track identifier as in \l Tracks.
|
||||||
|
*/
|
||||||
|
void InsertPoint(int track, const Vec3 &X);
|
||||||
|
|
||||||
|
/// Returns a pointer to the camera corresponding to \a image.
|
||||||
|
EuclideanCamera *CameraForImage(int image);
|
||||||
|
const EuclideanCamera *CameraForImage(int image) const;
|
||||||
|
|
||||||
|
/// Returns all cameras.
|
||||||
|
vector<EuclideanCamera> AllCameras() const;
|
||||||
|
|
||||||
|
/// Returns a pointer to the point corresponding to \a track.
|
||||||
|
EuclideanPoint *PointForTrack(int track);
|
||||||
|
const EuclideanPoint *PointForTrack(int track) const;
|
||||||
|
|
||||||
|
/// Returns all points.
|
||||||
|
vector<EuclideanPoint> AllPoints() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<EuclideanCamera> cameras_;
|
||||||
|
vector<EuclideanPoint> points_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A ProjectiveCamera is the projection matrix for the camera of \a image.
|
||||||
|
|
||||||
|
\a image identify which image from \l Tracks this camera represents.
|
||||||
|
\a P is the 3x4 projection matrix.
|
||||||
|
|
||||||
|
\sa ProjectiveReconstruction
|
||||||
|
*/
|
||||||
|
struct ProjectiveCamera {
|
||||||
|
ProjectiveCamera() : image(-1) {}
|
||||||
|
ProjectiveCamera(const ProjectiveCamera &c) : image(c.image), P(c.P) {}
|
||||||
|
|
||||||
|
int image;
|
||||||
|
Mat34 P;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A Point is the 3D location of a track.
|
||||||
|
|
||||||
|
\a track identifies which track from \l Tracks this point corresponds to.
|
||||||
|
\a X is the homogeneous 3D position of the track.
|
||||||
|
|
||||||
|
\sa Reconstruction
|
||||||
|
*/
|
||||||
|
struct ProjectivePoint {
|
||||||
|
ProjectivePoint() : track(-1) {}
|
||||||
|
ProjectivePoint(const ProjectivePoint &p) : track(p.track), X(p.X) {}
|
||||||
|
int track;
|
||||||
|
Vec4 X;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The ProjectiveReconstruction class stores \link ProjectiveCamera cameras
|
||||||
|
\endlink and \link ProjectivePoint points \endlink.
|
||||||
|
|
||||||
|
The ProjectiveReconstruction container is intended as the store of 3D
|
||||||
|
reconstruction data to be used with the MultiView API.
|
||||||
|
|
||||||
|
The container has lookups to query a \a ProjectiveCamera from an \a image or
|
||||||
|
a \a ProjectivePoint from a \a track.
|
||||||
|
|
||||||
|
\sa Camera, Point
|
||||||
|
*/
|
||||||
|
class ProjectiveReconstruction {
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
Insert a camera into the set. If there is already a camera for the given
|
||||||
|
\a image, the existing camera is replaced. If there is no camera for the
|
||||||
|
given \a image, a new one is added.
|
||||||
|
|
||||||
|
\a image is the key used to retrieve the cameras with the other methods
|
||||||
|
in this class.
|
||||||
|
|
||||||
|
\note You should use the same \a image identifier as in \l Tracks.
|
||||||
|
*/
|
||||||
|
void InsertCamera(int image, const Mat34 &P);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Insert a point into the reconstruction. If there is already a point for
|
||||||
|
the given \a track, the existing point is replaced. If there is no point
|
||||||
|
for the given \a track, a new one is added.
|
||||||
|
|
||||||
|
\a track is the key used to retrieve the points with the
|
||||||
|
other methods in this class.
|
||||||
|
|
||||||
|
\note You should use the same \a track identifier as in \l Tracks.
|
||||||
|
*/
|
||||||
|
void InsertPoint(int track, const Vec4 &X);
|
||||||
|
|
||||||
|
/// Returns a pointer to the camera corresponding to \a image.
|
||||||
|
ProjectiveCamera *CameraForImage(int image);
|
||||||
|
const ProjectiveCamera *CameraForImage(int image) const;
|
||||||
|
|
||||||
|
/// Returns all cameras.
|
||||||
|
vector<ProjectiveCamera> AllCameras() const;
|
||||||
|
|
||||||
|
/// Returns a pointer to the point corresponding to \a track.
|
||||||
|
ProjectivePoint *PointForTrack(int track);
|
||||||
|
const ProjectivePoint *PointForTrack(int track) const;
|
||||||
|
|
||||||
|
/// Returns all points.
|
||||||
|
vector<ProjectivePoint> AllPoints() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<ProjectiveCamera> cameras_;
|
||||||
|
vector<ProjectivePoint> points_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
|
||||||
271
extern/libmv/libmv/simple_pipeline/resect.cc
vendored
Normal file
271
extern/libmv/libmv/simple_pipeline/resect.cc
vendored
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
// 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 <cstdio>
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/multiview/euclidean_resection.h"
|
||||||
|
#include "libmv/multiview/resection.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/numeric/levenberg_marquardt.h"
|
||||||
|
#include "libmv/simple_pipeline/reconstruction.h"
|
||||||
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Mat2X PointMatrixFromMarkers(const vector<Marker> &markers) {
|
||||||
|
Mat2X points(2, markers.size());
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
points(0, i) = markers[i].x;
|
||||||
|
points(1, i) = markers[i].y;
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat3 RotationFromEulerVector(Vec3 euler_vector) {
|
||||||
|
double theta = euler_vector.norm();
|
||||||
|
if (theta == 0.0) {
|
||||||
|
return Mat3::Identity();
|
||||||
|
}
|
||||||
|
Vec3 w = euler_vector / theta;
|
||||||
|
Mat3 w_hat = CrossProductMatrix(w);
|
||||||
|
return Mat3::Identity() + w_hat*sin(theta) + w_hat*w_hat*(1 - cos(theta));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uses an incremental rotation:
|
||||||
|
//
|
||||||
|
// x = R' * R * X + t;
|
||||||
|
//
|
||||||
|
// to avoid issues with the rotation representation. R' is derived from a
|
||||||
|
// euler vector encoding the rotation in 3 parameters; the direction is the
|
||||||
|
// axis to rotate around and the magnitude is the amount of the rotation.
|
||||||
|
struct EuclideanResectCostFunction {
|
||||||
|
public:
|
||||||
|
typedef Vec FMatrixType;
|
||||||
|
typedef Vec6 XMatrixType;
|
||||||
|
|
||||||
|
EuclideanResectCostFunction(const vector<Marker> &markers,
|
||||||
|
const EuclideanReconstruction &reconstruction,
|
||||||
|
const Mat3 initial_R)
|
||||||
|
: markers(markers),
|
||||||
|
reconstruction(reconstruction),
|
||||||
|
initial_R(initial_R) {}
|
||||||
|
|
||||||
|
// dRt has dR (delta R) encoded as a euler vector in the first 3 parameters,
|
||||||
|
// followed by t in the next 3 parameters.
|
||||||
|
Vec operator()(const Vec6 &dRt) const {
|
||||||
|
// Unpack R, t from dRt.
|
||||||
|
Mat3 R = RotationFromEulerVector(dRt.head<3>()) * initial_R;
|
||||||
|
Vec3 t = dRt.tail<3>();
|
||||||
|
|
||||||
|
// Compute the reprojection error for each coordinate.
|
||||||
|
Vec residuals(2 * markers.size());
|
||||||
|
residuals.setZero();
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
const EuclideanPoint &point =
|
||||||
|
*reconstruction.PointForTrack(markers[i].track);
|
||||||
|
Vec3 projected = R * point.X + t;
|
||||||
|
projected /= projected(2);
|
||||||
|
residuals[2*i + 0] = projected(0) - markers[i].x;
|
||||||
|
residuals[2*i + 1] = projected(1) - markers[i].y;
|
||||||
|
}
|
||||||
|
return residuals;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vector<Marker> &markers;
|
||||||
|
const EuclideanReconstruction &reconstruction;
|
||||||
|
const Mat3 &initial_R;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool EuclideanResect(const vector<Marker> &markers,
|
||||||
|
EuclideanReconstruction *reconstruction, bool final_pass) {
|
||||||
|
if (markers.size() < 5) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Mat2X points_2d = PointMatrixFromMarkers(markers);
|
||||||
|
Mat3X points_3d(3, markers.size());
|
||||||
|
for (int i = 0; i < markers.size(); i++) {
|
||||||
|
points_3d.col(i) = reconstruction->PointForTrack(markers[i].track)->X;
|
||||||
|
}
|
||||||
|
LG << "Points for resect:\n" << points_2d;
|
||||||
|
|
||||||
|
Mat3 R;
|
||||||
|
Vec3 t;
|
||||||
|
if (0 || !euclidean_resection::EuclideanResection(points_2d, points_3d, &R, &t)) {
|
||||||
|
// printf("Resection for image %d failed\n", markers[0].image);
|
||||||
|
LG << "Resection for image " << markers[0].image << " failed;"
|
||||||
|
<< " trying fallback projective resection.";
|
||||||
|
if (!final_pass) return false;
|
||||||
|
// Euclidean resection failed. Fall back to projective resection, which is
|
||||||
|
// less reliable but better conditioned when there are many points.
|
||||||
|
Mat34 P;
|
||||||
|
Mat4X points_3d_homogeneous(4, markers.size());
|
||||||
|
for (int i = 0; i < markers.size(); i++) {
|
||||||
|
points_3d_homogeneous.col(i).head<3>() = points_3d.col(i);
|
||||||
|
points_3d_homogeneous(3, i) = 1.0;
|
||||||
|
}
|
||||||
|
resection::Resection(points_2d, points_3d_homogeneous, &P);
|
||||||
|
if ((P * points_3d_homogeneous.col(0))(2) < 0) {
|
||||||
|
LG << "Point behind camera; switch sign.";
|
||||||
|
P = -P;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat3 ignored;
|
||||||
|
KRt_From_P(P, &ignored, &R, &t);
|
||||||
|
|
||||||
|
// The R matrix should be a rotation, but don't rely on it.
|
||||||
|
Eigen::JacobiSVD<Mat3> svd(R, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
||||||
|
|
||||||
|
LG << "Resection rotation is: " << svd.singularValues().transpose();
|
||||||
|
LG << "Determinant is: " << R.determinant();
|
||||||
|
|
||||||
|
// Correct to make R a rotation.
|
||||||
|
R = svd.matrixU() * svd.matrixV().transpose();
|
||||||
|
|
||||||
|
Vec3 xx = R * points_3d.col(0) + t;
|
||||||
|
if (xx(2) < 0.0) {
|
||||||
|
LG << "Final point is still behind camera...";
|
||||||
|
}
|
||||||
|
// XXX Need to check if error is horrible and fail here too in that case.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refine the result.
|
||||||
|
typedef LevenbergMarquardt<EuclideanResectCostFunction> Solver;
|
||||||
|
|
||||||
|
// Give the cost our initial guess for R.
|
||||||
|
EuclideanResectCostFunction resect_cost(markers, *reconstruction, R);
|
||||||
|
|
||||||
|
// Encode the initial parameters: start with zero delta rotation, and the
|
||||||
|
// guess for t obtained from resection.
|
||||||
|
Vec6 dRt = Vec6::Zero();
|
||||||
|
dRt.tail<3>() = t;
|
||||||
|
|
||||||
|
Solver solver(resect_cost);
|
||||||
|
|
||||||
|
Solver::SolverParameters params;
|
||||||
|
Solver::Results results = solver.minimize(params, &dRt);
|
||||||
|
LG << "LM found incremental rotation: " << dRt.head<3>().transpose();
|
||||||
|
// TODO(keir): Check results to ensure clean termination.
|
||||||
|
|
||||||
|
// Unpack the rotation and translation.
|
||||||
|
R = RotationFromEulerVector(dRt.head<3>()) * R;
|
||||||
|
t = dRt.tail<3>();
|
||||||
|
|
||||||
|
LG << "Resection for image " << markers[0].image << " got:\n"
|
||||||
|
<< "R:\n" << R << "\nt:\n" << t;
|
||||||
|
reconstruction->InsertCamera(markers[0].image, R, t);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Directly parameterize the projection matrix, P, which is a 12 parameter
|
||||||
|
// homogeneous entry. In theory P should be parameterized with only 11
|
||||||
|
// parametetrs, but in practice it works fine to let the extra degree of
|
||||||
|
// freedom drift.
|
||||||
|
struct ProjectiveResectCostFunction {
|
||||||
|
public:
|
||||||
|
typedef Vec FMatrixType;
|
||||||
|
typedef Vec12 XMatrixType;
|
||||||
|
|
||||||
|
ProjectiveResectCostFunction(const vector<Marker> &markers,
|
||||||
|
const ProjectiveReconstruction &reconstruction)
|
||||||
|
: markers(markers),
|
||||||
|
reconstruction(reconstruction) {}
|
||||||
|
|
||||||
|
Vec operator()(const Vec12 &vector_P) const {
|
||||||
|
// Unpack P from vector_P.
|
||||||
|
Map<const Mat34> P(vector_P.data(), 3, 4);
|
||||||
|
|
||||||
|
// Compute the reprojection error for each coordinate.
|
||||||
|
Vec residuals(2 * markers.size());
|
||||||
|
residuals.setZero();
|
||||||
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
|
const ProjectivePoint &point =
|
||||||
|
*reconstruction.PointForTrack(markers[i].track);
|
||||||
|
Vec3 projected = P * point.X;
|
||||||
|
projected /= projected(2);
|
||||||
|
residuals[2*i + 0] = projected(0) - markers[i].x;
|
||||||
|
residuals[2*i + 1] = projected(1) - markers[i].y;
|
||||||
|
}
|
||||||
|
return residuals;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vector<Marker> &markers;
|
||||||
|
const ProjectiveReconstruction &reconstruction;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool ProjectiveResect(const vector<Marker> &markers,
|
||||||
|
ProjectiveReconstruction *reconstruction) {
|
||||||
|
if (markers.size() < 5) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stack the homogeneous 3D points as the columns of a matrix.
|
||||||
|
Mat2X points_2d = PointMatrixFromMarkers(markers);
|
||||||
|
Mat4X points_3d_homogeneous(4, markers.size());
|
||||||
|
for (int i = 0; i < markers.size(); i++) {
|
||||||
|
points_3d_homogeneous.col(i) =
|
||||||
|
reconstruction->PointForTrack(markers[i].track)->X;
|
||||||
|
}
|
||||||
|
LG << "Points for resect:\n" << points_2d;
|
||||||
|
|
||||||
|
// Resection the point.
|
||||||
|
Mat34 P;
|
||||||
|
resection::Resection(points_2d, points_3d_homogeneous, &P);
|
||||||
|
|
||||||
|
// Flip the sign of P if necessary to keep the point in front of the camera.
|
||||||
|
if ((P * points_3d_homogeneous.col(0))(2) < 0) {
|
||||||
|
LG << "Point behind camera; switch sign.";
|
||||||
|
P = -P;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(keir): Check if error is horrible and fail in that case.
|
||||||
|
|
||||||
|
// Refine the resulting projection matrix using geometric error.
|
||||||
|
typedef LevenbergMarquardt<ProjectiveResectCostFunction> Solver;
|
||||||
|
|
||||||
|
ProjectiveResectCostFunction resect_cost(markers, *reconstruction);
|
||||||
|
|
||||||
|
// Pack the initial P matrix into a size-12 vector..
|
||||||
|
Vec12 vector_P = Map<Vec12>(P.data());
|
||||||
|
|
||||||
|
Solver solver(resect_cost);
|
||||||
|
|
||||||
|
Solver::SolverParameters params;
|
||||||
|
Solver::Results results = solver.minimize(params, &vector_P);
|
||||||
|
// TODO(keir): Check results to ensure clean termination.
|
||||||
|
|
||||||
|
// Unpack the projection matrix.
|
||||||
|
P = Map<Mat34>(vector_P.data(), 3, 4);
|
||||||
|
|
||||||
|
LG << "Resection for image " << markers[0].image << " got:\n"
|
||||||
|
<< "P:\n" << P;
|
||||||
|
reconstruction->InsertCamera(markers[0].image, P);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace libmv
|
||||||
86
extern/libmv/libmv/simple_pipeline/resect.h
vendored
Normal file
86
extern/libmv/libmv/simple_pipeline/resect.h
vendored
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_SIMPLE_PIPELINE_RESECT_H
|
||||||
|
#define LIBMV_SIMPLE_PIPELINE_RESECT_H
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
|
#include "libmv/simple_pipeline/reconstruction.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Estimate the Euclidean pose of a camera from 2D to 3D correspondences.
|
||||||
|
|
||||||
|
This takes a set of markers visible in one frame (which is the one to
|
||||||
|
resection), such that the markers are also reconstructed in 3D in the
|
||||||
|
reconstruction object, and solves for the pose and orientation of the
|
||||||
|
camera for that frame.
|
||||||
|
|
||||||
|
\a markers should contain \l Marker markers \endlink belonging to tracks
|
||||||
|
visible in the one frame to be resectioned. Each of the tracks associated
|
||||||
|
with the markers must have a corresponding reconstructed 3D position in the
|
||||||
|
\a *reconstruction object.
|
||||||
|
|
||||||
|
\a *reconstruction should contain the 3D points associated with the tracks
|
||||||
|
for the markers present in \a markers.
|
||||||
|
|
||||||
|
\note This assumes a calibrated reconstruction, e.g. the markers are
|
||||||
|
already corrected for camera intrinsics and radial distortion.
|
||||||
|
\note This assumes an outlier-free set of markers.
|
||||||
|
|
||||||
|
\return True if the resection was successful, false otherwise.
|
||||||
|
|
||||||
|
\sa EuclideanIntersect, EuclideanReconstructTwoFrames
|
||||||
|
*/
|
||||||
|
bool EuclideanResect(const vector<Marker> &markers,
|
||||||
|
EuclideanReconstruction *reconstruction, bool final_pass);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Estimate the projective pose of a camera from 2D to 3D correspondences.
|
||||||
|
|
||||||
|
This takes a set of markers visible in one frame (which is the one to
|
||||||
|
resection), such that the markers are also reconstructed in a projective
|
||||||
|
frame in the reconstruction object, and solves for the projective matrix of
|
||||||
|
the camera for that frame.
|
||||||
|
|
||||||
|
\a markers should contain \l Marker markers \endlink belonging to tracks
|
||||||
|
visible in the one frame to be resectioned. Each of the tracks associated
|
||||||
|
with the markers must have a corresponding reconstructed homogeneous 3D
|
||||||
|
position in the \a *reconstruction object.
|
||||||
|
|
||||||
|
\a *reconstruction should contain the homogeneous 3D points associated with
|
||||||
|
the tracks for the markers present in \a markers.
|
||||||
|
|
||||||
|
\note This assumes radial distortion has already been corrected, but
|
||||||
|
otherwise works for uncalibrated sequences.
|
||||||
|
\note This assumes an outlier-free set of markers.
|
||||||
|
|
||||||
|
\return True if the resection was successful, false otherwise.
|
||||||
|
|
||||||
|
\sa ProjectiveIntersect, ProjectiveReconstructTwoFrames
|
||||||
|
*/
|
||||||
|
bool ProjectiveResect(const vector<Marker> &markers,
|
||||||
|
ProjectiveReconstruction *reconstruction);
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_SIMPLE_PIPELINE_RESECT_H
|
||||||
159
extern/libmv/libmv/simple_pipeline/tracks.cc
vendored
Normal file
159
extern/libmv/libmv/simple_pipeline/tracks.cc
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
// 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 <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
Tracks::Tracks(const Tracks &other) {
|
||||||
|
markers_ = other.markers_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tracks::Tracks(const vector<Marker> &markers) : markers_(markers) {}
|
||||||
|
|
||||||
|
void Tracks::Insert(int image, int track, double x, double y) {
|
||||||
|
// TODO(keir): Wow, this is quadratic for repeated insertions. Fix this by
|
||||||
|
// adding a smarter data structure like a set<>.
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if (markers_[i].image == image &&
|
||||||
|
markers_[i].track == track) {
|
||||||
|
markers_[i].x = x;
|
||||||
|
markers_[i].y = y;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Marker marker = { image, track, x, y };
|
||||||
|
markers_.push_back(marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<Marker> Tracks::AllMarkers() const {
|
||||||
|
return markers_;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<Marker> Tracks::MarkersInImage(int image) const {
|
||||||
|
vector<Marker> markers;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if (image == markers_[i].image) {
|
||||||
|
markers.push_back(markers_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<Marker> Tracks::MarkersForTrack(int track) const {
|
||||||
|
vector<Marker> markers;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if (track == markers_[i].track) {
|
||||||
|
markers.push_back(markers_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<Marker> Tracks::MarkersForTracksInBothImages(int image1, int image2) const {
|
||||||
|
std::vector<int> image1_tracks;
|
||||||
|
std::vector<int> image2_tracks;
|
||||||
|
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
int image = markers_[i].image;
|
||||||
|
if (image == image1) {
|
||||||
|
image1_tracks.push_back(markers_[i].track);
|
||||||
|
} else if (image == image2) {
|
||||||
|
image2_tracks.push_back(markers_[i].track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(image1_tracks.begin(), image1_tracks.end());
|
||||||
|
std::sort(image2_tracks.begin(), image2_tracks.end());
|
||||||
|
|
||||||
|
std::vector<int> intersection;
|
||||||
|
std::set_intersection(image1_tracks.begin(), image1_tracks.end(),
|
||||||
|
image2_tracks.begin(), image2_tracks.end(),
|
||||||
|
std::back_inserter(intersection));
|
||||||
|
|
||||||
|
vector<Marker> markers;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if ((markers_[i].image == image1 || markers_[i].image == image2) &&
|
||||||
|
std::binary_search(intersection.begin(),intersection.end(),
|
||||||
|
markers_[i].track)) {
|
||||||
|
markers.push_back(markers_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
Marker Tracks::MarkerInImageForTrack(int image, int track) const {
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if (markers_[i].image == image && markers_[i].track == track) {
|
||||||
|
return markers_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Marker null = { -1, -1, -1, -1 };
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tracks::RemoveMarkersForTrack(int track) {
|
||||||
|
int size = 0;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if (markers_[i].track != track) {
|
||||||
|
markers_[size++] = markers_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
markers_.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tracks::RemoveMarker(int image, int track) {
|
||||||
|
int size = 0;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if (markers_[i].image != image || markers_[i].track != track) {
|
||||||
|
markers_[size++] = markers_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
markers_.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Tracks::MaxImage() const {
|
||||||
|
// TODO(MatthiasF): maintain a max_image_ member (updated on Insert)
|
||||||
|
int max_image = 0;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
max_image = std::max(markers_[i].image, max_image);
|
||||||
|
}
|
||||||
|
return max_image;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Tracks::MaxTrack() const {
|
||||||
|
// TODO(MatthiasF): maintain a max_track_ member (updated on Insert)
|
||||||
|
int max_track = 0;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
max_track = std::max(markers_[i].track, max_track);
|
||||||
|
}
|
||||||
|
return max_track;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Tracks::NumMarkers() const {
|
||||||
|
return markers_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
119
extern/libmv/libmv/simple_pipeline/tracks.h
vendored
Normal file
119
extern/libmv/libmv/simple_pipeline/tracks.h
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_SIMPLE_PIPELINE_TRACKS_H_
|
||||||
|
#define LIBMV_SIMPLE_PIPELINE_TRACKS_H_
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A Marker is the 2D location of a tracked point in an image.
|
||||||
|
|
||||||
|
\a x, \a y is the position of the marker in pixels from the top left corner
|
||||||
|
in the image identified by \a image. All markers for to the same target
|
||||||
|
form a track identified by a common \a track number.
|
||||||
|
|
||||||
|
\note Markers are typically aggregated with the help of the \l Tracks class.
|
||||||
|
|
||||||
|
\sa Tracks
|
||||||
|
*/
|
||||||
|
struct Marker {
|
||||||
|
int image;
|
||||||
|
int track;
|
||||||
|
double x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The Tracks class stores \link Marker reconstruction markers \endlink.
|
||||||
|
|
||||||
|
The Tracks container is intended as the store of correspondences between
|
||||||
|
images, which must get created before any 3D reconstruction can take place.
|
||||||
|
|
||||||
|
The container has several fast lookups for queries typically needed for
|
||||||
|
structure from motion algorithms, such as \l MarkersForTracksInBothImages().
|
||||||
|
|
||||||
|
\sa Marker
|
||||||
|
*/
|
||||||
|
class Tracks {
|
||||||
|
public:
|
||||||
|
Tracks() {}
|
||||||
|
|
||||||
|
// Copy constructor for a tracks object.
|
||||||
|
Tracks(const Tracks &other);
|
||||||
|
|
||||||
|
/// Construct a new tracks object using the given markers to start.
|
||||||
|
Tracks(const vector<Marker> &markers);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Inserts a marker into the set. If there is already a marker for the given
|
||||||
|
\a image and \a track, the existing marker is replaced. If there is no
|
||||||
|
marker for the given \a image and \a track, a new one is added.
|
||||||
|
|
||||||
|
\a image and \a track are the keys used to retrieve the markers with the
|
||||||
|
other methods in this class.
|
||||||
|
|
||||||
|
\note To get an identifier for a new track, use \l MaxTrack() + 1.
|
||||||
|
*/
|
||||||
|
void Insert(int image, int track, double x, double y);
|
||||||
|
|
||||||
|
/// Returns all the markers.
|
||||||
|
vector<Marker> AllMarkers() const;
|
||||||
|
|
||||||
|
/// Returns all the markers belonging to a track.
|
||||||
|
vector<Marker> MarkersForTrack(int track) const;
|
||||||
|
|
||||||
|
/// Returns all the markers visible in \a image.
|
||||||
|
vector<Marker> MarkersInImage(int image) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the markers in \a image1 and \a image2 which have a common track.
|
||||||
|
|
||||||
|
This is not the same as the union of the markers in \a image1 and \a
|
||||||
|
image2; each marker is for a track that appears in both images.
|
||||||
|
*/
|
||||||
|
vector<Marker> MarkersForTracksInBothImages(int image1, int image2) const;
|
||||||
|
|
||||||
|
/// Returns the marker in \a image belonging to \a track.
|
||||||
|
Marker MarkerInImageForTrack(int image, int track) const;
|
||||||
|
|
||||||
|
/// Removes all the markers belonging to \a track.
|
||||||
|
void RemoveMarkersForTrack(int track);
|
||||||
|
|
||||||
|
/// Removes the marker in \a image belonging to \a track.
|
||||||
|
void RemoveMarker(int image, int track);
|
||||||
|
|
||||||
|
/// Returns the maximum image identifier used.
|
||||||
|
int MaxImage() const;
|
||||||
|
|
||||||
|
/// Returns the maximum track identifier used.
|
||||||
|
int MaxTrack() const;
|
||||||
|
|
||||||
|
/// Returns the number of markers.
|
||||||
|
int NumMarkers() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<Marker> markers_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_SIMPLE_PIPELINE_MARKERS_H_
|
||||||
132
extern/libmv/libmv/tracking/klt_region_tracker.cc
vendored
Normal file
132
extern/libmv/libmv/tracking/klt_region_tracker.cc
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
// Copyright (c) 2007, 2008, 2009, 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/tracking/klt_region_tracker.h"
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "libmv/image/convolve.h"
|
||||||
|
#include "libmv/image/sample.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
// Compute the gradient matrix noted by Z and the error vector e. See Good
|
||||||
|
// Features to Track.
|
||||||
|
//
|
||||||
|
// TODO(keir): The calls to SampleLinear() do boundary checking that should
|
||||||
|
// instead happen outside the loop. Since this is the innermost loop, the extra
|
||||||
|
// bounds checking hurts performance.
|
||||||
|
static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
|
||||||
|
const Array3Df &image_and_gradient2,
|
||||||
|
double x1, double y1,
|
||||||
|
double x2, double y2,
|
||||||
|
int half_width,
|
||||||
|
float *gxx,
|
||||||
|
float *gxy,
|
||||||
|
float *gyy,
|
||||||
|
float *ex,
|
||||||
|
float *ey) {
|
||||||
|
*gxx = *gxy = *gyy = 0;
|
||||||
|
*ex = *ey = 0;
|
||||||
|
for (int r = -half_width; r <= half_width; ++r) {
|
||||||
|
for (int c = -half_width; c <= half_width; ++c) {
|
||||||
|
float xx1 = x1 + c;
|
||||||
|
float yy1 = y1 + r;
|
||||||
|
float xx2 = x2 + c;
|
||||||
|
float yy2 = y2 + r;
|
||||||
|
float I = SampleLinear(image_and_gradient1, yy1, xx1, 0);
|
||||||
|
float J = SampleLinear(image_and_gradient2, yy2, xx2, 0);
|
||||||
|
float gx = SampleLinear(image_and_gradient2, yy2, xx2, 1);
|
||||||
|
float gy = SampleLinear(image_and_gradient2, yy2, xx2, 2);
|
||||||
|
*gxx += gx * gx;
|
||||||
|
*gxy += gx * gy;
|
||||||
|
*gyy += gy * gy;
|
||||||
|
*ex += (I - J) * gx;
|
||||||
|
*ey += (I - J) * gy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solve the tracking equation
|
||||||
|
//
|
||||||
|
// [gxx gxy] [dx] = [ex]
|
||||||
|
// [gxy gyy] [dy] = [ey]
|
||||||
|
//
|
||||||
|
// for dx and dy. Borrowed from Stan Birchfield's KLT implementation.
|
||||||
|
static bool SolveTrackingEquation(float gxx, float gxy, float gyy,
|
||||||
|
float ex, float ey,
|
||||||
|
float min_determinant,
|
||||||
|
float *dx, float *dy) {
|
||||||
|
float det = gxx * gyy - gxy * gxy;
|
||||||
|
if (det < min_determinant) {
|
||||||
|
*dx = 0;
|
||||||
|
*dy = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*dx = (gyy * ex - gxy * ey) / det;
|
||||||
|
*dy = (gxx * ey - gxy * ex) / det;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KltRegionTracker::Track(const FloatImage &image1,
|
||||||
|
const FloatImage &image2,
|
||||||
|
double x1, double y1,
|
||||||
|
double *x2, double *y2) const {
|
||||||
|
Array3Df image_and_gradient1;
|
||||||
|
Array3Df image_and_gradient2;
|
||||||
|
BlurredImageAndDerivativesChannels(image1, sigma, &image_and_gradient1);
|
||||||
|
BlurredImageAndDerivativesChannels(image2, sigma, &image_and_gradient2);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
float dx = 0, dy = 0;
|
||||||
|
for (i = 0; i < max_iterations; ++i) {
|
||||||
|
// Compute gradient matrix and error vector.
|
||||||
|
float gxx, gxy, gyy, ex, ey;
|
||||||
|
ComputeTrackingEquation(image_and_gradient1,
|
||||||
|
image_and_gradient2,
|
||||||
|
x1, y1,
|
||||||
|
*x2, *y2,
|
||||||
|
half_window_size,
|
||||||
|
&gxx, &gxy, &gyy, &ex, &ey);
|
||||||
|
|
||||||
|
// Solve the linear system for the best update to x2 and y2.
|
||||||
|
if (!SolveTrackingEquation(gxx, gxy, gyy, ex, ey, min_determinant,
|
||||||
|
&dx, &dy)) {
|
||||||
|
// The determinant, which indicates the trackiness of the point, is too
|
||||||
|
// small, so fail out.
|
||||||
|
LG << "Determinant too small; failing tracking.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the position with the solved displacement.
|
||||||
|
*x2 += dx;
|
||||||
|
*y2 += dy;
|
||||||
|
|
||||||
|
// If the update is small, then we probably found the target.
|
||||||
|
if (dx * dx + dy * dy < min_update_squared_distance) {
|
||||||
|
LG << "Successful track in " << i << " iterations.";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Getting here means we hit max iterations, so tracking failed.
|
||||||
|
LG << "Too many iterations.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
55
extern/libmv/libmv/tracking/klt_region_tracker.h
vendored
Normal file
55
extern/libmv/libmv/tracking/klt_region_tracker.h
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (c) 2007, 2008, 2009, 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_REGION_TRACKING_KLT_REGION_TRACKER_H_
|
||||||
|
#define LIBMV_REGION_TRACKING_KLT_REGION_TRACKER_H_
|
||||||
|
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "libmv/tracking/region_tracker.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
struct KltRegionTracker : public RegionTracker {
|
||||||
|
KltRegionTracker()
|
||||||
|
: half_window_size(4),
|
||||||
|
max_iterations(16),
|
||||||
|
min_determinant(1e-6),
|
||||||
|
min_update_squared_distance(1e-6),
|
||||||
|
sigma(0.9) {}
|
||||||
|
|
||||||
|
virtual ~KltRegionTracker() {}
|
||||||
|
|
||||||
|
// Tracker interface.
|
||||||
|
virtual bool Track(const FloatImage &image1,
|
||||||
|
const FloatImage &image2,
|
||||||
|
double x1, double y1,
|
||||||
|
double *x2, double *y2) const;
|
||||||
|
|
||||||
|
// No point in creating getters or setters.
|
||||||
|
int half_window_size;
|
||||||
|
int max_iterations;
|
||||||
|
double min_determinant;
|
||||||
|
double min_update_squared_distance;
|
||||||
|
double sigma;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_REGION_TRACKING_KLT_REGION_TRACKER_H_
|
||||||
80
extern/libmv/libmv/tracking/pyramid_region_tracker.cc
vendored
Normal file
80
extern/libmv/libmv/tracking/pyramid_region_tracker.cc
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// Copyright (c) 2007, 2008, 2009, 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "libmv/image/convolve.h"
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "libmv/image/sample.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/tracking/pyramid_region_tracker.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
static void MakePyramid(const FloatImage &image, int num_levels,
|
||||||
|
std::vector<FloatImage> *pyramid) {
|
||||||
|
pyramid->resize(num_levels);
|
||||||
|
(*pyramid)[0] = image;
|
||||||
|
for (int i = 1; i < num_levels; ++i) {
|
||||||
|
DownsampleChannelsBy2((*pyramid)[i - 1], &(*pyramid)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PyramidRegionTracker::Track(const FloatImage &image1,
|
||||||
|
const FloatImage &image2,
|
||||||
|
double x1, double y1,
|
||||||
|
double *x2, double *y2) const {
|
||||||
|
// Shrink the guessed x and y location to match the coarsest level + 1 (which
|
||||||
|
// when gets corrected in the loop).
|
||||||
|
*x2 /= pow(2., num_levels_);
|
||||||
|
*y2 /= pow(2., num_levels_);
|
||||||
|
|
||||||
|
// Create all the levels of the pyramid, since tracking has to happen from
|
||||||
|
// the coarsest to finest levels, which means holding on to all levels of the
|
||||||
|
// pyraid at once.
|
||||||
|
std::vector<FloatImage> pyramid1(num_levels_);
|
||||||
|
std::vector<FloatImage> pyramid2(num_levels_);
|
||||||
|
MakePyramid(image1, num_levels_, &pyramid1);
|
||||||
|
MakePyramid(image2, num_levels_, &pyramid2);
|
||||||
|
|
||||||
|
for (int i = num_levels_ - 1; i >= 0; --i) {
|
||||||
|
// Position in the first image at pyramid level i.
|
||||||
|
double xx = x1 / pow(2., i);
|
||||||
|
double yy = y1 / pow(2., i);
|
||||||
|
|
||||||
|
// Guess the new tracked position is where the last level tracked to.
|
||||||
|
*x2 *= 2;
|
||||||
|
*y2 *= 2;
|
||||||
|
|
||||||
|
// Track the point on this level with the base tracker.
|
||||||
|
bool succeeded = tracker_->Track(pyramid1[i], pyramid2[i], xx, yy, x2, y2);
|
||||||
|
|
||||||
|
if (i == 0 && !succeeded) {
|
||||||
|
// Only fail on the highest-resolution level, because a failure on a
|
||||||
|
// coarse level does not mean failure at a lower level (consider
|
||||||
|
// out-of-bounds conditions).
|
||||||
|
LG << "Finest level of pyramid tracking failed; failing.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
46
extern/libmv/libmv/tracking/pyramid_region_tracker.h
vendored
Normal file
46
extern/libmv/libmv/tracking/pyramid_region_tracker.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_
|
||||||
|
#define LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_
|
||||||
|
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "libmv/base/scoped_ptr.h"
|
||||||
|
#include "libmv/tracking/region_tracker.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
class PyramidRegionTracker : public RegionTracker {
|
||||||
|
public:
|
||||||
|
PyramidRegionTracker(RegionTracker *tracker, int num_levels)
|
||||||
|
: tracker_(tracker), num_levels_(num_levels) {}
|
||||||
|
|
||||||
|
virtual bool Track(const FloatImage &image1,
|
||||||
|
const FloatImage &image2,
|
||||||
|
double x1, double y1,
|
||||||
|
double *x2, double *y2) const;
|
||||||
|
private:
|
||||||
|
scoped_ptr<RegionTracker> tracker_;
|
||||||
|
int num_levels_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_
|
||||||
48
extern/libmv/libmv/tracking/region_tracker.h
vendored
Normal file
48
extern/libmv/libmv/tracking/region_tracker.h
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_TRACKING_TRACKER_H_
|
||||||
|
#define LIBMV_TRACKING_TRACKER_H_
|
||||||
|
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
class RegionTracker {
|
||||||
|
public:
|
||||||
|
RegionTracker() {}
|
||||||
|
virtual ~RegionTracker() {}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Track a point from \a image1 to \a image2.
|
||||||
|
|
||||||
|
\a x2, \a y2 should start out as a best guess for the position in \a
|
||||||
|
image2. If no guess is available, (\a x1, \a y1) is a good start. Returns
|
||||||
|
true on success, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool Track(const FloatImage &image1,
|
||||||
|
const FloatImage &image2,
|
||||||
|
double x1, double y1,
|
||||||
|
double *x2, double *y2) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_CORRESPONDENCE_TRACKER_H_
|
||||||
47
extern/libmv/libmv/tracking/retrack_region_tracker.cc
vendored
Normal file
47
extern/libmv/libmv/tracking/retrack_region_tracker.cc
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// 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 <cmath>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "libmv/tracking/retrack_region_tracker.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
bool RetrackRegionTracker::Track(const FloatImage &image1,
|
||||||
|
const FloatImage &image2,
|
||||||
|
double x1, double y1,
|
||||||
|
double *x2, double *y2) const {
|
||||||
|
// Track forward, getting x2 and y2.
|
||||||
|
if (!tracker_->Track(image1, image2, x1, y1, x2, y2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Now track x2 and y2 backward, to get xx1 and yy1 which, if the track is
|
||||||
|
// good, should match x1 and y1 (but may not if the track is bad).
|
||||||
|
double xx1 = *x2, yy1 = *x2;
|
||||||
|
if (!tracker_->Track(image2, image1, *x2, *y2, &xx1, &yy1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double dx = xx1 - x1;
|
||||||
|
double dy = yy1 - y1;
|
||||||
|
return sqrt(dx * dx + dy * dy) < tolerance_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
48
extern/libmv/libmv/tracking/retrack_region_tracker.h
vendored
Normal file
48
extern/libmv/libmv/tracking/retrack_region_tracker.h
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_
|
||||||
|
#define LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_
|
||||||
|
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "libmv/base/scoped_ptr.h"
|
||||||
|
#include "libmv/tracking/region_tracker.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
// A region tracker that tries tracking backwards and forwards, rejecting a
|
||||||
|
// track that doesn't track backwards to the starting point.
|
||||||
|
class RetrackRegionTracker : public RegionTracker {
|
||||||
|
public:
|
||||||
|
RetrackRegionTracker(RegionTracker *tracker, double tolerance)
|
||||||
|
: tracker_(tracker), tolerance_(tolerance) {}
|
||||||
|
|
||||||
|
virtual bool Track(const FloatImage &image1,
|
||||||
|
const FloatImage &image2,
|
||||||
|
double x1, double y1,
|
||||||
|
double *x2, double *y2) const;
|
||||||
|
private:
|
||||||
|
scoped_ptr<RegionTracker> tracker_;
|
||||||
|
double tolerance_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_
|
||||||
174
extern/libmv/libmv/tracking/sad.cc
vendored
Normal file
174
extern/libmv/libmv/tracking/sad.cc
vendored
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (c) 2011 libmv authors.
|
||||||
|
**
|
||||||
|
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
** of this software and associated documentation files (the "Software"), to
|
||||||
|
** deal in the Software without restriction, including without limitation the
|
||||||
|
** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
** sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
** furnished to do so, subject to the following conditions:
|
||||||
|
**
|
||||||
|
** The above copyright notice and this permission notice shall be included in
|
||||||
|
** all copies or substantial portions of the Software.
|
||||||
|
**
|
||||||
|
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
** IN THE SOFTWARE.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "libmv/tracking/sad.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
void LaplaceFilter(ubyte* src, ubyte* dst, int width, int height, int strength) {
|
||||||
|
for(int y=1; y<height-1; y++) for(int x=1; x<width-1; x++) {
|
||||||
|
const ubyte* s = &src[y*width+x];
|
||||||
|
int l = 128 +
|
||||||
|
s[-width-1] + s[-width] + s[-width+1] +
|
||||||
|
s[1] - 8*s[0] + s[1] +
|
||||||
|
s[ width-1] + s[ width] + s[ width+1] ;
|
||||||
|
int d = ((256-strength)*s[0] + strength*l) / 256;
|
||||||
|
if(d < 0) d=0;
|
||||||
|
if(d > 255) d=255;
|
||||||
|
dst[y*width+x] = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vec2 {
|
||||||
|
float x,y;
|
||||||
|
inline vec2(float x, float y):x(x),y(y){}
|
||||||
|
};
|
||||||
|
inline vec2 operator*(mat32 m, vec2 v) {
|
||||||
|
return vec2(v.x*m(0,0)+v.y*m(0,1)+m(0,2),v.x*m(1,0)+v.y*m(1,1)+m(1,2));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! fixed point bilinear sample with precision k
|
||||||
|
template <int k> inline int sample(const ubyte* image,int stride, int x, int y, int u, int v) {
|
||||||
|
const ubyte* s = &image[y*stride+x];
|
||||||
|
return ((s[ 0] * (k-u) + s[ 1] * u) * (k-v)
|
||||||
|
+ (s[stride] * (k-u) + s[stride+1] * u) * ( v) ) / (k*k);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __SSE__
|
||||||
|
#include <xmmintrin.h>
|
||||||
|
int lround(float x) { return _mm_cvtss_si32(_mm_set_ss(x)); }
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
int lround(float x) { return x+0.5; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//TODO(MatthiasF): SSE optimization
|
||||||
|
void SamplePattern(ubyte* image, int stride, mat32 warp, ubyte* pattern, int size) {
|
||||||
|
const int k = 256;
|
||||||
|
for (int i = 0; i < size; i++) for (int j = 0; j < size; j++) {
|
||||||
|
vec2 p = warp*vec2(j-size/2,i-size/2);
|
||||||
|
int fx = lround(p.x*k), fy = lround(p.y*k);
|
||||||
|
int ix = fx/k, iy = fy/k;
|
||||||
|
int u = fx%k, v = fy%k;
|
||||||
|
pattern[i*size+j] = sample<k>(image,stride,ix,iy,u,v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __SSE2__
|
||||||
|
#include <emmintrin.h>
|
||||||
|
static uint SAD(const ubyte* pattern, const ubyte* image, int stride, int size) {
|
||||||
|
__m128i a = _mm_setzero_si128();
|
||||||
|
for(int i = 0; i < size; i++) {
|
||||||
|
for(int j = 0; j < size/16; j++) {
|
||||||
|
a = _mm_adds_epu16(a, _mm_sad_epu8( _mm_loadu_si128((__m128i*)(pattern+i*size+j*16)),
|
||||||
|
_mm_loadu_si128((__m128i*)(image+i*stride+j*16))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _mm_extract_epi16(a,0) + _mm_extract_epi16(a,4);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static uint SAD(const ubyte* pattern, const ubyte* image, int stride, int size) {
|
||||||
|
uint sad=0;
|
||||||
|
for(int i = 0; i < size; i++) {
|
||||||
|
for(int j = 0; j < size; j++) {
|
||||||
|
sad += abs((int)pattern[i*size+j] - image[i*stride+j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sad;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float sq(float x) { return x*x; }
|
||||||
|
float Track(ubyte* reference, ubyte* warped, int size, ubyte* image, int stride, int w, int h, mat32* warp, float areaPenalty, float conditionPenalty) {
|
||||||
|
mat32 m=*warp;
|
||||||
|
uint min=-1;
|
||||||
|
|
||||||
|
// exhaustive search integer pixel translation
|
||||||
|
int ix = m(0,2), iy = m(1,2);
|
||||||
|
for(int y = size/2; y < h-size/2; y++) {
|
||||||
|
for(int x = size/2; x < w-size/2; x++) {
|
||||||
|
m(0,2) = x, m(1,2) = y;
|
||||||
|
uint sad = SAD(warped,&image[(y-size/2)*stride+(x-size/2)],stride,size);
|
||||||
|
// TODO: using chroma could help disambiguate some cases
|
||||||
|
if(sad < min) {
|
||||||
|
min = sad;
|
||||||
|
ix = x, iy = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m(0,2) = ix, m(1,2) = iy;
|
||||||
|
min=-1; //reset score since direct warped search match too well (but the wrong pattern).
|
||||||
|
|
||||||
|
// 6D coordinate descent to find affine transform
|
||||||
|
ubyte* match = new ubyte[size*size];
|
||||||
|
float step = 0.5;
|
||||||
|
for(int p = 0; p < 8; p++) { //foreach precision level
|
||||||
|
for(int i = 0; i < 2; i++) { // iterate twice per precision level
|
||||||
|
//TODO: other sweep pattern might converge better
|
||||||
|
for(int d=0; d < 6; d++) { // iterate dimension sequentially (cyclic descent)
|
||||||
|
for(float e = -step; e <= step; e+=step) { //solve subproblem (evaluate only along one coordinate)
|
||||||
|
mat32 t = m;
|
||||||
|
t.data[d] += e;
|
||||||
|
//TODO: better performance would also allow a more exhaustive search
|
||||||
|
SamplePattern(image,stride,t,match,size);
|
||||||
|
uint sad = SAD(reference,match,size,size);
|
||||||
|
// regularization: keep constant area and good condition
|
||||||
|
float area = t(0,0)*t(1,1)-t(0,1)*t(1,0);
|
||||||
|
float x = sq(t(0,0))+sq(t(0,1)), y = sq(t(1,0))+sq(t(1,1));
|
||||||
|
float condition = x>y ? x/y : y/x;
|
||||||
|
sad += size*size*( areaPenalty*sq(area-1) + conditionPenalty*sq(condition-1) );
|
||||||
|
if(sad < min) {
|
||||||
|
min = sad;
|
||||||
|
m = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step /= 2;
|
||||||
|
}
|
||||||
|
*warp = m;
|
||||||
|
|
||||||
|
// Compute Pearson product-moment correlation coefficient
|
||||||
|
uint sX=0,sY=0,sXX=0,sYY=0,sXY=0;
|
||||||
|
SamplePattern(image,stride,m,match,size);
|
||||||
|
SAD(reference,match,size,size);
|
||||||
|
for(int i = 0; i < size; i++) {
|
||||||
|
for(int j = 0; j < size; j++) {
|
||||||
|
int x = reference[i*size+j];
|
||||||
|
int y = match[i*size+j];
|
||||||
|
sX += x;
|
||||||
|
sY += y;
|
||||||
|
sXX += x*x;
|
||||||
|
sYY += y*y;
|
||||||
|
sXY += x*y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] match;
|
||||||
|
const int N = size*size;
|
||||||
|
sX /= N, sY /= N, sXX /= N, sYY /= N, sXY /= N;
|
||||||
|
return (sXY-sX*sY)/sqrt(double((sXX-sX*sX)*(sYY-sY*sY)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
109
extern/libmv/libmv/tracking/sad.h
vendored
Normal file
109
extern/libmv/libmv/tracking/sad.h
vendored
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (c) 2011 libmv authors.
|
||||||
|
**
|
||||||
|
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
** of this software and associated documentation files (the "Software"), to
|
||||||
|
** deal in the Software without restriction, including without limitation the
|
||||||
|
** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
** sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
** furnished to do so, subject to the following conditions:
|
||||||
|
**
|
||||||
|
** The above copyright notice and this permission notice shall be included in
|
||||||
|
** all copies or substantial portions of the Software.
|
||||||
|
**
|
||||||
|
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
** IN THE SOFTWARE.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LIBMV_TRACKING_SAD_H_
|
||||||
|
#define LIBMV_TRACKING_SAD_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
namespace libmv {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned char ubyte;
|
||||||
|
typedef unsigned int uint;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Convolve \a src into \a dst with the discrete laplacian operator.
|
||||||
|
|
||||||
|
\a src and \a dst should be \a width x \a height images.
|
||||||
|
\a strength is an interpolation coefficient (0-256) between original image and the laplacian.
|
||||||
|
|
||||||
|
\note Make sure the search region is filtered with the same strength as the pattern.
|
||||||
|
*/
|
||||||
|
void LaplaceFilter(ubyte* src, ubyte* dst, int width, int height, int strength);
|
||||||
|
|
||||||
|
/// Affine transformation matrix in column major order.
|
||||||
|
struct mat32 {
|
||||||
|
float data[3*2];
|
||||||
|
#ifdef __cplusplus
|
||||||
|
inline mat32(int d=1) { for(int i=0;i<3*2;i++) data[i]=0; if(d!=0) for(int i=0;i<2;i++) m(i,i)=d; }
|
||||||
|
inline float m(int i, int j) const { return data[j*2+i]; }
|
||||||
|
inline float& m(int i, int j) { return data[j*2+i]; }
|
||||||
|
inline float operator()(int i, int j) const { return m(i,j); }
|
||||||
|
inline float& operator()(int i, int j) { return m(i,j); }
|
||||||
|
inline operator bool() const { for (int i=0; i<3*2; i++) if(data[i]!=0) return true; return false; }
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sample \a pattern from \a image.
|
||||||
|
|
||||||
|
\a warp is the transformation to apply to \a image when sampling the \a pattern.
|
||||||
|
*/
|
||||||
|
void SamplePattern(ubyte* image, int stride, mat32 warp, ubyte* pattern, int size);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Track \a pattern in \a image.
|
||||||
|
|
||||||
|
This template matcher computes the
|
||||||
|
\link http://en.wikipedia.org/wiki/Sum_of_absolute_differences Sum of Absolute Differences (SAD) \endlink
|
||||||
|
for each integer pixel position in the search region and then iteratively
|
||||||
|
refine subpixel position using a square search.
|
||||||
|
A similar method is used for motion estimation in video encoders.
|
||||||
|
|
||||||
|
\a reference is the pattern to track.
|
||||||
|
\a warped is a warped version of reference for fast unsampled integer search.
|
||||||
|
Best is to directly extract an already warped pattern from previous frame.
|
||||||
|
The \a size of the patterns should be aligned to 16.
|
||||||
|
\a image is a reference to the region to search.
|
||||||
|
\a stride is size of \a image lines.
|
||||||
|
|
||||||
|
On input, \a warp is the predicted affine transformation (e.g from previous frame)
|
||||||
|
On return, \a warp is the affine transformation which best match the reference \a pattern
|
||||||
|
|
||||||
|
\a areaPenalty and conditionPenalty control the regularization and need to be tweaked depending on the motion.
|
||||||
|
Setting them to 0 will allow any transformation (including unrealistic distortions and scaling).
|
||||||
|
Good values are between 0-32. 16 can be used as a realistic default.
|
||||||
|
areaPenalty control scaling (decrease to allow pull/zoom, increase to allow only 2D rotation).
|
||||||
|
a large conditionPenalty avoid a large ratio between the largest and smallest axices.
|
||||||
|
It need to be decreased for non-2D rotation (when pattern appears to scale along an axis).
|
||||||
|
|
||||||
|
\return Pearson product-moment correlation coefficient between reference and matched pattern.
|
||||||
|
This measure of the linear dependence between the patterns
|
||||||
|
ranges from −1 (negative correlation) to 1 (positive correlation).
|
||||||
|
A value of 0 implies that there is no linear correlation between the variables.
|
||||||
|
|
||||||
|
\note To track affine features:
|
||||||
|
- Sample reference pattern using estimated (e.g previous frame) warp.
|
||||||
|
-
|
||||||
|
\note \a stride allow you to reference your search region instead of copying.
|
||||||
|
\note For a 16x speedup, compile this tracker with SSE2 support.
|
||||||
|
*/
|
||||||
|
float Track(ubyte* reference, ubyte* warped, int size, ubyte* image, int stride, int width, int height, mat32* warp,
|
||||||
|
float areaPenalty, float conditionPenalty);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // namespace libmv
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // LIBMV_TRACKING_SAD_H_
|
||||||
135
extern/libmv/libmv/tracking/trklt_region_tracker.cc
vendored
Normal file
135
extern/libmv/libmv/tracking/trklt_region_tracker.cc
vendored
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/tracking/trklt_region_tracker.h"
|
||||||
|
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "libmv/image/convolve.h"
|
||||||
|
#include "libmv/image/sample.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
// Computes U and e from the Ud = e equation (number 14) from the paper.
|
||||||
|
static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
|
||||||
|
const Array3Df &image_and_gradient2,
|
||||||
|
double x1, double y1,
|
||||||
|
double x2, double y2,
|
||||||
|
int half_width,
|
||||||
|
double lambda,
|
||||||
|
Mat2f *U,
|
||||||
|
Vec2f *e) {
|
||||||
|
Mat2f A, B, C, D;
|
||||||
|
A = B = C = D = Mat2f::Zero();
|
||||||
|
|
||||||
|
Vec2f R, S, V, W;
|
||||||
|
R = S = V = W = Vec2f::Zero();
|
||||||
|
|
||||||
|
for (int r = -half_width; r <= half_width; ++r) {
|
||||||
|
for (int c = -half_width; c <= half_width; ++c) {
|
||||||
|
float xx1 = x1 + c;
|
||||||
|
float yy1 = y1 + r;
|
||||||
|
float xx2 = x2 + c;
|
||||||
|
float yy2 = y2 + r;
|
||||||
|
|
||||||
|
float I = SampleLinear(image_and_gradient1, yy1, xx1, 0);
|
||||||
|
float J = SampleLinear(image_and_gradient2, yy2, xx2, 0);
|
||||||
|
|
||||||
|
Vec2f gI, gJ;
|
||||||
|
gI << SampleLinear(image_and_gradient1, yy1, xx1, 1),
|
||||||
|
SampleLinear(image_and_gradient1, yy1, xx1, 2);
|
||||||
|
gJ << SampleLinear(image_and_gradient2, yy2, xx2, 1),
|
||||||
|
SampleLinear(image_and_gradient2, yy2, xx2, 2);
|
||||||
|
|
||||||
|
// Equation 15 from the paper.
|
||||||
|
A += gI * gI.transpose();
|
||||||
|
B += gI * gJ.transpose();
|
||||||
|
C += gJ * gJ.transpose();
|
||||||
|
R += I * gI;
|
||||||
|
S += J * gI;
|
||||||
|
V += I * gJ;
|
||||||
|
W += J * gJ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the paper they show a D matrix, but it is just B transpose, so use that
|
||||||
|
// instead of explicitly computing D.
|
||||||
|
Mat2f Di = B.transpose().inverse();
|
||||||
|
|
||||||
|
// Equation 14 from the paper.
|
||||||
|
*U = A*Di*C + lambda*Di*C - 0.5*B;
|
||||||
|
*e = (A + lambda*Mat2f::Identity())*Di*(V - W) + 0.5*(S - R);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TrkltRegionTracker::Track(const FloatImage &image1,
|
||||||
|
const FloatImage &image2,
|
||||||
|
double x1, double y1,
|
||||||
|
double *x2, double *y2) const {
|
||||||
|
Array3Df image_and_gradient1;
|
||||||
|
Array3Df image_and_gradient2;
|
||||||
|
BlurredImageAndDerivativesChannels(image1, sigma, &image_and_gradient1);
|
||||||
|
BlurredImageAndDerivativesChannels(image2, sigma, &image_and_gradient2);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
Vec2f d = Vec2f::Zero();
|
||||||
|
for (i = 0; i < max_iterations; ++i) {
|
||||||
|
// Compute gradient matrix and error vector.
|
||||||
|
Mat2f U;
|
||||||
|
Vec2f e;
|
||||||
|
ComputeTrackingEquation(image_and_gradient1,
|
||||||
|
image_and_gradient2,
|
||||||
|
x1, y1,
|
||||||
|
*x2, *y2,
|
||||||
|
half_window_size,
|
||||||
|
lambda,
|
||||||
|
&U, &e);
|
||||||
|
|
||||||
|
// Solve the linear system for the best update to x2 and y2.
|
||||||
|
d = U.lu().solve(e);
|
||||||
|
|
||||||
|
// Update the position with the solved displacement.
|
||||||
|
*x2 += d[0];
|
||||||
|
*y2 += d[1];
|
||||||
|
|
||||||
|
// Check for the quality of the solution, but not until having already
|
||||||
|
// updated the position with our best estimate. The reason to do the update
|
||||||
|
// anyway is that the user already knows the position is bad, so we may as
|
||||||
|
// well try our best.
|
||||||
|
float determinant = U.determinant();
|
||||||
|
if (fabs(determinant) < min_determinant) {
|
||||||
|
// The determinant, which indicates the trackiness of the point, is too
|
||||||
|
// small, so fail out.
|
||||||
|
LG << "Determinant " << determinant << " is too small; failing tracking.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the update is small, then we probably found the target.
|
||||||
|
if (d.squaredNorm() < min_update_squared_distance) {
|
||||||
|
LG << "Successful track in " << i << " iterations.";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Getting here means we hit max iterations, so tracking failed.
|
||||||
|
LG << "Too many iterations; max is set to " << max_iterations << ".";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
65
extern/libmv/libmv/tracking/trklt_region_tracker.h
vendored
Normal file
65
extern/libmv/libmv/tracking/trklt_region_tracker.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_REGION_TRACKING_TRKLT_REGION_TRACKER_H_
|
||||||
|
#define LIBMV_REGION_TRACKING_TRKLT_REGION_TRACKER_H_
|
||||||
|
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "libmv/tracking/region_tracker.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
// An improved KLT algorithm that enforces that the tracking is time-reversible
|
||||||
|
// [1]. This is not the same as the "symmetric" KLT that is sometimes used.
|
||||||
|
// Anecdotally, this tracks much more consistently than vanilla KLT.
|
||||||
|
//
|
||||||
|
// [1] H. Wu, R. Chellappa, and A. Sankaranarayanan and S. Kevin Zhou. Robust
|
||||||
|
// visual tracking using the time-reversibility constraint. International
|
||||||
|
// Conference on Computer Vision (ICCV), Rio de Janeiro, October 2007.
|
||||||
|
//
|
||||||
|
struct TrkltRegionTracker : public RegionTracker {
|
||||||
|
TrkltRegionTracker()
|
||||||
|
: half_window_size(4),
|
||||||
|
max_iterations(100),
|
||||||
|
min_determinant(1e-6),
|
||||||
|
min_update_squared_distance(1e-6),
|
||||||
|
sigma(0.9),
|
||||||
|
lambda(0.05) {}
|
||||||
|
|
||||||
|
virtual ~TrkltRegionTracker() {}
|
||||||
|
|
||||||
|
// Tracker interface.
|
||||||
|
virtual bool Track(const FloatImage &image1,
|
||||||
|
const FloatImage &image2,
|
||||||
|
double x1, double y1,
|
||||||
|
double *x2, double *y2) const;
|
||||||
|
|
||||||
|
// No point in creating getters or setters.
|
||||||
|
int half_window_size;
|
||||||
|
int max_iterations;
|
||||||
|
double min_determinant;
|
||||||
|
double min_update_squared_distance;
|
||||||
|
double sigma;
|
||||||
|
double lambda;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_REGION_TRACKING_TRKLT_REGION_TRACKER_H_
|
||||||
4
extern/libmv/mkfiles.sh
vendored
Executable file
4
extern/libmv/mkfiles.sh
vendored
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
find ./libmv/ -type f | sed -r 's/^\.\///' > files.txt
|
||||||
|
find ./third_party/ -type f | sed -r 's/^\.\///' >> files.txt
|
||||||
122
extern/libmv/patches/bundle_tweaks.patch
vendored
Normal file
122
extern/libmv/patches/bundle_tweaks.patch
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
diff --git a/src/libmv/logging/logging.h b/src/libmv/logging/logging.h
|
||||||
|
index 067da52..af86c4b 100644
|
||||||
|
--- a/src/libmv/logging/logging.h
|
||||||
|
+++ b/src/libmv/logging/logging.h
|
||||||
|
@@ -21,7 +21,7 @@
|
||||||
|
#ifndef LIBMV_LOGGING_LOGGING_H
|
||||||
|
#define LIBMV_LOGGING_LOGGING_H
|
||||||
|
|
||||||
|
-#include "third_party/glog/src/glog/logging.h"
|
||||||
|
+#include "glog/logging.h"
|
||||||
|
|
||||||
|
#define LG LOG(INFO)
|
||||||
|
#define V0 LOG(INFO)
|
||||||
|
diff --git a/src/third_party/glog/src/glog/logging.h b/src/third_party/glog/src/glog/logging.h
|
||||||
|
index 57615ef..a58d478 100644
|
||||||
|
--- a/src/third_party/glog/src/glog/logging.h
|
||||||
|
+++ b/src/third_party/glog/src/glog/logging.h
|
||||||
|
@@ -33,6 +33,7 @@
|
||||||
|
// Pretty much everybody needs to #include this file so that they can
|
||||||
|
// log various happenings.
|
||||||
|
//
|
||||||
|
+
|
||||||
|
#ifndef _LOGGING_H_
|
||||||
|
#define _LOGGING_H_
|
||||||
|
|
||||||
|
diff --git a/src/third_party/glog/src/logging.cc b/src/third_party/glog/src/logging.cc
|
||||||
|
index 868898f..1bb3867 100644
|
||||||
|
--- a/src/third_party/glog/src/logging.cc
|
||||||
|
+++ b/src/third_party/glog/src/logging.cc
|
||||||
|
@@ -58,8 +58,8 @@
|
||||||
|
#include <errno.h> // for errno
|
||||||
|
#include <sstream>
|
||||||
|
#include "base/commandlineflags.h" // to get the program name
|
||||||
|
-#include "glog/logging.h"
|
||||||
|
-#include "glog/raw_logging.h"
|
||||||
|
+#include <glog/logging.h>
|
||||||
|
+#include <glog/raw_logging.h>
|
||||||
|
#include "base/googleinit.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_STACKTRACE
|
||||||
|
@@ -1232,7 +1232,9 @@ void LogMessage::RecordCrashReason(
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logging_fail() {
|
||||||
|
-#if defined(_DEBUG) && defined(_MSC_VER)
|
||||||
|
+// #if defined(_DEBUG) && defined(_MSC_VER)
|
||||||
|
+// doesn't work for my laptop (sergey)
|
||||||
|
+#if 0
|
||||||
|
// When debugging on windows, avoid the obnoxious dialog and make
|
||||||
|
// it possible to continue past a LOG(FATAL) in the debugger
|
||||||
|
_asm int 3
|
||||||
|
diff --git a/src/third_party/glog/src/raw_logging.cc b/src/third_party/glog/src/raw_logging.cc
|
||||||
|
index 50c6a71..b179a1e 100644
|
||||||
|
--- a/src/third_party/glog/src/raw_logging.cc
|
||||||
|
+++ b/src/third_party/glog/src/raw_logging.cc
|
||||||
|
@@ -42,8 +42,8 @@
|
||||||
|
#include <fcntl.h> // for open()
|
||||||
|
#include <time.h>
|
||||||
|
#include "config.h"
|
||||||
|
-#include "glog/logging.h" // To pick up flag settings etc.
|
||||||
|
-#include "glog/raw_logging.h"
|
||||||
|
+#include <glog/logging.h> // To pick up flag settings etc.
|
||||||
|
+#include <glog/raw_logging.h>
|
||||||
|
#include "base/commandlineflags.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_STACKTRACE
|
||||||
|
diff --git a/src/third_party/glog/src/utilities.h b/src/third_party/glog/src/utilities.h
|
||||||
|
index ee54f94..2d4e99e 100644
|
||||||
|
--- a/src/third_party/glog/src/utilities.h
|
||||||
|
+++ b/src/third_party/glog/src/utilities.h
|
||||||
|
@@ -79,7 +79,7 @@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
-#include "glog/logging.h"
|
||||||
|
+#include <glog/logging.h>
|
||||||
|
|
||||||
|
// There are three different ways we can try to get the stack trace:
|
||||||
|
//
|
||||||
|
diff --git a/src/third_party/glog/src/vlog_is_on.cc b/src/third_party/glog/src/vlog_is_on.cc
|
||||||
|
index ee0e412..ed88514 100644
|
||||||
|
--- a/src/third_party/glog/src/vlog_is_on.cc
|
||||||
|
+++ b/src/third_party/glog/src/vlog_is_on.cc
|
||||||
|
@@ -40,8 +40,8 @@
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include "base/commandlineflags.h"
|
||||||
|
-#include "glog/logging.h"
|
||||||
|
-#include "glog/raw_logging.h"
|
||||||
|
+#include <glog/logging.h>
|
||||||
|
+#include <glog/raw_logging.h>
|
||||||
|
#include "base/googleinit.h"
|
||||||
|
|
||||||
|
// glog doesn't have annotation
|
||||||
|
diff --git a/src/third_party/glog/src/windows/config.h b/src/third_party/glog/src/windows/config.h
|
||||||
|
index 114762e..682a1b9 100755
|
||||||
|
--- a/src/third_party/glog/src/windows/config.h
|
||||||
|
+++ b/src/third_party/glog/src/windows/config.h
|
||||||
|
@@ -19,7 +19,7 @@
|
||||||
|
#undef HAVE_LIBUNWIND_H
|
||||||
|
|
||||||
|
/* define if you have google gflags library */
|
||||||
|
-#undef HAVE_LIB_GFLAGS
|
||||||
|
+#define HAVE_LIB_GFLAGS 1
|
||||||
|
|
||||||
|
/* define if you have libunwind */
|
||||||
|
#undef HAVE_LIB_UNWIND
|
||||||
|
diff --git a/src/third_party/glog/src/windows/glog/logging.h b/src/third_party/glog/src/windows/glog/logging.h
|
||||||
|
index 7a6df74..de51586 100755
|
||||||
|
--- a/src/third_party/glog/src/windows/glog/logging.h
|
||||||
|
+++ b/src/third_party/glog/src/windows/glog/logging.h
|
||||||
|
@@ -82,8 +82,8 @@
|
||||||
|
#include <inttypes.h> // a third place for uint16_t or u_int16_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-#if 0
|
||||||
|
-#include <gflags/gflags.h>
|
||||||
|
+#if 1
|
||||||
|
+#include "third_party/gflags/gflags.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace google {
|
||||||
13
extern/libmv/patches/config_mac.patch
vendored
Normal file
13
extern/libmv/patches/config_mac.patch
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/src/third_party/glog/src/config_mac.h b/src/third_party/glog/src/config_mac.h
|
||||||
|
index a45575b..5f953d1 100644
|
||||||
|
--- a/src/third_party/glog/src/config_mac.h
|
||||||
|
+++ b/src/third_party/glog/src/config_mac.h
|
||||||
|
@@ -131,7 +131,7 @@
|
||||||
|
#define PACKAGE_VERSION "0.3.1"
|
||||||
|
|
||||||
|
/* How to access the PC from a struct ucontext */
|
||||||
|
-#define PC_FROM_UCONTEXT uc_mcontext->__ss.__rip
|
||||||
|
+#undef PC_FROM_UCONTEXT
|
||||||
|
|
||||||
|
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||||
|
your system. */
|
||||||
181
extern/libmv/patches/detect.patch
vendored
Normal file
181
extern/libmv/patches/detect.patch
vendored
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
diff --git a/src/libmv/simple_pipeline/detect.cc b/src/libmv/simple_pipeline/detect.cc
|
||||||
|
index 6fc0cdd..8ac42ab 100644
|
||||||
|
--- a/src/libmv/simple_pipeline/detect.cc
|
||||||
|
+++ b/src/libmv/simple_pipeline/detect.cc
|
||||||
|
@@ -23,15 +23,89 @@
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/detect.h"
|
||||||
|
+#include <third_party/fast/fast.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
-#include <string.h>
|
||||||
|
+#include <memory.h>
|
||||||
|
+
|
||||||
|
+#ifdef __SSE2__
|
||||||
|
+#include <emmintrin.h>
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
typedef unsigned int uint;
|
||||||
|
|
||||||
|
+int featurecmp(const void *a_v, const void *b_v)
|
||||||
|
+{
|
||||||
|
+ Feature *a = (Feature*)a_v;
|
||||||
|
+ Feature *b = (Feature*)b_v;
|
||||||
|
+
|
||||||
|
+ return b->score - a->score;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+std::vector<Feature> DetectFAST(const unsigned char* data, int width, int height, int stride,
|
||||||
|
+ int min_trackness, int min_distance) {
|
||||||
|
+ std::vector<Feature> features;
|
||||||
|
+ // TODO(MatthiasF): Support targetting a feature count (binary search trackness)
|
||||||
|
+ int num_features;
|
||||||
|
+ xy* all = fast9_detect(data, width, height,
|
||||||
|
+ stride, min_trackness, &num_features);
|
||||||
|
+ if(num_features == 0) {
|
||||||
|
+ free(all);
|
||||||
|
+ return features;
|
||||||
|
+ }
|
||||||
|
+ int* scores = fast9_score(data, stride, all, num_features, min_trackness);
|
||||||
|
+ // TODO: merge with close feature suppression
|
||||||
|
+ xy* nonmax = nonmax_suppression(all, scores, num_features, &num_features);
|
||||||
|
+ free(all);
|
||||||
|
+ // Remove too close features
|
||||||
|
+ // TODO(MatthiasF): A resolution independent parameter would be better than distance
|
||||||
|
+ // e.g. a coefficient going from 0 (no minimal distance) to 1 (optimal circle packing)
|
||||||
|
+ // FIXME(MatthiasF): this method will not necessarily give all maximum markers
|
||||||
|
+ if(num_features) {
|
||||||
|
+ Feature *all_features = new Feature[num_features];
|
||||||
|
+
|
||||||
|
+ for(int i = 0; i < num_features; ++i) {
|
||||||
|
+ Feature a = { nonmax[i].x, nonmax[i].y, scores[i], 0 };
|
||||||
|
+ all_features[i] = a;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ qsort((void *)all_features, num_features, sizeof(Feature), featurecmp);
|
||||||
|
+
|
||||||
|
+ features.reserve(num_features);
|
||||||
|
+
|
||||||
|
+ int prev_score = all_features[0].score;
|
||||||
|
+ for(int i = 0; i < num_features; ++i) {
|
||||||
|
+ bool ok = true;
|
||||||
|
+ Feature a = all_features[i];
|
||||||
|
+ if(a.score>prev_score)
|
||||||
|
+ abort();
|
||||||
|
+ prev_score = a.score;
|
||||||
|
+
|
||||||
|
+ // compare each feature against filtered set
|
||||||
|
+ for(int j = 0; j < features.size(); j++) {
|
||||||
|
+ Feature& b = features[j];
|
||||||
|
+ if ( (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) < min_distance*min_distance ) {
|
||||||
|
+ // already a nearby feature
|
||||||
|
+ ok = false;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if(ok) {
|
||||||
|
+ // add the new feature
|
||||||
|
+ features.push_back(a);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ delete [] all_features;
|
||||||
|
+ }
|
||||||
|
+ free(scores);
|
||||||
|
+ free(nonmax);
|
||||||
|
+ return features;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#ifdef __SSE2__
|
||||||
|
-#include <emmintrin.h>
|
||||||
|
static uint SAD(const ubyte* imageA, const ubyte* imageB, int strideA, int strideB) {
|
||||||
|
__m128i a = _mm_setzero_si128();
|
||||||
|
for(int i = 0; i < 16; i++) {
|
||||||
|
@@ -52,7 +126,7 @@ static uint SAD(const ubyte* imageA, const ubyte* imageB, int strideA, int strid
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-void Detect(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance, ubyte* pattern) {
|
||||||
|
+void DetectMORAVEC(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance, ubyte* pattern) {
|
||||||
|
unsigned short histogram[256];
|
||||||
|
memset(histogram,0,sizeof(histogram));
|
||||||
|
ubyte* scores = new ubyte[width*height];
|
||||||
|
diff --git a/src/libmv/simple_pipeline/detect.h b/src/libmv/simple_pipeline/detect.h
|
||||||
|
index 23b239b..bbe7aed 100644
|
||||||
|
--- a/src/libmv/simple_pipeline/detect.h
|
||||||
|
+++ b/src/libmv/simple_pipeline/detect.h
|
||||||
|
@@ -25,27 +25,52 @@
|
||||||
|
#ifndef LIBMV_SIMPLE_PIPELINE_DETECT_H_
|
||||||
|
#define LIBMV_SIMPLE_PIPELINE_DETECT_H_
|
||||||
|
|
||||||
|
-#ifdef __cplusplus
|
||||||
|
+#include <vector>
|
||||||
|
+
|
||||||
|
namespace libmv {
|
||||||
|
-#endif
|
||||||
|
|
||||||
|
typedef unsigned char ubyte;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
- \a Feature is the 2D location of a detected feature in an image.
|
||||||
|
+ A Feature is the 2D location of a detected feature in an image.
|
||||||
|
|
||||||
|
- \a x, \a y is the position of the center in pixels (from image top-left).
|
||||||
|
- \a score is an estimate of how well the pattern will be tracked.
|
||||||
|
- \a size can be used as an initial size to track the pattern.
|
||||||
|
+ \a x, \a y is the position of the feature in pixels from the top left corner.
|
||||||
|
+ \a score is an estimate of how well the feature will be tracked.
|
||||||
|
+ \a size can be used as an initial pattern size to track the feature.
|
||||||
|
|
||||||
|
\sa Detect
|
||||||
|
*/
|
||||||
|
struct Feature {
|
||||||
|
+ /// Position in pixels (from top-left corner)
|
||||||
|
+ /// \note libmv might eventually support subpixel precision.
|
||||||
|
float x, y;
|
||||||
|
+ /// Trackness of the feature
|
||||||
|
float score;
|
||||||
|
+ /// Size of the feature in pixels
|
||||||
|
float size;
|
||||||
|
};
|
||||||
|
- //radius for non maximal suppression
|
||||||
|
+
|
||||||
|
+/*!
|
||||||
|
+ Detect features in an image.
|
||||||
|
+
|
||||||
|
+ You need to input a single channel 8-bit image using pointer to image \a data,
|
||||||
|
+ \a width, \a height and \a stride (i.e bytes per line).
|
||||||
|
+
|
||||||
|
+ You can tweak the count of detected features using \a min_trackness, which is
|
||||||
|
+ the minimum score to add a feature, and \a min_distance which is the minimal
|
||||||
|
+ distance accepted between two featuress.
|
||||||
|
+
|
||||||
|
+ \note You can binary search over \a min_trackness to get a given feature count.
|
||||||
|
+
|
||||||
|
+ \note a way to get an uniform distribution of a given feature count is:
|
||||||
|
+ \a min_distance = \a width * \a height / desired_feature_count ^ 2
|
||||||
|
+
|
||||||
|
+ \return All detected feartures matching given parameters
|
||||||
|
+*/
|
||||||
|
+std::vector<Feature> DetectFAST(const unsigned char* data, int width, int height,
|
||||||
|
+ int stride, int min_trackness = 128,
|
||||||
|
+ int min_distance = 120);
|
||||||
|
+
|
||||||
|
/*!
|
||||||
|
Detect features in an image.
|
||||||
|
|
||||||
|
@@ -63,10 +88,8 @@ struct Feature {
|
||||||
|
\note \a You can crop the image (to avoid detecting markers near the borders) without copying:
|
||||||
|
image += marginY*stride+marginX, width -= 2*marginX, height -= 2*marginY;
|
||||||
|
*/
|
||||||
|
-void Detect(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance /*=32*/, ubyte* pattern /*=0*/);
|
||||||
|
+void DetectMORAVEC(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance /*=32*/, ubyte* pattern /*=0*/);
|
||||||
|
|
||||||
|
-#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
-#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
24
extern/libmv/patches/fast.patch
vendored
Normal file
24
extern/libmv/patches/fast.patch
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
diff --git a/src/third_party/fast/fast.h b/src/third_party/fast/fast.h
|
||||||
|
index 2b3825a..06fa90e 100644
|
||||||
|
--- a/src/third_party/fast/fast.h
|
||||||
|
+++ b/src/third_party/fast/fast.h
|
||||||
|
@@ -1,6 +1,10 @@
|
||||||
|
#ifndef FAST_H
|
||||||
|
#define FAST_H
|
||||||
|
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
typedef struct { int x, y; } xy;
|
||||||
|
typedef unsigned char byte;
|
||||||
|
|
||||||
|
@@ -28,4 +32,8 @@ xy* fast12_detect_nonmax(const byte* im, int xsize, int ysize, int stride, int b
|
||||||
|
xy* nonmax_suppression(const xy* corners, const int* scores, int num_corners, int* ret_num_nonmax);
|
||||||
|
|
||||||
|
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#endif
|
||||||
21
extern/libmv/patches/function_derivative.patch
vendored
Normal file
21
extern/libmv/patches/function_derivative.patch
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
diff --git a/src/libmv/numeric/function_derivative.h b/src/libmv/numeric/function_derivative.h
|
||||||
|
index 0075d23..d7bc437 100644
|
||||||
|
--- a/src/libmv/numeric/function_derivative.h
|
||||||
|
+++ b/src/libmv/numeric/function_derivative.h
|
||||||
|
@@ -24,6 +24,7 @@
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
+#include "libmv/logging/logging.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
@@ -97,7 +98,7 @@ bool CheckJacobian(const Function &f, const typename Function::XMatrixType &x) {
|
||||||
|
|
||||||
|
typename NumericJacobian<Function>::JMatrixType J_numeric = j_numeric(x);
|
||||||
|
typename NumericJacobian<Function>::JMatrixType J_analytic = j_analytic(x);
|
||||||
|
- //LG << J_numeric - J_analytic;
|
||||||
|
+ LG << J_numeric - J_analytic;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
21
extern/libmv/patches/high_distortion_crash_fix.patch
vendored
Normal file
21
extern/libmv/patches/high_distortion_crash_fix.patch
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
diff --git a/src/libmv/simple_pipeline/camera_intrinsics.cc b/src/libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
|
index 4e88e1f..f9888ff 100644
|
||||||
|
--- a/src/libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
|
+++ b/src/libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
|
@@ -160,9 +160,13 @@ void CameraIntrinsics::ComputeLookupGrid(Offset* grid, int width, int height) {
|
||||||
|
if( iy < 0 ) { iy = 0, fy = 0; }
|
||||||
|
if( ix >= width-2 ) ix = width-2;
|
||||||
|
if( iy >= height-2 ) iy = height-2;
|
||||||
|
- //assert( ix-x > -128 && ix-x < 128 && iy-y > -128 && iy-y < 128 );
|
||||||
|
- Offset offset = { ix-x, iy-y, fx, fy };
|
||||||
|
- grid[y*width+x] = offset;
|
||||||
|
+ if ( ix-x > -128 && ix-x < 128 && iy-y > -128 && iy-y < 128 ) {
|
||||||
|
+ Offset offset = { ix-x, iy-y, fx, fy };
|
||||||
|
+ grid[y*width+x] = offset;
|
||||||
|
+ } else {
|
||||||
|
+ Offset offset = { 0, 0, 0, 0 };
|
||||||
|
+ grid[y*width+x] = offset;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
71
extern/libmv/patches/levenberg_marquardt.patch
vendored
Normal file
71
extern/libmv/patches/levenberg_marquardt.patch
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
diff --git a/src/libmv/numeric/levenberg_marquardt.h b/src/libmv/numeric/levenberg_marquardt.h
|
||||||
|
index 6a54f66..4473b72 100644
|
||||||
|
--- a/src/libmv/numeric/levenberg_marquardt.h
|
||||||
|
+++ b/src/libmv/numeric/levenberg_marquardt.h
|
||||||
|
@@ -33,6 +33,7 @@
|
||||||
|
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/numeric/function_derivative.h"
|
||||||
|
+#include "libmv/logging/logging.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
@@ -123,26 +124,40 @@ class LevenbergMarquardt {
|
||||||
|
Parameters dx, x_new;
|
||||||
|
int i;
|
||||||
|
for (i = 0; results.status == RUNNING && i < params.max_iterations; ++i) {
|
||||||
|
- if (dx.norm() <= params.relative_step_threshold * x.norm()) {
|
||||||
|
+ 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;
|
||||||
|
- }
|
||||||
|
- 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;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
+ }
|
||||||
|
+ 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.
|
||||||
171
extern/libmv/patches/mingw.patch
vendored
Normal file
171
extern/libmv/patches/mingw.patch
vendored
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
diff --git a/src/libmv/multiview/euclidean_resection.cc b/src/libmv/multiview/euclidean_resection.cc
|
||||||
|
index 6d918a1..9286251 100644
|
||||||
|
--- a/src/libmv/multiview/euclidean_resection.cc
|
||||||
|
+++ b/src/libmv/multiview/euclidean_resection.cc
|
||||||
|
@@ -32,6 +32,8 @@
|
||||||
|
namespace libmv {
|
||||||
|
namespace euclidean_resection {
|
||||||
|
|
||||||
|
+typedef unsigned int uint;
|
||||||
|
+
|
||||||
|
bool EuclideanResection(const Mat2X &x_camera,
|
||||||
|
const Mat3X &X_world,
|
||||||
|
Mat3 *R, Vec3 *t,
|
||||||
|
diff --git a/src/libmv/numeric/numeric.h b/src/libmv/numeric/numeric.h
|
||||||
|
index f39d126..21e0f06 100644
|
||||||
|
--- a/src/libmv/numeric/numeric.h
|
||||||
|
+++ b/src/libmv/numeric/numeric.h
|
||||||
|
@@ -40,7 +40,7 @@
|
||||||
|
}
|
||||||
|
#endif //_WIN32 || __APPLE__
|
||||||
|
|
||||||
|
-#if _WIN32
|
||||||
|
+#if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__)
|
||||||
|
inline long lround(double d) {
|
||||||
|
return (long)(d>0 ? d+0.5 : ceil(d-0.5));
|
||||||
|
}
|
||||||
|
diff --git a/src/third_party/glog/src/config.h b/src/third_party/glog/src/config.h
|
||||||
|
index ed8d56e..06ed686 100644
|
||||||
|
--- a/src/third_party/glog/src/config.h
|
||||||
|
+++ b/src/third_party/glog/src/config.h
|
||||||
|
@@ -4,6 +4,8 @@
|
||||||
|
/* Namespace for Google classes */
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "config_mac.h"
|
||||||
|
+#elif __MINGW32__
|
||||||
|
+ #include "windows/config.h"
|
||||||
|
#elif __GNUC__
|
||||||
|
#include "config_linux.h"
|
||||||
|
#elif _MSC_VER
|
||||||
|
diff --git a/src/third_party/glog/src/utilities.h b/src/third_party/glog/src/utilities.h
|
||||||
|
index ee54f94..c4ae256 100644
|
||||||
|
--- a/src/third_party/glog/src/utilities.h
|
||||||
|
+++ b/src/third_party/glog/src/utilities.h
|
||||||
|
@@ -101,7 +101,9 @@
|
||||||
|
// correctly when GetStackTrace() is called with max_depth == 0.
|
||||||
|
// Some code may do that.
|
||||||
|
|
||||||
|
-#if defined(HAVE_LIB_UNWIND)
|
||||||
|
+#if __MINGW32__
|
||||||
|
+# undef STACKTRACE_H
|
||||||
|
+#elif defined(HAVE_LIB_UNWIND)
|
||||||
|
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
|
||||||
|
#elif !defined(NO_FRAME_POINTER)
|
||||||
|
# if defined(__i386__) && __GNUC__ >= 2
|
||||||
|
diff --git a/src/third_party/glog/src/windows/glog/logging.h b/src/third_party/glog/src/windows/glog/logging.h
|
||||||
|
index 7a6df74..4257375 100755
|
||||||
|
--- a/src/third_party/glog/src/windows/glog/logging.h
|
||||||
|
+++ b/src/third_party/glog/src/windows/glog/logging.h
|
||||||
|
@@ -59,7 +59,7 @@
|
||||||
|
|
||||||
|
// Annoying stuff for windows -- makes sure clients can import these functions
|
||||||
|
#ifndef GOOGLE_GLOG_DLL_DECL
|
||||||
|
-# if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
|
||||||
|
# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
|
||||||
|
# else
|
||||||
|
# define GOOGLE_GLOG_DLL_DECL
|
||||||
|
@@ -86,6 +86,15 @@
|
||||||
|
#include <gflags/gflags.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifdef __MINGW32__
|
||||||
|
+# include <stdlib.h>
|
||||||
|
+# include <unistd.h>
|
||||||
|
+# include <stdint.h> // the normal place uint16_t is defined
|
||||||
|
+# include <sys/types.h> // the normal place u_int16_t is defined
|
||||||
|
+# include <inttypes.h> // a third place for uint16_t or u_int16_t
|
||||||
|
+# define _exit(x) exit(x)
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
namespace google {
|
||||||
|
|
||||||
|
#if 0 // the C99 format
|
||||||
|
@@ -98,11 +107,16 @@ typedef int32_t int32;
|
||||||
|
typedef u_int32_t uint32;
|
||||||
|
typedef int64_t int64;
|
||||||
|
typedef u_int64_t uint64;
|
||||||
|
-#elif 1 // the windows (vc7) format
|
||||||
|
+#elif defined(_MSC_VER)
|
||||||
|
typedef __int32 int32;
|
||||||
|
typedef unsigned __int32 uint32;
|
||||||
|
typedef __int64 int64;
|
||||||
|
typedef unsigned __int64 uint64;
|
||||||
|
+#elif defined(__MINGW32__)
|
||||||
|
+typedef int32_t int32;
|
||||||
|
+typedef uint32_t uint32;
|
||||||
|
+typedef int64_t int64;
|
||||||
|
+typedef uint64_t uint64;
|
||||||
|
#else
|
||||||
|
#error Do not know how to define a 32-bit integer quantity on your system
|
||||||
|
#endif
|
||||||
|
diff --git a/src/third_party/glog/src/windows/port.h b/src/third_party/glog/src/windows/port.h
|
||||||
|
index d093bf5..d507812 100755
|
||||||
|
--- a/src/third_party/glog/src/windows/port.h
|
||||||
|
+++ b/src/third_party/glog/src/windows/port.h
|
||||||
|
@@ -59,14 +59,16 @@
|
||||||
|
* used by both C and C++ code, so we put all the C++ together.
|
||||||
|
*/
|
||||||
|
|
||||||
|
-/* 4244: otherwise we get problems when substracting two size_t's to an int
|
||||||
|
- * 4251: it's complaining about a private struct I've chosen not to dllexport
|
||||||
|
- * 4355: we use this in a constructor, but we do it safely
|
||||||
|
- * 4715: for some reason VC++ stopped realizing you can't return after abort()
|
||||||
|
- * 4800: we know we're casting ints/char*'s to bools, and we're ok with that
|
||||||
|
- * 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
|
||||||
|
- */
|
||||||
|
-#pragma warning(disable:4244 4251 4355 4715 4800 4996)
|
||||||
|
+#if _MSC_VER
|
||||||
|
+ /* 4244: otherwise we get problems when substracting two size_t's to an int
|
||||||
|
+ * 4251: it's complaining about a private struct I've chosen not to dllexport
|
||||||
|
+ * 4355: we use this in a constructor, but we do it safely
|
||||||
|
+ * 4715: for some reason VC++ stopped realizing you can't return after abort()
|
||||||
|
+ * 4800: we know we're casting ints/char*'s to bools, and we're ok with that
|
||||||
|
+ * 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
|
||||||
|
+ */
|
||||||
|
+# pragma warning(disable:4244 4251 4355 4715 4800 4996)
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
/* file I/O */
|
||||||
|
#define PATH_MAX 1024
|
||||||
|
@@ -108,7 +110,9 @@ extern int snprintf(char *str, size_t size,
|
||||||
|
extern int safe_vsnprintf(char *str, size_t size,
|
||||||
|
const char *format, va_list ap);
|
||||||
|
#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
|
||||||
|
+#if !defined(__MINGW32__)
|
||||||
|
#define va_copy(dst, src) (dst) = (src)
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
/* Windows doesn't support specifying the number of buckets as a
|
||||||
|
* hash_map constructor arg, so we leave this blank.
|
||||||
|
@@ -130,13 +134,30 @@ enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
|
||||||
|
#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
|
||||||
|
|
||||||
|
inline struct tm* localtime_r(const time_t* timep, struct tm* result) {
|
||||||
|
+#if __MINGW32__
|
||||||
|
+ struct tm *local_result;
|
||||||
|
+ local_result = localtime (timep);
|
||||||
|
+
|
||||||
|
+ if (local_result == NULL || result == NULL)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ memcpy (result, local_result, sizeof (result));
|
||||||
|
+
|
||||||
|
+ return result;
|
||||||
|
+#else
|
||||||
|
localtime_s(result, timep);
|
||||||
|
return result;
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* strerror_r(int errnum, char* buf, size_t buflen) {
|
||||||
|
+#if __MINGW32__
|
||||||
|
+ strncpy(buf, "Not implemented yet", buflen);
|
||||||
|
+ return buf;
|
||||||
|
+#else
|
||||||
|
strerror_s(buf, buflen, errnum);
|
||||||
|
return buf;
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
12
extern/libmv/patches/msvc2010.patch
vendored
Normal file
12
extern/libmv/patches/msvc2010.patch
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
diff --git a/src/libmv/simple_pipeline/tracks.cc b/src/libmv/simple_pipeline/tracks.cc
|
||||||
|
index 0e2a1b6..3fb8ddb 100644
|
||||||
|
--- a/src/libmv/simple_pipeline/tracks.cc
|
||||||
|
+++ b/src/libmv/simple_pipeline/tracks.cc
|
||||||
|
@@ -20,6 +20,7 @@
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
+#include <iterator>
|
||||||
|
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
182
extern/libmv/patches/overscan.patch
vendored
Normal file
182
extern/libmv/patches/overscan.patch
vendored
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
diff --git a/src/libmv/simple_pipeline/camera_intrinsics.cc b/src/libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
|
index 110a16d..366129d 100644
|
||||||
|
--- a/src/libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
|
+++ b/src/libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
|
@@ -31,6 +31,7 @@ struct Offset {
|
||||||
|
struct Grid {
|
||||||
|
struct Offset *offset;
|
||||||
|
int width, height;
|
||||||
|
+ double overscan;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct Grid *copyGrid(struct Grid *from)
|
||||||
|
@@ -42,6 +43,7 @@ static struct Grid *copyGrid(struct Grid *from)
|
||||||
|
|
||||||
|
to->width = from->width;
|
||||||
|
to->height = from->height;
|
||||||
|
+ to->overscan = from->overscan;
|
||||||
|
|
||||||
|
to->offset = new Offset[to->width*to->height];
|
||||||
|
memcpy(to->offset, from->offset, sizeof(struct Offset)*to->width*to->height);
|
||||||
|
@@ -184,17 +186,19 @@ void CameraIntrinsics::InvertIntrinsics(double image_x,
|
||||||
|
|
||||||
|
// TODO(MatthiasF): downsample lookup
|
||||||
|
template<typename WarpFunction>
|
||||||
|
-void CameraIntrinsics::ComputeLookupGrid(Grid* grid, int width, int height) {
|
||||||
|
- double aspx = (double)width / image_width_;
|
||||||
|
- double aspy = (double)height / image_height_;
|
||||||
|
+void CameraIntrinsics::ComputeLookupGrid(Grid* grid, int width, int height, double overscan) {
|
||||||
|
+ double w = (double)width / (1 + overscan);
|
||||||
|
+ double h = (double)height / (1 + overscan);
|
||||||
|
+ double aspx = (double)w / image_width_;
|
||||||
|
+ double aspy = (double)h / image_height_;
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
- double src_x = x / aspx, src_y = y / aspy;
|
||||||
|
+ double src_x = (x - 0.5 * overscan * w) / aspx, src_y = (y - 0.5 * overscan * h) / aspy;
|
||||||
|
double warp_x, warp_y;
|
||||||
|
WarpFunction(this,src_x,src_y,&warp_x,&warp_y);
|
||||||
|
- warp_x = warp_x*aspx;
|
||||||
|
- warp_y = warp_y*aspy;
|
||||||
|
+ warp_x = warp_x*aspx + 0.5 * overscan * w;
|
||||||
|
+ warp_y = warp_y*aspy + 0.5 * overscan * h;
|
||||||
|
int ix = int(warp_x), iy = int(warp_y);
|
||||||
|
int fx = round((warp_x-ix)*256), fy = round((warp_y-iy)*256);
|
||||||
|
if(fx == 256) { fx=0; ix++; }
|
||||||
|
@@ -264,10 +268,10 @@ struct InvertIntrinsicsFunction {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
-void CameraIntrinsics::CheckDistortLookupGrid(int width, int height)
|
||||||
|
+void CameraIntrinsics::CheckDistortLookupGrid(int width, int height, double overscan)
|
||||||
|
{
|
||||||
|
if(distort_) {
|
||||||
|
- if(distort_->width != width || distort_->height != height) {
|
||||||
|
+ if(distort_->width != width || distort_->height != height || distort_->overscan != overscan) {
|
||||||
|
delete [] distort_->offset;
|
||||||
|
distort_->offset = NULL;
|
||||||
|
}
|
||||||
|
@@ -278,17 +282,18 @@ void CameraIntrinsics::CheckDistortLookupGrid(int width, int height)
|
||||||
|
|
||||||
|
if(!distort_->offset) {
|
||||||
|
distort_->offset = new Offset[width*height];
|
||||||
|
- ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height);
|
||||||
|
+ ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height,overscan);
|
||||||
|
}
|
||||||
|
|
||||||
|
distort_->width = width;
|
||||||
|
distort_->height = height;
|
||||||
|
+ distort_->overscan = overscan;
|
||||||
|
}
|
||||||
|
|
||||||
|
-void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height)
|
||||||
|
+void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height, double overscan)
|
||||||
|
{
|
||||||
|
if(undistort_) {
|
||||||
|
- if(undistort_->width != width || undistort_->height != height) {
|
||||||
|
+ if(undistort_->width != width || undistort_->height != height || undistort_->overscan != overscan) {
|
||||||
|
delete [] undistort_->offset;
|
||||||
|
undistort_->offset = NULL;
|
||||||
|
}
|
||||||
|
@@ -299,15 +304,16 @@ void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height)
|
||||||
|
|
||||||
|
if(!undistort_->offset) {
|
||||||
|
undistort_->offset = new Offset[width*height];
|
||||||
|
- ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height);
|
||||||
|
+ ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height,overscan);
|
||||||
|
}
|
||||||
|
|
||||||
|
undistort_->width = width;
|
||||||
|
undistort_->height = height;
|
||||||
|
+ undistort_->overscan = overscan;
|
||||||
|
}
|
||||||
|
|
||||||
|
-void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, int channels) {
|
||||||
|
- CheckDistortLookupGrid(width, height);
|
||||||
|
+void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, double overscan, int channels) {
|
||||||
|
+ CheckDistortLookupGrid(width, height, overscan);
|
||||||
|
if(channels==1) Warp<float,1>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<float,2>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<float,3>(distort_,src,dst,width,height);
|
||||||
|
@@ -315,8 +321,8 @@ void CameraIntrinsics::Distort(const float* src, float* dst, int width, int heig
|
||||||
|
//else assert("channels must be between 1 and 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
-void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int width, int height, int channels) {
|
||||||
|
- CheckDistortLookupGrid(width, height);
|
||||||
|
+void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int width, int height, double overscan, int channels) {
|
||||||
|
+ CheckDistortLookupGrid(width, height, overscan);
|
||||||
|
if(channels==1) Warp<unsigned char,1>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<unsigned char,2>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<unsigned char,3>(distort_,src,dst,width,height);
|
||||||
|
@@ -324,8 +330,8 @@ void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int
|
||||||
|
//else assert("channels must be between 1 and 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
-void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int height, int channels) {
|
||||||
|
- CheckUndistortLookupGrid(width, height);
|
||||||
|
+void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int height, double overscan, int channels) {
|
||||||
|
+ CheckUndistortLookupGrid(width, height, overscan);
|
||||||
|
if(channels==1) Warp<float,1>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<float,2>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<float,3>(undistort_,src,dst,width,height);
|
||||||
|
@@ -333,8 +339,8 @@ void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int he
|
||||||
|
//else assert("channels must be between 1 and 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
-void CameraIntrinsics::Undistort(const unsigned char* src, unsigned char* dst, int width, int height, int channels) {
|
||||||
|
- CheckUndistortLookupGrid(width, height);
|
||||||
|
+void CameraIntrinsics::Undistort(const unsigned char* src, unsigned char* dst, int width, int height, double overscan, int channels) {
|
||||||
|
+ CheckUndistortLookupGrid(width, height, overscan);
|
||||||
|
if(channels==1) Warp<unsigned char,1>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<unsigned char,2>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<unsigned char,3>(undistort_,src,dst,width,height);
|
||||||
|
diff --git a/src/libmv/simple_pipeline/camera_intrinsics.h b/src/libmv/simple_pipeline/camera_intrinsics.h
|
||||||
|
index f525571..f4bf903 100644
|
||||||
|
--- a/src/libmv/simple_pipeline/camera_intrinsics.h
|
||||||
|
+++ b/src/libmv/simple_pipeline/camera_intrinsics.h
|
||||||
|
@@ -91,7 +91,7 @@ class CameraIntrinsics {
|
||||||
|
\note This is the reference implementation using floating point images.
|
||||||
|
*/
|
||||||
|
void Distort(const float* src, float* dst,
|
||||||
|
- int width, int height, int channels);
|
||||||
|
+ int width, int height, double overscan, int channels);
|
||||||
|
/*!
|
||||||
|
Distort an image using the current camera instrinsics
|
||||||
|
|
||||||
|
@@ -101,7 +101,7 @@ class CameraIntrinsics {
|
||||||
|
\note This version is much faster.
|
||||||
|
*/
|
||||||
|
void Distort(const unsigned char* src, unsigned char* dst,
|
||||||
|
- int width, int height, int channels);
|
||||||
|
+ int width, int height, double overscan, int channels);
|
||||||
|
/*!
|
||||||
|
Undistort an image using the current camera instrinsics
|
||||||
|
|
||||||
|
@@ -111,7 +111,7 @@ class CameraIntrinsics {
|
||||||
|
\note This is the reference implementation using floating point images.
|
||||||
|
*/
|
||||||
|
void Undistort(const float* src, float* dst,
|
||||||
|
- int width, int height, int channels);
|
||||||
|
+ int width, int height, double overscan, int channels);
|
||||||
|
/*!
|
||||||
|
Undistort an image using the current camera instrinsics
|
||||||
|
|
||||||
|
@@ -121,12 +121,12 @@ class CameraIntrinsics {
|
||||||
|
\note This version is much faster.
|
||||||
|
*/
|
||||||
|
void Undistort(const unsigned char* src, unsigned char* dst,
|
||||||
|
- int width, int height, int channels);
|
||||||
|
+ int width, int height, double overscan, int channels);
|
||||||
|
|
||||||
|
private:
|
||||||
|
- template<typename WarpFunction> void ComputeLookupGrid(struct Grid* grid, int width, int height);
|
||||||
|
- void CheckUndistortLookupGrid(int width, int height);
|
||||||
|
- void CheckDistortLookupGrid(int width, int height);
|
||||||
|
+ template<typename WarpFunction> void ComputeLookupGrid(struct Grid* grid, int width, int height, double overscan);
|
||||||
|
+ void CheckUndistortLookupGrid(int width, int height, double overscan);
|
||||||
|
+ void CheckDistortLookupGrid(int width, int height, double overscan);
|
||||||
|
void FreeLookupGrid();
|
||||||
|
|
||||||
|
// The traditional intrinsics matrix from x = K[R|t]X.
|
||||||
261
extern/libmv/patches/scaled_distortion.patch
vendored
Normal file
261
extern/libmv/patches/scaled_distortion.patch
vendored
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
diff --git a/src/libmv/simple_pipeline/camera_intrinsics.cc b/src/libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
|
index f9888ff..110a16d 100644
|
||||||
|
--- a/src/libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
|
+++ b/src/libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
|
@@ -23,7 +23,32 @@
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
-struct Offset { signed char ix,iy; unsigned char fx,fy; };
|
||||||
|
+struct Offset {
|
||||||
|
+ signed char ix, iy;
|
||||||
|
+ unsigned char fx,fy;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct Grid {
|
||||||
|
+ struct Offset *offset;
|
||||||
|
+ int width, height;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct Grid *copyGrid(struct Grid *from)
|
||||||
|
+{
|
||||||
|
+ struct Grid *to = NULL;
|
||||||
|
+
|
||||||
|
+ if (from) {
|
||||||
|
+ to = new Grid;
|
||||||
|
+
|
||||||
|
+ to->width = from->width;
|
||||||
|
+ to->height = from->height;
|
||||||
|
+
|
||||||
|
+ to->offset = new Offset[to->width*to->height];
|
||||||
|
+ memcpy(to->offset, from->offset, sizeof(struct Offset)*to->width*to->height);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return to;
|
||||||
|
+}
|
||||||
|
|
||||||
|
CameraIntrinsics::CameraIntrinsics()
|
||||||
|
: K_(Mat3::Identity()),
|
||||||
|
@@ -37,9 +62,22 @@ CameraIntrinsics::CameraIntrinsics()
|
||||||
|
distort_(0),
|
||||||
|
undistort_(0) {}
|
||||||
|
|
||||||
|
+CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics &from)
|
||||||
|
+ : K_(from.K_),
|
||||||
|
+ image_width_(from.image_width_),
|
||||||
|
+ image_height_(from.image_height_),
|
||||||
|
+ k1_(from.k1_),
|
||||||
|
+ k2_(from.k2_),
|
||||||
|
+ k3_(from.k3_),
|
||||||
|
+ p1_(from.p1_),
|
||||||
|
+ p2_(from.p2_)
|
||||||
|
+{
|
||||||
|
+ distort_ = copyGrid(from.distort_);
|
||||||
|
+ undistort_ = copyGrid(from.undistort_);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
CameraIntrinsics::~CameraIntrinsics() {
|
||||||
|
- if(distort_) delete[] distort_;
|
||||||
|
- if(undistort_) delete[] undistort_;
|
||||||
|
+ FreeLookupGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the entire calibration matrix at once.
|
||||||
|
@@ -146,11 +184,17 @@ void CameraIntrinsics::InvertIntrinsics(double image_x,
|
||||||
|
|
||||||
|
// TODO(MatthiasF): downsample lookup
|
||||||
|
template<typename WarpFunction>
|
||||||
|
-void CameraIntrinsics::ComputeLookupGrid(Offset* grid, int width, int height) {
|
||||||
|
+void CameraIntrinsics::ComputeLookupGrid(Grid* grid, int width, int height) {
|
||||||
|
+ double aspx = (double)width / image_width_;
|
||||||
|
+ double aspy = (double)height / image_height_;
|
||||||
|
+
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
+ double src_x = x / aspx, src_y = y / aspy;
|
||||||
|
double warp_x, warp_y;
|
||||||
|
- WarpFunction(this,x,y,&warp_x,&warp_y);
|
||||||
|
+ WarpFunction(this,src_x,src_y,&warp_x,&warp_y);
|
||||||
|
+ warp_x = warp_x*aspx;
|
||||||
|
+ warp_y = warp_y*aspy;
|
||||||
|
int ix = int(warp_x), iy = int(warp_y);
|
||||||
|
int fx = round((warp_x-ix)*256), fy = round((warp_y-iy)*256);
|
||||||
|
if(fx == 256) { fx=0; ix++; }
|
||||||
|
@@ -162,10 +206,10 @@ void CameraIntrinsics::ComputeLookupGrid(Offset* grid, int width, int height) {
|
||||||
|
if( iy >= height-2 ) iy = height-2;
|
||||||
|
if ( ix-x > -128 && ix-x < 128 && iy-y > -128 && iy-y < 128 ) {
|
||||||
|
Offset offset = { ix-x, iy-y, fx, fy };
|
||||||
|
- grid[y*width+x] = offset;
|
||||||
|
+ grid->offset[y*width+x] = offset;
|
||||||
|
} else {
|
||||||
|
Offset offset = { 0, 0, 0, 0 };
|
||||||
|
- grid[y*width+x] = offset;
|
||||||
|
+ grid->offset[y*width+x] = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -173,11 +217,11 @@ void CameraIntrinsics::ComputeLookupGrid(Offset* grid, int width, int height) {
|
||||||
|
|
||||||
|
// TODO(MatthiasF): cubic B-Spline image sampling, bilinear lookup
|
||||||
|
template<typename T,int N>
|
||||||
|
-static void Warp(const Offset* grid, const T* src, T* dst,
|
||||||
|
+static void Warp(const Grid* grid, const T* src, T* dst,
|
||||||
|
int width, int height) {
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
- Offset offset = grid[y*width+x];
|
||||||
|
+ Offset offset = grid->offset[y*width+x];
|
||||||
|
const T* s = &src[((y+offset.iy)*width+(x+offset.ix))*N];
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
dst[(y*width+x)*N+i] = ((s[ i] * (256-offset.fx) + s[ N+i] * offset.fx) * (256-offset.fy)
|
||||||
|
@@ -188,8 +232,17 @@ static void Warp(const Offset* grid, const T* src, T* dst,
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::FreeLookupGrid() {
|
||||||
|
- if(distort_) delete distort_, distort_=0;
|
||||||
|
- if(undistort_) delete undistort_, undistort_=0;
|
||||||
|
+ if(distort_) {
|
||||||
|
+ delete distort_->offset;
|
||||||
|
+ delete distort_;
|
||||||
|
+ distort_ = NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if(undistort_) {
|
||||||
|
+ delete undistort_->offset;
|
||||||
|
+ delete undistort_;
|
||||||
|
+ undistort_ = NULL;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: C++ templates limitations makes thing complicated, but maybe there is a simpler method.
|
||||||
|
@@ -211,11 +264,50 @@ struct InvertIntrinsicsFunction {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
-void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, int channels) {
|
||||||
|
- if(!distort_) {
|
||||||
|
- distort_ = new Offset[width*height];
|
||||||
|
- ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height);
|
||||||
|
+void CameraIntrinsics::CheckDistortLookupGrid(int width, int height)
|
||||||
|
+{
|
||||||
|
+ if(distort_) {
|
||||||
|
+ if(distort_->width != width || distort_->height != height) {
|
||||||
|
+ delete [] distort_->offset;
|
||||||
|
+ distort_->offset = NULL;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ distort_ = new Grid;
|
||||||
|
+ distort_->offset = NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if(!distort_->offset) {
|
||||||
|
+ distort_->offset = new Offset[width*height];
|
||||||
|
+ ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ distort_->width = width;
|
||||||
|
+ distort_->height = height;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height)
|
||||||
|
+{
|
||||||
|
+ if(undistort_) {
|
||||||
|
+ if(undistort_->width != width || undistort_->height != height) {
|
||||||
|
+ delete [] undistort_->offset;
|
||||||
|
+ undistort_->offset = NULL;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ undistort_ = new Grid;
|
||||||
|
+ undistort_->offset = NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if(!undistort_->offset) {
|
||||||
|
+ undistort_->offset = new Offset[width*height];
|
||||||
|
+ ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ undistort_->width = width;
|
||||||
|
+ undistort_->height = height;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, int channels) {
|
||||||
|
+ CheckDistortLookupGrid(width, height);
|
||||||
|
if(channels==1) Warp<float,1>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<float,2>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<float,3>(distort_,src,dst,width,height);
|
||||||
|
@@ -224,10 +316,7 @@ void CameraIntrinsics::Distort(const float* src, float* dst, int width, int heig
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int width, int height, int channels) {
|
||||||
|
- if(!distort_) {
|
||||||
|
- distort_ = new Offset[width*height];
|
||||||
|
- ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height);
|
||||||
|
- }
|
||||||
|
+ CheckDistortLookupGrid(width, height);
|
||||||
|
if(channels==1) Warp<unsigned char,1>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<unsigned char,2>(distort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<unsigned char,3>(distort_,src,dst,width,height);
|
||||||
|
@@ -236,10 +325,7 @@ void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int height, int channels) {
|
||||||
|
- if(!undistort_) {
|
||||||
|
- undistort_ = new Offset[width*height];
|
||||||
|
- ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height);
|
||||||
|
- }
|
||||||
|
+ CheckUndistortLookupGrid(width, height);
|
||||||
|
if(channels==1) Warp<float,1>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<float,2>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<float,3>(undistort_,src,dst,width,height);
|
||||||
|
@@ -248,10 +334,7 @@ void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int he
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraIntrinsics::Undistort(const unsigned char* src, unsigned char* dst, int width, int height, int channels) {
|
||||||
|
- if(!undistort_) {
|
||||||
|
- undistort_ = new Offset[width*height];
|
||||||
|
- ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height);
|
||||||
|
- }
|
||||||
|
+ CheckUndistortLookupGrid(width, height);
|
||||||
|
if(channels==1) Warp<unsigned char,1>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==2) Warp<unsigned char,2>(undistort_,src,dst,width,height);
|
||||||
|
else if(channels==3) Warp<unsigned char,3>(undistort_,src,dst,width,height);
|
||||||
|
diff --git a/src/libmv/simple_pipeline/camera_intrinsics.h b/src/libmv/simple_pipeline/camera_intrinsics.h
|
||||||
|
index 29bc8a1..f525571 100644
|
||||||
|
--- a/src/libmv/simple_pipeline/camera_intrinsics.h
|
||||||
|
+++ b/src/libmv/simple_pipeline/camera_intrinsics.h
|
||||||
|
@@ -26,11 +26,12 @@ typedef Eigen::Matrix<double, 3, 3> Mat3;
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
-struct Offset;
|
||||||
|
+struct Grid;
|
||||||
|
|
||||||
|
class CameraIntrinsics {
|
||||||
|
public:
|
||||||
|
CameraIntrinsics();
|
||||||
|
+ CameraIntrinsics(const CameraIntrinsics &from);
|
||||||
|
~CameraIntrinsics();
|
||||||
|
|
||||||
|
const Mat3 &K() const { return K_; }
|
||||||
|
@@ -123,7 +124,9 @@ class CameraIntrinsics {
|
||||||
|
int width, int height, int channels);
|
||||||
|
|
||||||
|
private:
|
||||||
|
- template<typename WarpFunction> void ComputeLookupGrid(Offset* grid, int width, int height);
|
||||||
|
+ template<typename WarpFunction> void ComputeLookupGrid(struct Grid* grid, int width, int height);
|
||||||
|
+ void CheckUndistortLookupGrid(int width, int height);
|
||||||
|
+ void CheckDistortLookupGrid(int width, int height);
|
||||||
|
void FreeLookupGrid();
|
||||||
|
|
||||||
|
// The traditional intrinsics matrix from x = K[R|t]X.
|
||||||
|
@@ -140,8 +143,8 @@ class CameraIntrinsics {
|
||||||
|
// independent of image size.
|
||||||
|
double k1_, k2_, k3_, p1_, p2_;
|
||||||
|
|
||||||
|
- Offset* distort_;
|
||||||
|
- Offset* undistort_;
|
||||||
|
+ struct Grid *distort_;
|
||||||
|
+ struct Grid *undistort_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
13
extern/libmv/patches/series
vendored
Normal file
13
extern/libmv/patches/series
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
v3d_verbosity.patch
|
||||||
|
snrptinf_fix.patch
|
||||||
|
bundle_tweaks.patch
|
||||||
|
fast.patch
|
||||||
|
config_mac.patch
|
||||||
|
levenberg_marquardt.patch
|
||||||
|
function_derivative.patch
|
||||||
|
high_distortion_crash_fix.patch
|
||||||
|
mingw.patch
|
||||||
|
msvc2010.patch
|
||||||
|
scaled_distortion.patch
|
||||||
|
overscan.patch
|
||||||
|
detect.patch
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user