├── .gitignore ├── AUTHORS ├── CMakeLists.txt ├── FindBoost.cmake ├── FindOctave.cmake ├── INSTALL.md ├── LICENSE ├── README ├── cmake_uninstall.cmake.in ├── examples ├── test0.jpg ├── test1.jpg ├── test2.jpg └── testsiftfast.py ├── install_manifest.txt ├── libsiftfast.cpp ├── makerelease.sh ├── profiler.cpp ├── profiler.h ├── runcmake.bat ├── siftfast.cpp ├── siftfast.h ├── siftfast.m ├── siftfastpy.cpp └── siftmex.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.eprj 2 | *.svn 3 | *.pyc 4 | *.orig 5 | .DS_Store 6 | *~ 7 | \#*\# 8 | 9 | *.a 10 | *.o 11 | *.so 12 | *.dylib 13 | 14 | *.dmg 15 | *.jar 16 | 17 | *.hg 18 | *.hgignore 19 | .hg/* 20 | .hgignore 21 | 22 | *.dropbox 23 | .dropbox 24 | 25 | Icon* 26 | install_manifest.txt 27 | CMakeCache.txt 28 | CMakeFiles/ 29 | siftfast 30 | Makefile 31 | cmake_install.cmake 32 | cmake_uninstall.cmake 33 | 34 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | zerofrog(@gmail.com) -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # exact C++ implementation of lowe's sift program 2 | # author: zerofrog(@gmail.com), Sep 2008 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU Lesser General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # Lesser GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public License 15 | # along with this program. If not, see . 16 | cmake_minimum_required (VERSION 2.4.7) 17 | project (libsiftfast) 18 | set( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE ) 19 | set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}") 20 | 21 | # Differences between CMake 2.4 and 2.6 22 | if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" GREATER 2.4) 23 | message(STATUS "Using cmake version ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" ) 24 | # some developers may be using an cmake cvs version which didn't have set_property() yet 25 | # Tell them that a more recent version is required. 26 | if(NOT COMMAND SET_PROPERTY) 27 | message(FATAL_ERROR "You are using an old version of CMake from cvs, please update to CMake >= 2.6.0 or cvs at least from Feb 20th, 2008") 28 | endif(NOT COMMAND SET_PROPERTY) 29 | 30 | # CMP0003: add the link paths to the link command as with cmake 2.4 31 | cmake_policy(SET CMP0003 OLD) 32 | endif() 33 | 34 | # Add the automatically determined parts of the RPATH 35 | # which point to directories outside the build tree to the install RPATH 36 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 37 | 38 | include(CheckCXXSourceRuns) 39 | 40 | if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) 41 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 -g") 42 | add_definitions(" -Wall -fPIC -v ") 43 | 44 | # check for x86-64 system 45 | check_cxx_source_runs(" 46 | int main() 47 | { 48 | int a = 0; 49 | int*pa = &a; 50 | asm(\".intel_syntax\\\\n\" 51 | \"mov %%rax, %0\\\\n\" 52 | \"mov %%eax, [%%rax]\\\\n\" 53 | \".att_syntax\\\\n\" 54 | : : \"r\"(pa) : \"%rax\"); 55 | return 0; 56 | }" 57 | IS_X86_64) 58 | 59 | if( IS_X86_64 ) 60 | add_definitions("-D__x86_64__") 61 | endif() 62 | else() 63 | set(IS_X86_64 0) 64 | endif() 65 | 66 | include(CheckIncludeFile) 67 | include(CheckLibraryExists) 68 | include(CheckCXXSourceRuns) 69 | include(CheckCXXCompilerFlag) 70 | 71 | if( UNIX OR CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) 72 | set(STDC_LIBRARY stdc++) 73 | else() 74 | set(STDC_LIBRARY) 75 | endif() 76 | 77 | # check for SSE extensions 78 | if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) 79 | set(SSE_FLAGS) 80 | 81 | set(CMAKE_REQUIRED_FLAGS "-msse2") 82 | check_cxx_source_runs(" 83 | #include 84 | 85 | int main() 86 | { 87 | __m128d a, b; 88 | double vals[2] = {0}; 89 | a = _mm_loadu_pd(vals); 90 | b = _mm_add_pd(a,a); 91 | _mm_storeu_pd(vals,b); 92 | return 0; 93 | }" 94 | HAS_SSE2_EXTENSIONS) 95 | 96 | set(CMAKE_REQUIRED_FLAGS "-msse") 97 | check_cxx_source_runs(" 98 | #include 99 | int main() 100 | { 101 | __m128 a, b; 102 | float vals[4] = {0}; 103 | a = _mm_loadu_ps(vals); 104 | b = a; 105 | b = _mm_add_ps(a,b); 106 | _mm_storeu_ps(vals,b); 107 | return 0; 108 | }" 109 | HAS_SSE_EXTENSIONS) 110 | 111 | set(CMAKE_REQUIRED_FLAGS) 112 | 113 | if(HAS_SSE2_EXTENSIONS) 114 | message(STATUS "Using SSE2 extensions") 115 | set(SSE_FLAGS "-msse2 -mfpmath=sse") 116 | elseif(HAS_SSE_EXTENSIONS) 117 | message(STATUS "Using SSE extensions") 118 | set(SSE_FLAGS "-msse -mfpmath=sse") 119 | endif() 120 | 121 | add_definitions(${SSE_FLAGS}) 122 | elseif(MSVC) 123 | check_cxx_source_runs(" 124 | #include 125 | 126 | int main() 127 | { 128 | __m128d a, b; 129 | double vals[2] = {0}; 130 | a = _mm_loadu_pd(vals); 131 | b = _mm_add_pd(a,a); 132 | _mm_storeu_pd(vals,b); 133 | return 0; 134 | }" 135 | HAS_SSE2_EXTENSIONS) 136 | if( HAS_SSE2_EXTENSIONS ) 137 | message(STATUS "Using SSE2 extensions") 138 | add_definitions( "/arch:SSE2 /fp:fast -D__SSE__ -D__SSE2__" ) 139 | endif() 140 | endif() 141 | 142 | set(Boost_ADDITIONAL_VERSIONS "1.40" "1.39" "1.38" "1.37.0" "1.37" "1.35.0" "1.34.1" "1.34.0" "1.34" "1.33.1" "1.33.0" "1.33") 143 | if( NOT $ENV{BOOST_INCLUDEDIR} STREQUAL "" ) 144 | set(Boost_INCLUDE_DIR $ENV{BOOST_INCLUDEDIR}) 145 | endif() 146 | if( NOT $ENV{BOOST_LIBRARYDIR} STREQUAL "" ) 147 | set(Boost_LIBRARY_DIRS $ENV{BOOST_LIBRARYDIR}) 148 | endif() 149 | 150 | find_package(Boost 151 | COMPONENTS python 152 | ) 153 | 154 | if( Boost_FOUND ) 155 | message(STATUS "found boost version: ${Boost_VERSION}") 156 | else() 157 | message(STATUS "Could not find boost libraries!") 158 | endif() 159 | 160 | 161 | #find_library( 162 | # CPPUNIT_LIBRARY_RELEASE 163 | # NAMES 164 | # PATHS /usr/local/Cellar/cppunit/1.12.1/lib 165 | # /usr/lib 166 | # /usr/lib64 167 | # /usr/local/lib 168 | # /usr/local/lib64 169 | #) 170 | 171 | add_library(libsiftfast SHARED libsiftfast.cpp) 172 | add_library(libsiftfast-static STATIC libsiftfast.cpp) 173 | 174 | 175 | 176 | 177 | if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) 178 | target_link_libraries(libsiftfast m stdc++) 179 | endif() 180 | 181 | target_link_libraries(libsiftfast m stdc++ dl python2.7) 182 | 183 | set_target_properties(libsiftfast PROPERTIES OUTPUT_NAME siftfast CLEAN_DIRECT_OUTPUT 1) 184 | if( MSVC ) 185 | set(LIBSIFTFAST_NAME libsiftfast-s) 186 | else() 187 | set(LIBSIFTFAST_NAME siftfast) 188 | endif() 189 | set_target_properties(libsiftfast-static PROPERTIES OUTPUT_NAME ${LIBSIFTFAST_NAME} CLEAN_DIRECT_OUTPUT 1) 190 | 191 | #if(UNIX AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 192 | # set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "libsiftfast install prefix" FORCE ) 193 | #endif() 194 | 195 | message(STATUS "installing to ${CMAKE_INSTALL_PREFIX}") 196 | 197 | # compile without depending on libsiftfast 198 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 199 | add_executable(siftfast libsiftfast.cpp siftfast.cpp)# profiler.cpp) 200 | #set_target_properties(siftfast PROPERTIES COMPILE_FLAGS "-DDVPROFILE") 201 | target_link_libraries(siftfast libsiftfast m stdc++ dl python2.7) 202 | 203 | # 204 | # generate python bindings via boost-python 205 | # 206 | set(BUILD_SIFTFASTPY) 207 | if( Boost_PYTHON_FOUND ) 208 | find_package(PythonLibs) 209 | 210 | if( PYTHONLIBS_FOUND OR PYTHON_LIBRARIES ) 211 | 212 | find_package(PythonInterp) 213 | if( NOT PYTHON_EXECUTABLE ) 214 | # look specifically for 2.6 215 | FIND_PROGRAM(PYTHON_EXECUTABLE 216 | NAMES python2.7 python 217 | PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath]) 218 | endif() 219 | 220 | if( PYTHON_EXECUTABLE ) 221 | # get the site-packages directory 222 | execute_process( 223 | COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" 224 | OUTPUT_VARIABLE _python_sitepackage 225 | RESULT_VARIABLE _python_failed) 226 | if( ${_python_failed} EQUAL 0 ) 227 | string(REGEX REPLACE "[\r\n]" "" _python_sitepackage "${_python_sitepackage}") 228 | set(PYTHON_INCLUDE_PATH ${PYTHON_INCLUDE_PATH} ${_python_sitepackage}/numpy/core/include) 229 | else() 230 | message(STATUS "failed to get python site-package directory") 231 | endif() 232 | endif() 233 | 234 | add_definitions(${Boost_CFLAGS}) 235 | set(CMAKE_REQUIRED_INCLUDES ${PYTHON_INCLUDE_PATH} ${Boost_INCLUDE_DIR} ) 236 | set(CMAKE_REQUIRED_LIBRARIES ${PYTHON_LIBRARIES} ${Boost_PYTHON_LIBRARY} ${Boost_THREAD_LIBRARY}) 237 | set(CMAKE_REQUIRED_FLAGS ${Boost_CFLAGS}) 238 | 239 | # check if all header files can be included 240 | check_cxx_source_runs(" 241 | #include 242 | #include 243 | #include 244 | #include 245 | #include 246 | #define PY_ARRAY_UNIQUE_SYMBOL PyArrayHandle 247 | #include 248 | #include 249 | #include 250 | int main() 251 | { 252 | return 0; 253 | }" 254 | HAVE_ALL_PYTHON_HEADERS) 255 | 256 | if( HAVE_ALL_PYTHON_HEADERS ) 257 | message(STATUS "python and boost-python found") 258 | include_directories(${PYTHON_INCLUDE_PATH} ${Boost_INCLUDE_DIRS}) 259 | link_directories(${Boost_LIBRARY_DIRS}) 260 | add_library(siftfastpy SHARED siftfastpy.cpp libsiftfast.cpp) 261 | # stdc++ has to be included before opengl libraries due to some ATI bug (http://wiki.fifengine.de/Segfault_in_cxa_allocate_exception#Workaround) 262 | target_link_libraries(siftfastpy ${STDC_LIBRARY} ${PYTHON_LIBRARIES} ${Boost_PYTHON_LIBRARY}) 263 | 264 | set_target_properties(siftfastpy PROPERTIES PREFIX "") 265 | if( WIN32 ) 266 | set_target_properties(siftfastpy PROPERTIES SUFFIX ".pyd") 267 | endif() 268 | set(BUILD_SIFTFASTPY 1) 269 | install(TARGETS siftfastpy DESTINATION lib/python2.7/site-packages PERMISSIONS 270 | OWNER_READ OWNER_WRITE OWNER_EXECUTE 271 | GROUP_READ GROUP_EXECUTE 272 | WORLD_READ WORLD_EXECUTE) 273 | else() 274 | message(STATUS "failed to use boost python libraries, check if python-numpy is installed.") 275 | endif() 276 | else() 277 | message(STATUS "failed to find python-dev please install it") 278 | endif() 279 | else() 280 | message(STATUS "failed to find boost-python, please install it") 281 | endif() 282 | 283 | # check for OpenMP 284 | if( NOT DEFINED USE_OPENMP OR USE_OPENMP ) 285 | 286 | if( WIN32 ) 287 | CHECK_INCLUDE_FILE(omp.h HAVE_OMP_H) 288 | if( HAVE_OMP_H ) 289 | message(STATUS "Using OpenMP") 290 | check_cxx_compiler_flag(/openmp HAVE_OPENMP) 291 | 292 | if( HAVE_OPENMP ) 293 | message(STATUS "compiling with openmp support") 294 | add_definitions("/openmp") 295 | endif() 296 | endif() 297 | 298 | elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) 299 | 300 | # check if compilers supports -fopenmp 301 | INCLUDE(CheckCCompilerFlag) 302 | check_cxx_compiler_flag(-fopenmp HAVE_OPENMP) 303 | check_library_exists(gomp omp_get_num_threads "" HAS_GOMP_LIB) 304 | 305 | if( HAVE_OPENMP AND HAS_GOMP_LIB ) 306 | message(STATUS "compiling with openmp support") 307 | add_definitions("-fopenmp") 308 | target_link_libraries(siftfast gomp) 309 | target_link_libraries(libsiftfast gomp) 310 | target_link_libraries(libsiftfast-static gomp) 311 | if( BUILD_SIFTFASTPY ) 312 | target_link_libraries(siftfastpy gomp) 313 | endif() 314 | set(OPENMP_LFLAGS "-lgomp") 315 | endif() 316 | endif() 317 | endif() 318 | 319 | # 320 | # generate mex files 321 | # 322 | 323 | set(MATLAB MATLAB-NOTFOUND) 324 | if( WIN32 ) 325 | FIND_PROGRAM(MATLAB NAME "mex.bat" PATHS ) 326 | else() 327 | FIND_PROGRAM(MATLAB NAME "mex" PATHS ) 328 | endif() 329 | 330 | set(MEX_LIBS) 331 | if( CMAKE_COMPILER_IS_GNUC OR CMAKE_COMPILER_IS_GNUCXX ) 332 | if( WIN32 ) 333 | set(MEX_CXXFLAGS "${OPENMP_LFLAGS} ") 334 | else() 335 | # check for lapack 336 | check_library_exists(lapack _init "" HAS_LAPACK_LIB) 337 | if( HAS_LAPACK_LIB ) 338 | set(MEX_LIBS "-llapack") 339 | endif() 340 | set(MEX_CXXFLAGS "-Wl,-rpath,${CMAKE_INSTALL_PREFIX}/lib ${OPENMP_LFLAGS}") 341 | endif() 342 | elseif(MSVC) 343 | set(MEX_CXXFLAGS "-L\"${libsiftfast_BINARY_DIR}/Release\" -L\"${libsiftfast_BINARY_DIR}/Debug\"") 344 | else() 345 | set(MEX_CXXFLAGS) 346 | endif() 347 | 348 | if(MATLAB) 349 | # check if the mex file is actually matlab (can be confused with latex) 350 | EXEC_PROGRAM(${MATLAB} ARGS "-version" OUTPUT_VARIABLE MEX_TEST_OUT RETURN_VALUE MEX_TEST_RETURN) 351 | #message(STATUS "mex result: ${MEX_TEST_OUT}") 352 | string(REGEX MATCH "MATLAB" IS_MATLAB "${MEX_TEST_OUT}") 353 | 354 | if( IS_MATLAB ) 355 | set(USE_MATLAB 1) 356 | else() 357 | set(USE_MATLAB) 358 | endif() 359 | endif() 360 | 361 | if(USE_MATLAB) 362 | 363 | if( DARWIN OR APPLE ) 364 | set(MEXEXT "mexmac") 365 | elseif( UNIX ) 366 | if( IS_X86_64 ) 367 | set(MEXEXT "mexa64") 368 | else() 369 | set(MEXEXT "mexglx") 370 | endif() 371 | elseif( WIN64 ) 372 | set(MEXEXT "mexw64") 373 | elseif( WIN32 OR CYGWIN OR WINDOWS ) 374 | set(MEXEXT "mexw32") 375 | else() 376 | set(MEXEXT "mex") 377 | endif() 378 | 379 | set(MATLAB_MEX "siftfast.${MEXEXT}") 380 | 381 | if( MSVC ) 382 | set(MATLAB_MEX_OUT "${CMAKE_CURRENT_BINARY_DIR}/matlab") 383 | else() 384 | set(MATLAB_MEX_OUT ${CMAKE_CURRENT_BINARY_DIR}) 385 | endif() 386 | 387 | add_custom_command( 388 | OUTPUT ${MATLAB_MEX_OUT}/${MATLAB_MEX} 389 | COMMAND mex 390 | ARGS -I\"${CMAKE_SOURCE_DIR}\" -L\"${libsiftfast_BINARY_DIR}\" ${MEX_LIBS} ${MEX_CXXFLAGS} -lsiftfast -outdir \"${MATLAB_MEX_OUT}\" -output \"${MATLAB_MEX}\" \"${CMAKE_CURRENT_SOURCE_DIR}/siftmex.cpp\" 391 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/siftmex.cpp libsiftfast libsiftfast-static 392 | ) 393 | add_custom_target(siftfast_matlab ALL DEPENDS ${MATLAB_MEX_OUT}/${MATLAB_MEX}) 394 | install(FILES ${MATLAB_MEX_OUT}/${MATLAB_MEX} siftfast.m DESTINATION share/siftfast/matlab) 395 | else() 396 | message(STATUS "MATLAB installation not found") 397 | endif(USE_MATLAB) 398 | 399 | 400 | # include(${CMAKE_SOURCE_DIR}/FindOctave.cmake) 401 | # if(OCTAVE_FOUND) 402 | # if( MSVC ) 403 | # # need _mex since mkoctfile generates a siftfast.lib which messes with windows stuff 404 | # set(OCTAVE_MEX ${CMAKE_CURRENT_BINARY_DIR}/octave/siftfast_mex.mex) 405 | # else() 406 | # set(OCTAVE_MEX ${CMAKE_CURRENT_BINARY_DIR}/siftfast.mex) 407 | # endif() 408 | # 409 | # add_custom_command( 410 | # OUTPUT ${OCTAVE_MEX} 411 | # COMMAND ${MKOCTFILE_EXECUTABLE} 412 | # ARGS --mex -I${CMAKE_SOURCE_DIR} -L\"${libsiftfast_BINARY_DIR}\" ${MEX_LIBS} ${MEX_CXXFLAGS} -lsiftfast -o \"${OCTAVE_MEX}\" \"${CMAKE_CURRENT_SOURCE_DIR}/siftmex.cpp\" 413 | # DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/siftmex.cpp libsiftfast libsiftfast-static 414 | # ) 415 | # 416 | # add_custom_target(siftfast_octave ALL DEPENDS ${OCTAVE_MEX}) 417 | # if( MSVC ) 418 | # add_custom_command( 419 | # OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/octave/siftfast.mex 420 | # COMMAND ${CMAKE_COMMAND} -E copy 421 | # ARGS \"${OCTAVE_MEX}\" \"${CMAKE_CURRENT_BINARY_DIR}/octave/siftfast.mex\" 422 | # DEPENDS ${OCTAVE_MEX} 423 | # ) 424 | # add_custom_target(siftfast_octave2 ALL DEPENDS DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/octave/siftfast.mex) 425 | # endif() 426 | # 427 | # install(FILES ${OCTAVE_MEX} siftfast.m DESTINATION share/siftfast/octave) 428 | # 429 | # else(OCTAVE_FOUND) 430 | # message(STATUS "Octave installation not found") 431 | # endif(OCTAVE_FOUND) 432 | 433 | install(FILES siftfast.h DESTINATION include/siftfast) 434 | install(TARGETS siftfast DESTINATION bin) 435 | if( MSVC ) 436 | install(TARGETS libsiftfast RUNTIME DESTINATION bin LIBRARY DESTINATION bin ARCHIVE DESTINATION lib) 437 | else() 438 | install(TARGETS libsiftfast DESTINATION lib PERMISSIONS 439 | OWNER_READ OWNER_WRITE OWNER_EXECUTE 440 | GROUP_READ GROUP_EXECUTE 441 | WORLD_READ WORLD_EXECUTE) 442 | endif() 443 | 444 | file(GLOB jpg_files ${CMAKE_CURRENT_SOURCE_DIR}/examples/*.jpg) 445 | install(FILES ${jpg_files} DESTINATION share/siftfast/examples) 446 | install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/examples/testsiftfast.py DESTINATION share/siftfast/examples) 447 | 448 | # add make uninstall capability 449 | CONFIGURE_FILE( 450 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" 451 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 452 | IMMEDIATE @ONLY) 453 | 454 | ADD_CUSTOM_TARGET(uninstall 455 | "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") 456 | -------------------------------------------------------------------------------- /FindBoost.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Boost include dirs and libraries 2 | # Usage of this module as follows: 3 | # 4 | # SET(Boost_USE_STATIC_LIBS ON) 5 | # SET(Boost_USE_MULTITHREAD OFF) 6 | # FIND_PACKAGE( Boost 1.34.1 COMPONENTS date_time filesystem iostreams ... ) 7 | # 8 | # The Boost_ADDITIONAL_VERSIONS variable can be used to specify a list of 9 | # boost version numbers that should be taken into account when searching 10 | # for the libraries. Unfortunately boost puts the version number into the 11 | # actual filename for the libraries, so this might be needed in the future 12 | # when new Boost versions are released. 13 | # 14 | # Currently this module searches for the following version numbers: 15 | # 1.33, 1.33.0, 1.33.1, 1.34, 1.34.0, 1.34.1, 1.35, 1.35.0, 1.35.1, 1.36, 16 | # 1.36.0, 1.36.1 17 | # 18 | # The components list needs to be the actual names of boost libraries, that is 19 | # the part of the actual library files that differ on different libraries. So 20 | # its "date_time" for "libboost_date_time...". Anything else will result in 21 | # errors 22 | # 23 | # You can provide a minimum version number that should be used. If you provide this 24 | # version number and specify the REQUIRED attribute, this module will fail if it 25 | # can't find the specified or a later version. If you specify a version number this is 26 | # automatically put into the considered list of version numbers and thus doesn't need 27 | # to be specified in the Boost_ADDITIONAL_VERSIONS variable 28 | # 29 | # Variables used by this module, they can change the default behaviour and need to be set 30 | # before calling find_package: 31 | # Boost_USE_MULTITHREAD Can be set to OFF to use the non-multithreaded 32 | # boost libraries. Defaults to ON. 33 | # Boost_USE_STATIC_LIBS Can be set to ON to force the use of the static 34 | # boost libraries. Defaults to OFF. 35 | # Boost_ADDITIONAL_VERSIONS A list of version numbers to use for searching 36 | # the boost include directory. The default list 37 | # of version numbers is: 38 | # 1.33, 1.33.0, 1.33.1, 1.34, 1.34.0, 1.34.1, 39 | # 1.35, 1.35.0, 1.35.1, 1.36, 1.36.0, 1.36.1 40 | # If you want to look for an older or newer 41 | # version set this variable to a list of 42 | # strings, where each string contains a number, i.e. 43 | # SET(Boost_ADDITIONAL_VERSIONS "0.99.0" "1.35.0") 44 | # BOOST_ROOT or BOOSTROOT Preferred installation prefix for searching for Boost, 45 | # set this if the module has problems finding the proper Boost installation 46 | # BOOST_INCLUDEDIR Set this to the include directory of Boost, if the 47 | # module has problems finding the proper Boost installation 48 | # BOOST_LIBRARYDIR Set this to the lib directory of Boost, if the 49 | # module has problems finding the proper Boost installation 50 | # 51 | # The last three variables are available also as environment variables 52 | # 53 | # 54 | # Variables defined by this module: 55 | # 56 | # Boost_FOUND System has Boost, this means the include dir was found, 57 | # as well as all the libraries specified in the COMPONENTS list 58 | # Boost_INCLUDE_DIRS Boost include directories, not cached 59 | # Boost_INCLUDE_DIR This is almost the same as above, but this one is cached and may be 60 | # modified by advanced users 61 | # Boost_LIBRARIES Link these to use the Boost libraries that you specified, not cached 62 | # Boost_LIBRARY_DIRS The path to where the Boost library files are. 63 | # Boost_VERSION The version number of the boost libraries that have been found, 64 | # same as in version.hpp from Boost 65 | # Boost_LIB_VERSION The version number in filename form as its appended to the library filenames 66 | # Boost_MAJOR_VERSION major version number of boost 67 | # Boost_MINOR_VERSION minor version number of boost 68 | # Boost_SUBMINOR_VERSION subminor version number of boost 69 | # Boost_LIB_DIAGNOSTIC_DEFINITIONS Only set on windows. Can be used with add_definitions 70 | # to print diagnostic information about the automatic 71 | # linking done on windows. 72 | 73 | # For each component you list the following variables are set. 74 | # ATTENTION: The component names need to be in lower case, just as the boost 75 | # library names however the cmake variables use upper case for the component 76 | # part. So you'd get Boost_SERIALIZATION_FOUND for example. 77 | # 78 | # Boost_${COMPONENT}_FOUND True IF the Boost library "component" was found. 79 | # Boost_${COMPONENT}_LIBRARY The absolute path of the Boost library "component". 80 | # Boost_${COMPONENT}_LIBRARY_DEBUG The absolute path of the debug version of the 81 | # Boost library "component". 82 | # Boost_${COMPONENT}_LIBRARY_RELEASE The absolute path of the release version of the 83 | # Boost library "component" 84 | # 85 | # Copyright (c) 2006-2008 Andreas Schneider 86 | # Copyright (c) 2007 Wengo 87 | # Copyright (c) 2007 Mike Jackson 88 | # Copyright (c) 2008 Andreas Pakulat 89 | # 90 | # Redistribution AND use is allowed according to the terms of the New 91 | # BSD license. 92 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 93 | # 94 | OPTION(Boost_USE_MULTITHREADED 95 | "Use the multithreaded versions of the Boost libraries" ON) 96 | 97 | if (Boost_FIND_VERSION_EXACT) 98 | if (Boost_FIND_VERSION_PATCH) 99 | set( _boost_TEST_VERSIONS 100 | "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}.${Boost_FIND_VERSION_PATCH}") 101 | else (Boost_FIND_VERSION_PATCH) 102 | set( _boost_TEST_VERSIONS 103 | "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}.0" 104 | "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") 105 | endif (Boost_FIND_VERSION_PATCH) 106 | else (Boost_FIND_VERSION_EXACT) 107 | set( _boost_TEST_VERSIONS ${Boost_ADDITIONAL_VERSIONS} 108 | "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0" 109 | "1.34" "1.33.1" "1.33.0" "1.33" ) 110 | endif (Boost_FIND_VERSION_EXACT) 111 | 112 | # The reason that we failed to find Boost. This will be set to a 113 | # user-friendly message when we fail to find some necessary piece of 114 | # Boost. 115 | set(Boost_ERROR_REASON) 116 | 117 | ############################################ 118 | # 119 | # Check the existence of the libraries. 120 | # 121 | ############################################ 122 | # This macro was taken directly from the FindQt4.cmake file that is included 123 | # with the CMake distribution. This is NOT my work. All work was done by the 124 | # original authors of the FindQt4.cmake file. Only minor modifications were 125 | # made to remove references to Qt and make this file more generally applicable 126 | ######################################################################### 127 | 128 | MACRO (_Boost_ADJUST_LIB_VARS basename) 129 | IF (Boost_INCLUDE_DIR ) 130 | IF (Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) 131 | # if the generator supports configuration types then set 132 | # optimized and debug libraries, or if the CMAKE_BUILD_TYPE has a value 133 | IF (CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) 134 | SET(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) 135 | ELSE(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) 136 | # if there are no configuration types and CMAKE_BUILD_TYPE has no value 137 | # then just use the release libraries 138 | SET(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) 139 | ENDIF(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) 140 | SET(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) 141 | ENDIF (Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) 142 | 143 | # if only the release version was found, set the debug variable also to the release version 144 | IF (Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) 145 | SET(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE}) 146 | SET(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE}) 147 | SET(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE}) 148 | ENDIF (Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) 149 | 150 | # if only the debug version was found, set the release variable also to the debug version 151 | IF (Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) 152 | SET(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG}) 153 | SET(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG}) 154 | SET(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG}) 155 | ENDIF (Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) 156 | 157 | IF (Boost_${basename}_LIBRARY) 158 | SET(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY} CACHE FILEPATH "The Boost ${basename} library") 159 | GET_FILENAME_COMPONENT(Boost_LIBRARY_DIRS "${Boost_${basename}_LIBRARY}" PATH) 160 | SET(Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIRS} CACHE FILEPATH "Boost library directory") 161 | SET(Boost_${basename}_FOUND ON CACHE INTERNAL "Whether the Boost ${basename} library found") 162 | ENDIF (Boost_${basename}_LIBRARY) 163 | 164 | ENDIF (Boost_INCLUDE_DIR ) 165 | # Make variables changeble to the advanced user 166 | MARK_AS_ADVANCED( 167 | Boost_${basename}_LIBRARY 168 | Boost_${basename}_LIBRARY_RELEASE 169 | Boost_${basename}_LIBRARY_DEBUG 170 | ) 171 | ENDMACRO (_Boost_ADJUST_LIB_VARS) 172 | 173 | #------------------------------------------------------------------------------- 174 | 175 | 176 | SET( _boost_IN_CACHE TRUE) 177 | IF(Boost_INCLUDE_DIR) 178 | FOREACH(COMPONENT ${Boost_FIND_COMPONENTS}) 179 | STRING(TOUPPER ${COMPONENT} COMPONENT) 180 | IF(NOT Boost_${COMPONENT}_FOUND) 181 | SET( _boost_IN_CACHE FALSE) 182 | ENDIF(NOT Boost_${COMPONENT}_FOUND) 183 | ENDFOREACH(COMPONENT) 184 | ELSE(Boost_INCLUDE_DIR) 185 | SET( _boost_IN_CACHE FALSE) 186 | ENDIF(Boost_INCLUDE_DIR) 187 | 188 | IF (_boost_IN_CACHE) 189 | # in cache already 190 | SET(Boost_FOUND TRUE) 191 | FOREACH(COMPONENT ${Boost_FIND_COMPONENTS}) 192 | STRING(TOUPPER ${COMPONENT} COMPONENT) 193 | _Boost_ADJUST_LIB_VARS( ${COMPONENT} ) 194 | SET(Boost_LIBRARIES ${Boost_LIBRARIES} ${Boost_${COMPONENT}_LIBRARY}) 195 | ENDFOREACH(COMPONENT) 196 | SET(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR}) 197 | IF(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") 198 | MATH(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") 199 | MATH(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") 200 | MATH(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") 201 | ENDIF(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") 202 | ELSE (_boost_IN_CACHE) 203 | # Need to search for boost 204 | 205 | IF(WIN32) 206 | # In windows, automatic linking is performed, so you do not have 207 | # to specify the libraries. If you are linking to a dynamic 208 | # runtime, then you can choose to link to either a static or a 209 | # dynamic Boost library, the default is to do a static link. You 210 | # can alter this for a specific library "whatever" by defining 211 | # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be 212 | # linked dynamically. Alternatively you can force all Boost 213 | # libraries to dynamic link by defining BOOST_ALL_DYN_LINK. 214 | 215 | # This feature can be disabled for Boost library "whatever" by 216 | # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining 217 | # BOOST_ALL_NO_LIB. 218 | 219 | # If you want to observe which libraries are being linked against 220 | # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking 221 | # code to emit a #pragma message each time a library is selected 222 | # for linking. 223 | SET(Boost_LIB_DIAGNOSTIC_DEFINITIONS 224 | "-DBOOST_LIB_DIAGNOSTIC" CACHE STRING "Boost diagnostic define") 225 | ENDIF(WIN32) 226 | 227 | SET(_boost_INCLUDE_SEARCH_DIRS 228 | C:/boost/include 229 | "C:/boost" 230 | "$ENV{ProgramFiles}/boost/boost_${Boost_FIND_VERSION_MAJOR}_${Boost_FIND_VERSION_MINOR}_${Boost_FIND_VERSION_PATCH}" 231 | "$ENV{ProgramFiles}/Boost" 232 | /sw/local/include 233 | ) 234 | 235 | SET(_boost_LIBRARIES_SEARCH_DIRS 236 | C:/boost/lib 237 | "C:/boost" 238 | "$ENV{ProgramFiles}/boost/boost_${Boost_FIND_VERSION_MAJOR}_${Boost_FIND_VERSION_MINOR}_${Boost_FIND_VERSION_PATCH}/lib" 239 | "$ENV{ProgramFiles}/Boost" 240 | /sw/local/lib 241 | ) 242 | 243 | # If BOOST_ROOT was defined in the environment, use it. 244 | if (NOT BOOST_ROOT AND NOT $ENV{BOOST_ROOT} STREQUAL "") 245 | set(BOOST_ROOT $ENV{BOOST_ROOT}) 246 | endif(NOT BOOST_ROOT AND NOT $ENV{BOOST_ROOT} STREQUAL "") 247 | 248 | # If BOOSTROOT was defined in the environment, use it. 249 | if (NOT BOOST_ROOT AND NOT $ENV{BOOSTROOT} STREQUAL "") 250 | set(BOOST_ROOT $ENV{BOOSTROOT}) 251 | endif(NOT BOOST_ROOT AND NOT $ENV{BOOSTROOT} STREQUAL "") 252 | 253 | # If BOOST_INCLUDEDIR was defined in the environment, use it. 254 | IF( NOT $ENV{BOOST_INCLUDEDIR} STREQUAL "" ) 255 | set(BOOST_INCLUDEDIR $ENV{BOOST_INCLUDEDIR}) 256 | ENDIF( NOT $ENV{BOOST_INCLUDEDIR} STREQUAL "" ) 257 | 258 | # If BOOST_LIBRARYDIR was defined in the environment, use it. 259 | IF( NOT $ENV{BOOST_LIBRARYDIR} STREQUAL "" ) 260 | set(BOOST_LIBRARYDIR $ENV{BOOST_LIBRARYDIR}) 261 | ENDIF( NOT $ENV{BOOST_LIBRARYDIR} STREQUAL "" ) 262 | 263 | IF( BOOST_ROOT ) 264 | file(TO_CMAKE_PATH ${BOOST_ROOT} BOOST_ROOT) 265 | SET(_boost_INCLUDE_SEARCH_DIRS 266 | ${BOOST_ROOT}/include 267 | ${BOOST_ROOT} 268 | ${_boost_INCLUDE_SEARCH_DIRS}) 269 | SET(_boost_LIBRARIES_SEARCH_DIRS 270 | ${BOOST_ROOT}/lib 271 | ${BOOST_ROOT}/stage/lib 272 | ${_boost_LIBRARIES_SEARCH_DIRS}) 273 | ENDIF( BOOST_ROOT ) 274 | 275 | IF( BOOST_INCLUDEDIR ) 276 | file(TO_CMAKE_PATH ${BOOST_INCLUDEDIR} BOOST_INCLUDEDIR) 277 | SET(_boost_INCLUDE_SEARCH_DIRS 278 | ${BOOST_INCLUDEDIR} ${_boost_INCLUDE_SEARCH_DIRS}) 279 | ENDIF( BOOST_INCLUDEDIR ) 280 | 281 | IF( BOOST_LIBRARYDIR ) 282 | file(TO_CMAKE_PATH ${BOOST_LIBRARYDIR} BOOST_LIBRARYDIR) 283 | SET(_boost_LIBRARIES_SEARCH_DIRS 284 | ${BOOST_LIBRARYDIR} ${_boost_LIBRARIES_SEARCH_DIRS}) 285 | ENDIF( BOOST_LIBRARYDIR ) 286 | 287 | # Try to find Boost by stepping backwards through the Boost versions 288 | # we know about. 289 | IF( NOT Boost_INCLUDE_DIR ) 290 | # Build a list of path suffixes for each version. 291 | SET(_boost_PATH_SUFFIXES) 292 | FOREACH(_boost_VER ${_boost_TEST_VERSIONS}) 293 | # Add in a path suffix, based on the required version, ideally 294 | # we could read this from version.hpp, but for that to work we'd 295 | # need to know the include dir already 296 | if (WIN32 AND NOT CYGWIN) 297 | set(_boost_PATH_SUFFIX boost_${_boost_VER}) 298 | else (WIN32 AND NOT CYGWIN) 299 | set(_boost_PATH_SUFFIX boost-${_boost_VER}) 300 | endif (WIN32 AND NOT CYGWIN) 301 | 302 | IF(_boost_PATH_SUFFIX MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") 303 | STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1_\\2_\\3" 304 | _boost_PATH_SUFFIX ${_boost_PATH_SUFFIX}) 305 | ELSEIF(_boost_PATH_SUFFIX MATCHES "[0-9]+\\.[0-9]+") 306 | STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\1_\\2" 307 | _boost_PATH_SUFFIX ${_boost_PATH_SUFFIX}) 308 | ENDIF(_boost_PATH_SUFFIX MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") 309 | LIST(APPEND _boost_PATH_SUFFIXES "${_boost_PATH_SUFFIX}") 310 | ENDFOREACH(_boost_VER) 311 | 312 | # Look for a standard boost header file. 313 | FIND_PATH(Boost_INCLUDE_DIR 314 | NAMES boost/config.hpp 315 | HINTS ${_boost_INCLUDE_SEARCH_DIRS} 316 | PATH_SUFFIXES ${_boost_PATH_SUFFIXES} 317 | ) 318 | ENDIF( NOT Boost_INCLUDE_DIR ) 319 | 320 | IF(Boost_INCLUDE_DIR) 321 | # Extract Boost_VERSION and Boost_LIB_VERSION from version.hpp 322 | # Read the whole file: 323 | # 324 | SET(BOOST_VERSION 0) 325 | SET(BOOST_LIB_VERSION "") 326 | FILE(READ "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS) 327 | 328 | STRING(REGEX REPLACE ".*#define BOOST_VERSION ([0-9]+).*" "\\1" Boost_VERSION "${_boost_VERSION_HPP_CONTENTS}") 329 | STRING(REGEX REPLACE ".*#define BOOST_LIB_VERSION \"([0-9_]+)\".*" "\\1" Boost_LIB_VERSION "${_boost_VERSION_HPP_CONTENTS}") 330 | 331 | SET(Boost_LIB_VERSION ${Boost_LIB_VERSION} CACHE INTERNAL "The library version string for boost libraries") 332 | SET(Boost_VERSION ${Boost_VERSION} CACHE INTERNAL "The version number for boost libraries") 333 | 334 | IF(NOT "${Boost_VERSION}" STREQUAL "0") 335 | MATH(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") 336 | MATH(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") 337 | MATH(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") 338 | 339 | set(Boost_ERROR_REASON 340 | "${Boost_ERROR_REASON}Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}\nBoost include path: ${Boost_INCLUDE_DIR}") 341 | ENDIF(NOT "${Boost_VERSION}" STREQUAL "0") 342 | ELSE(Boost_INCLUDE_DIR) 343 | set(Boost_ERROR_REASON 344 | "${Boost_ERROR_REASON}Unable to find the Boost header files. Please set BOOST_ROOT to the root directory containing Boost or BOOST_INCLUDEDIR to the directory containing Boost's headers.") 345 | ENDIF(Boost_INCLUDE_DIR) 346 | 347 | # Setting some more suffixes for the library 348 | SET (Boost_LIB_PREFIX "") 349 | IF ( WIN32 AND Boost_USE_STATIC_LIBS ) 350 | SET (Boost_LIB_PREFIX "lib") 351 | ENDIF ( WIN32 AND Boost_USE_STATIC_LIBS ) 352 | SET (_boost_COMPILER "-gcc") 353 | IF (MSVC90) 354 | SET (_boost_COMPILER "-vc90") 355 | ELSEIF (MSVC80) 356 | SET (_boost_COMPILER "-vc80") 357 | ELSEIF (MSVC71) 358 | SET (_boost_COMPILER "-vc71") 359 | ENDIF(MSVC90) 360 | IF (MINGW) 361 | EXEC_PROGRAM(${CMAKE_CXX_COMPILER} 362 | ARGS -dumpversion 363 | OUTPUT_VARIABLE _boost_COMPILER_VERSION 364 | ) 365 | STRING(REGEX REPLACE "([0-9])\\.([0-9])\\.[0-9]" "\\1\\2" 366 | _boost_COMPILER_VERSION ${_boost_COMPILER_VERSION}) 367 | SET (_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}") 368 | ENDIF(MINGW) 369 | IF (UNIX) 370 | IF (NOT CMAKE_COMPILER_IS_GNUCC) 371 | # We assume that we have the Intel compiler. 372 | SET (_boost_COMPILER "-il") 373 | ELSE (NOT CMAKE_COMPILER_IS_GNUCC) 374 | # Determine which version of GCC we have. 375 | EXEC_PROGRAM(${CMAKE_CXX_COMPILER} 376 | ARGS -dumpversion 377 | OUTPUT_VARIABLE _boost_COMPILER_VERSION 378 | ) 379 | STRING(REGEX REPLACE "([0-9])\\.([0-9])\\.[0-9]" "\\1\\2" 380 | _boost_COMPILER_VERSION ${_boost_COMPILER_VERSION}) 381 | IF(APPLE) 382 | IF(Boost_MINOR_VERSION) 383 | IF(${Boost_MINOR_VERSION} GREATER 35) 384 | # In Boost 1.36.0 and newer, the mangled compiler name used 385 | # on Mac OS X/Darwin is "xgcc". 386 | SET(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}") 387 | ELSE(${Boost_MINOR_VERSION} GREATER 35) 388 | # In Boost <= 1.35.0, there is no mangled compiler name for 389 | # the Mac OS X/Darwin version of GCC. 390 | SET(_boost_COMPILER "") 391 | ENDIF(${Boost_MINOR_VERSION} GREATER 35) 392 | ELSE(Boost_MINOR_VERSION) 393 | # We don't know the Boost version, so assume it's 394 | # pre-1.36.0. 395 | SET(_boost_COMPILER "") 396 | ENDIF(Boost_MINOR_VERSION) 397 | ELSE() 398 | SET (_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}") 399 | ENDIF() 400 | ENDIF (NOT CMAKE_COMPILER_IS_GNUCC) 401 | ENDIF(UNIX) 402 | 403 | SET (_boost_MULTITHREADED "-mt") 404 | 405 | IF( NOT Boost_USE_MULTITHREADED ) 406 | SET (_boost_MULTITHREADED "") 407 | ENDIF( NOT Boost_USE_MULTITHREADED ) 408 | 409 | SET( _boost_STATIC_TAG "") 410 | IF (WIN32) 411 | IF(MSVC) 412 | SET (_boost_ABI_TAG "g") 413 | ENDIF(MSVC) 414 | IF( Boost_USE_STATIC_LIBS ) 415 | SET( _boost_STATIC_TAG "-s") 416 | ENDIF( Boost_USE_STATIC_LIBS ) 417 | ENDIF(WIN32) 418 | SET (_boost_ABI_TAG "${_boost_ABI_TAG}d") 419 | 420 | # ------------------------------------------------------------------------ 421 | # Begin finding boost libraries 422 | # ------------------------------------------------------------------------ 423 | FOREACH(COMPONENT ${Boost_FIND_COMPONENTS}) 424 | STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT) 425 | SET( Boost_${UPPERCOMPONENT}_LIBRARY "Boost_${UPPERCOMPONENT}_LIBRARY-NOTFOUND" ) 426 | SET( Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE-NOTFOUND" ) 427 | SET( Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG-NOTFOUND") 428 | 429 | # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES 430 | IF( Boost_USE_STATIC_LIBS ) 431 | SET( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) 432 | IF(WIN32) 433 | SET(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) 434 | ELSE(WIN32) 435 | SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) 436 | ENDIF(WIN32) 437 | ENDIF( Boost_USE_STATIC_LIBS ) 438 | 439 | FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE 440 | NAMES ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}-${Boost_LIB_VERSION} 441 | ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_STATIC_TAG}-${Boost_LIB_VERSION} 442 | ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED} 443 | ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_STATIC_TAG} 444 | ${Boost_LIB_PREFIX}boost_${COMPONENT} 445 | HINTS ${_boost_LIBRARIES_SEARCH_DIRS} 446 | PATHS ${_boost_LIBRARIES_SEARCH_DIRS} 447 | ) 448 | 449 | FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG 450 | NAMES ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}-${_boost_ABI_TAG}-${Boost_LIB_VERSION} 451 | ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_STATIC_TAG}${_boost_ABI_TAG}-${Boost_LIB_VERSION} 452 | ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}-${_boost_ABI_TAG} 453 | ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_STATIC_TAG}${_boost_ABI_TAG} 454 | ${Boost_LIB_PREFIX}boost_${COMPONENT}-${_boost_ABI_TAG} 455 | HINTS ${_boost_LIBRARIES_SEARCH_DIRS} 456 | ) 457 | 458 | _Boost_ADJUST_LIB_VARS(${UPPERCOMPONENT}) 459 | IF( Boost_USE_STATIC_LIBS ) 460 | SET(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) 461 | ENDIF( Boost_USE_STATIC_LIBS ) 462 | ENDFOREACH(COMPONENT) 463 | # ------------------------------------------------------------------------ 464 | # End finding boost libraries 465 | # ------------------------------------------------------------------------ 466 | 467 | SET(Boost_INCLUDE_DIRS 468 | ${Boost_INCLUDE_DIR} 469 | ) 470 | 471 | SET(Boost_FOUND FALSE) 472 | IF(Boost_INCLUDE_DIR) 473 | SET( Boost_FOUND TRUE ) 474 | 475 | # Check the version of Boost against the requested version. 476 | if (Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) 477 | message(SEND_ERROR "When requesting a specific version of Boost, you must provide at least the major and minor version numbers, e.g., 1.34") 478 | endif (Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) 479 | if(Boost_MAJOR_VERSION LESS "${Boost_FIND_VERSION_MAJOR}" ) 480 | set( Boost_FOUND FALSE ) 481 | set(_Boost_VERSION_AGE "old") 482 | elseif(Boost_MAJOR_VERSION EQUAL "${Boost_FIND_VERSION_MAJOR}" ) 483 | if(Boost_MINOR_VERSION LESS "${Boost_FIND_VERSION_MINOR}" ) 484 | set( Boost_FOUND FALSE ) 485 | set(_Boost_VERSION_AGE "old") 486 | elseif(Boost_MINOR_VERSION EQUAL "${Boost_FIND_VERSION_MINOR}" ) 487 | if( Boost_FIND_VERSION_PATCH AND Boost_SUBMINOR_VERSION LESS "${Boost_FIND_VERSION_PATCH}" ) 488 | set( Boost_FOUND FALSE ) 489 | set(_Boost_VERSION_AGE "old") 490 | endif( Boost_FIND_VERSION_PATCH AND Boost_SUBMINOR_VERSION LESS "${Boost_FIND_VERSION_PATCH}" ) 491 | endif( Boost_MINOR_VERSION LESS "${Boost_FIND_VERSION_MINOR}" ) 492 | endif( Boost_MAJOR_VERSION LESS "${Boost_FIND_VERSION_MAJOR}" ) 493 | 494 | if (Boost_FOUND AND Boost_FIND_VERSION_EXACT) 495 | # If the user requested an exact version of Boost, check 496 | # that. We already know that the Boost version we have is >= the 497 | # requested version. 498 | set(_Boost_VERSION_AGE "new") 499 | 500 | # If the user didn't specify a patchlevel, it's 0. 501 | if (NOT Boost_FIND_VERSION_PATCH) 502 | set(Boost_FIND_VERSION_PATCH 0) 503 | endif (NOT Boost_FIND_VERSION_PATCH) 504 | 505 | # We'll set Boost_FOUND true again if we have an exact version match. 506 | set(Boost_FOUND FALSE) 507 | if(Boost_MAJOR_VERSION EQUAL "${Boost_FIND_VERSION_MAJOR}" ) 508 | if(Boost_MINOR_VERSION EQUAL "${Boost_FIND_VERSION_MINOR}" ) 509 | if(Boost_SUBMINOR_VERSION EQUAL "${Boost_FIND_VERSION_PATCH}" ) 510 | set( Boost_FOUND TRUE ) 511 | endif(Boost_SUBMINOR_VERSION EQUAL "${Boost_FIND_VERSION_PATCH}" ) 512 | endif( Boost_MINOR_VERSION EQUAL "${Boost_FIND_VERSION_MINOR}" ) 513 | endif( Boost_MAJOR_VERSION EQUAL "${Boost_FIND_VERSION_MAJOR}" ) 514 | endif (Boost_FOUND AND Boost_FIND_VERSION_EXACT) 515 | 516 | if(NOT Boost_FOUND) 517 | # State that we found a version of Boost that is too new or too old. 518 | set(Boost_ERROR_REASON 519 | "${Boost_ERROR_REASON}\nDetected version of Boost is too ${_Boost_VERSION_AGE}. Requested version was ${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") 520 | if (Boost_FIND_VERSION_PATCH) 521 | set(Boost_ERROR_REASON 522 | "${Boost_ERROR_REASON}.${Boost_FIND_VERSION_PATCH}") 523 | endif (Boost_FIND_VERSION_PATCH) 524 | if (NOT Boost_FIND_VERSION_EXACT) 525 | set(Boost_ERROR_REASON "${Boost_ERROR_REASON} (or newer)") 526 | endif (NOT Boost_FIND_VERSION_EXACT) 527 | set(Boost_ERROR_REASON "${Boost_ERROR_REASON}.") 528 | endif (NOT Boost_FOUND) 529 | 530 | if (Boost_FOUND) 531 | set(_boost_CHECKED_COMPONENT FALSE) 532 | set(_Boost_MISSING_COMPONENTS) 533 | foreach(COMPONENT ${Boost_FIND_COMPONENTS}) 534 | string(TOUPPER ${COMPONENT} COMPONENT) 535 | set(_boost_CHECKED_COMPONENT TRUE) 536 | if(NOT Boost_${COMPONENT}_FOUND) 537 | string(TOLOWER ${COMPONENT} COMPONENT) 538 | list(APPEND _Boost_MISSING_COMPONENTS ${COMPONENT}) 539 | set( Boost_FOUND FALSE) 540 | endif(NOT Boost_${COMPONENT}_FOUND) 541 | endforeach(COMPONENT) 542 | endif (Boost_FOUND) 543 | 544 | if (_Boost_MISSING_COMPONENTS) 545 | # We were unable to find some libraries, so generate a sensible 546 | # error message that lists the libraries we were unable to find. 547 | set(Boost_ERROR_REASON 548 | "${Boost_ERROR_REASON}\nThe following Boost libraries could not be found:\n") 549 | foreach(COMPONENT ${_Boost_MISSING_COMPONENTS}) 550 | set(Boost_ERROR_REASON 551 | "${Boost_ERROR_REASON} boost_${COMPONENT}\n") 552 | endforeach(COMPONENT) 553 | 554 | list(LENGTH Boost_FIND_COMPONENTS Boost_NUM_COMPONENTS_WANTED) 555 | list(LENGTH _Boost_MISSING_COMPONENTS Boost_NUM_MISSING_COMPONENTS) 556 | if (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) 557 | set(Boost_ERROR_REASON 558 | "${Boost_ERROR_REASON}No Boost libraries were found. You may need to set Boost_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") 559 | else (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) 560 | set(Boost_ERROR_REASON 561 | "${Boost_ERROR_REASON}Some (but not all) of the required Boost libraries were found. You may need to install these additional Boost libraries. Alternatively, set Boost_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") 562 | endif (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) 563 | endif (_Boost_MISSING_COMPONENTS) 564 | 565 | IF( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) 566 | # Compatibility Code for backwards compatibility with CMake 567 | # 2.4's FindBoost module. 568 | 569 | # Look for the boost library path. 570 | # Note that the user may not have installed any libraries 571 | # so it is quite possible the Boost_LIBRARY_PATH may not exist. 572 | SET(_boost_LIB_DIR ${Boost_INCLUDE_DIR}) 573 | 574 | IF("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") 575 | GET_FILENAME_COMPONENT(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) 576 | ENDIF ("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") 577 | 578 | IF("${_boost_LIB_DIR}" MATCHES "/include$") 579 | # Strip off the trailing "/include" in the path. 580 | GET_FILENAME_COMPONENT(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) 581 | ENDIF("${_boost_LIB_DIR}" MATCHES "/include$") 582 | 583 | IF(EXISTS "${_boost_LIB_DIR}/lib") 584 | SET (_boost_LIB_DIR ${_boost_LIB_DIR}/lib) 585 | ELSE(EXISTS "${_boost_LIB_DIR}/lib") 586 | IF(EXISTS "${_boost_LIB_DIR}/stage/lib") 587 | SET(_boost_LIB_DIR ${_boost_LIB_DIR}/stage/lib) 588 | ELSE(EXISTS "${_boost_LIB_DIR}/stage/lib") 589 | SET(_boost_LIB_DIR "") 590 | ENDIF(EXISTS "${_boost_LIB_DIR}/stage/lib") 591 | ENDIF(EXISTS "${_boost_LIB_DIR}/lib") 592 | 593 | IF(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") 594 | SET(Boost_LIBRARY_DIRS ${_boost_LIB_DIR} CACHE FILEPATH "Boost library directory") 595 | ENDIF(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") 596 | 597 | ENDIF( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) 598 | 599 | ELSE(Boost_INCLUDE_DIR) 600 | SET( Boost_FOUND FALSE) 601 | ENDIF(Boost_INCLUDE_DIR) 602 | 603 | IF (Boost_FOUND) 604 | IF (NOT Boost_FIND_QUIETLY) 605 | MESSAGE(STATUS "Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") 606 | ENDIF(NOT Boost_FIND_QUIETLY) 607 | IF (NOT Boost_FIND_QUIETLY) 608 | MESSAGE(STATUS "Found the following Boost libraries:") 609 | ENDIF(NOT Boost_FIND_QUIETLY) 610 | FOREACH ( COMPONENT ${Boost_FIND_COMPONENTS} ) 611 | STRING( TOUPPER ${COMPONENT} UPPERCOMPONENT ) 612 | IF ( Boost_${UPPERCOMPONENT}_FOUND ) 613 | IF (NOT Boost_FIND_QUIETLY) 614 | MESSAGE (STATUS " ${COMPONENT}") 615 | ENDIF(NOT Boost_FIND_QUIETLY) 616 | SET(Boost_LIBRARIES ${Boost_LIBRARIES} ${Boost_${UPPERCOMPONENT}_LIBRARY}) 617 | ENDIF ( Boost_${UPPERCOMPONENT}_FOUND ) 618 | ENDFOREACH(COMPONENT) 619 | ELSE (Boost_FOUND) 620 | IF (Boost_FIND_REQUIRED) 621 | message(SEND_ERROR "Unable to find the requested Boost libraries.\n${Boost_ERROR_REASON}") 622 | ENDIF(Boost_FIND_REQUIRED) 623 | ENDIF(Boost_FOUND) 624 | 625 | # Under Windows, automatic linking is performed, so no need to specify the libraries. 626 | IF (WIN32) 627 | IF (NOT MINGW) 628 | SET(Boost_LIBRARIES "") 629 | ENDIF (NOT MINGW) 630 | ENDIF(WIN32) 631 | 632 | # show the Boost_INCLUDE_DIRS AND Boost_LIBRARIES variables only in the advanced view 633 | MARK_AS_ADVANCED(Boost_INCLUDE_DIR 634 | Boost_INCLUDE_DIRS 635 | Boost_LIBRARY_DIRS 636 | Boost_USE_MULTITHREADED 637 | ) 638 | ENDIF(_boost_IN_CACHE) 639 | 640 | -------------------------------------------------------------------------------- /FindOctave.cmake: -------------------------------------------------------------------------------- 1 | # Try to find the build flags to compile octave shared objects (oct and mex files) 2 | # Once done this will define 3 | # 4 | # OCTAVE_FOUND - if Coin3d is found 5 | # OCTAVE_CXXFLAGS - extra flags 6 | # OCTAVE_INCLUDE_DIRS - include directories 7 | # OCTAVE_LINK_DIRS - link directories 8 | # OCTAVE_LIBRARY_RELEASE - the relase version 9 | # OCTAVE_LIBRARY_DEBUG - the debug version 10 | # OCTAVE_LIBRARY - a default library, with priority debug. 11 | 12 | # use mkoctfile 13 | set(MKOCTFILE_EXECUTABLE MKOCTFILE_EXECUTABLE-NOTFOUND) 14 | find_program(MKOCTFILE_EXECUTABLE NAME mkoctfile PATHS) 15 | mark_as_advanced(MKOCTFILE_EXECUTABLE) 16 | 17 | if(MKOCTFILE_EXECUTABLE) 18 | set(OCTAVE_FOUND 1) 19 | 20 | execute_process( 21 | COMMAND ${MKOCTFILE_EXECUTABLE} -p ALL_CXXFLAGS 22 | OUTPUT_VARIABLE _mkoctfile_cppflags 23 | RESULT_VARIABLE _mkoctfile_failed) 24 | string(REGEX REPLACE "[\r\n]" " " _mkoctfile_cppflags "${_mkoctfile_cppflags}") 25 | execute_process( 26 | COMMAND ${MKOCTFILE_EXECUTABLE} -p INCFLAGS 27 | OUTPUT_VARIABLE _mkoctfile_includedir 28 | RESULT_VARIABLE _mkoctfile_failed) 29 | string(REGEX REPLACE "[\r\n]" " " _mkoctfile_includedir "${_mkoctfile_includedir}") 30 | execute_process( 31 | COMMAND ${MKOCTFILE_EXECUTABLE} -p ALL_LDFLAGS 32 | OUTPUT_VARIABLE _mkoctfile_ldflags 33 | RESULT_VARIABLE _mkoctfile_failed) 34 | string(REGEX REPLACE "[\r\n]" " " _mkoctfile_ldflags "${_mkoctfile_ldflags}") 35 | execute_process( 36 | COMMAND ${MKOCTFILE_EXECUTABLE} -p LFLAGS 37 | OUTPUT_VARIABLE _mkoctfile_lflags 38 | RESULT_VARIABLE _mkoctfile_failed) 39 | string(REGEX REPLACE "[\r\n]" " " _mkoctfile_lflags "${_mkoctfile_lflags}") 40 | execute_process( 41 | COMMAND ${MKOCTFILE_EXECUTABLE} -p LIBS 42 | OUTPUT_VARIABLE _mkoctfile_libs 43 | RESULT_VARIABLE _mkoctfile_failed) 44 | string(REGEX REPLACE "[\r\n]" " " _mkoctfile_libs "${_mkoctfile_libs}") 45 | execute_process( 46 | COMMAND ${MKOCTFILE_EXECUTABLE} -p OCTAVE_LIBS 47 | OUTPUT_VARIABLE _mkoctfile_octlibs 48 | RESULT_VARIABLE _mkoctfile_failed) 49 | string(REGEX REPLACE "[\r\n]" " " _mkoctfile_octlibs "${_mkoctfile_octlibs}") 50 | set(_mkoctfile_libs "${_mkoctfile_libs} ${_mkoctfile_octlibs}") 51 | 52 | string(REGEX MATCHALL "(^| )-l([./+-_\\a-zA-Z]*)" _mkoctfile_libs "${_mkoctfile_libs}") 53 | string(REGEX REPLACE "(^| )-l" "" _mkoctfile_libs "${_mkoctfile_libs}") 54 | 55 | string(REGEX MATCHALL "(^| )-L([./+-_\\a-zA-Z]*)" _mkoctfile_ldirs "${_mkoctfile_lflags}") 56 | string(REGEX REPLACE "(^| )-L" "" _mkoctfile_ldirs "${_mkoctfile_ldirs}") 57 | 58 | string(REGEX REPLACE "(^| )-l([./+-_\\a-zA-Z]*)" " " _mkoctfile_ldflags "${_mkoctfile_ldflags}") 59 | string(REGEX REPLACE "(^| )-L([./+-_\\a-zA-Z]*)" " " _mkoctfile_ldflags "${_mkoctfile_ldflags}") 60 | 61 | string(REGEX REPLACE "(^| )-I" " " _mkoctfile_includedir "${_mkoctfile_includedir}") 62 | 63 | separate_arguments(_mkoctfile_includedir) 64 | 65 | set( OCTAVE_CXXFLAGS "${_mkoctfile_cppflags}" ) 66 | set( OCTAVE_LINK_FLAGS "${_mkoctfile_ldflags}" ) 67 | set( OCTAVE_INCLUDE_DIRS ${_mkoctfile_includedir}) 68 | set( OCTAVE_LINK_DIRS ${_mkoctfile_ldirs}) 69 | set( OCTAVE_LIBRARY ${_mkoctfile_libs}) 70 | set( OCTAVE_LIBRARY_RELEASE ${OCTAVE_LIBRARY}) 71 | set( OCTAVE_LIBRARY_DEBUG ${OCTAVE_LIBRARY}) 72 | endif(MKOCTFILE_EXECUTABLE) 73 | 74 | MARK_AS_ADVANCED( 75 | OCTAVE_LIBRARY_FOUND 76 | OCTAVE_CXXFLAGS 77 | OCTAVE_LINK_FLAGS 78 | OCTAVE_INCLUDE_DIRS 79 | OCTAVE_LINK_DIRS 80 | OCTAVE_LIBRARY 81 | OCTAVE_LIBRARY_RELEASE 82 | OCTAVE_LIBRARY_DEBUG 83 | ) 84 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # libsiftfast: author zerofrog(@gmail.com) 2 | 3 | The compilation system uses a cross-platform tool called cmake. 4 | 5 | It must be installed on either Windows or Linux. 6 | 7 | ## Linux/Mac OSX Instructions: 8 | 9 | Change into the root directory. 10 | 11 | Then have cmake generate the Makefile. 12 | 13 | $ cmake . 14 | 15 | Then run the generated Makefile. 16 | 17 | $ make 18 | 19 | This will set the project to be installed in /usr/local. To change the install 20 | directory type 21 | 22 | $ make prefix=/my/new/dir 23 | 24 | To change other environment variables that cmake uses after initially making, 25 | type "cmake build" 26 | 27 | ## Windows Instructions: 28 | 29 | Download [cmake](http://www.cmake.org/), make sure to install it in the PATH. 30 | Then run runcmake.bat, that should generate visual studio files in the build 31 | folder. Open libsiftfast.sln and compile. 32 | 33 | OpenMP: 34 | 35 | cmake will use OpenMP if it exists in your system. Note that OpenMP is 36 | available only on gcc versions >= 4.2. CMake checks this automatically, but you 37 | can force usage or disabling of it by adding "-DUSE_OPENMP=OFF" when manually 38 | running cmake. Use ON to force enabling. 39 | 40 | Sometimes siftfast might fail to compile with OpenMP because libgomp.so is not 41 | setup properly to be used by shared objects. Checkout this tutorial here on how 42 | to compile the correct 43 | [libgomp](http://openrave.programmingvision.com/index.php?title=Misc:MatlabOpenMP) 44 | 45 | Basically the problem is that the default libgomp might be compiled with 46 | nodlopen flag refusing it to be dynamically loaded. The only way around this is 47 | to compile your own libgomp library and make sure libsiftfast is linking to it. 48 | 49 | Matlab: 50 | 51 | Read this if you are interested in using siftfast.m for matlab on Linux. When 52 | compiling a matlab mex file, you might get a message saying the gcc version is 53 | too high. If so, matlab will have a hard time locating the correct libstdc++.so 54 | file. In this case, go into /usr/local/share/sys/os/glnx86 and make 55 | libgcc_s and libstdc++ point to the /usr/lib versions 56 | 57 | sudo mv libgcc_s.so.1 libgcc_s.so.1.back 58 | sudo ln -s /lib/libgcc_s.so.1 libgcc_s.so.1 59 | sudo rm libstdc++.so.6 (this was already a symbolic link) 60 | sudo ln -s /usr/lib/libstdc++.so.6.0.9 libstdc++.so.6 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | 3 | Version 3, 29 June 2007 4 | 5 | Copyright (C) 2007 Free Software Foundation, Inc. 6 | 7 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 8 | 9 | This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 10 | 0. Additional Definitions. 11 | 12 | As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License. 13 | 14 | “The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. 15 | 16 | An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. 17 | 18 | A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”. 19 | 20 | The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. 21 | 22 | The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 23 | 1. Exception to Section 3 of the GNU GPL. 24 | 25 | You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 26 | 2. Conveying Modified Versions. 27 | 28 | If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: 29 | 30 | * a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or 31 | * b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 32 | 33 | 3. Object Code Incorporating Material from Library Header Files. 34 | 35 | The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: 36 | 37 | * a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. 38 | * b) Accompany the object code with a copy of the GNU GPL and this license document. 39 | 40 | 4. Combined Works. 41 | 42 | You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: 43 | 44 | * a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. 45 | * b) Accompany the Combined Work with a copy of the GNU GPL and this license document. 46 | * c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. 47 | * d) Do one of the following: 48 | o 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 49 | o 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. 50 | * e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 51 | 52 | 5. Combined Libraries. 53 | 54 | You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: 55 | 56 | * a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. 57 | * b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 58 | 59 | 6. Revised Versions of the GNU Lesser General Public License. 60 | 61 | The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. 62 | 63 | Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. 64 | 65 | If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. 66 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | libsiftfast: author zerofrog(@gmail.com) 2 | ---------------------------------------- 3 | Various utilities to compute the SIFT features of a greyscale image. Packages offered: 4 | 5 | *libsiftfast.so - main library that contains the sift code 6 | 7 | *siftfast - really fast SIFT implementation using SSE and OpenMP (also fixes some bugs from lowe's code, so outputs are similar, but not exact). The usage is very similar to David Lowe's sift program. To input a greyscale image test.pgm and get the SIFT keys test.key use 8 | 9 | > siftfast < test.pgm > test.key 10 | 11 | The format of test.key is pretty self explanatory: 12 | 13 | #keys #key_dimension 14 | (for #keys) [x y scale orientation (for #key_dimension)[value] ] 15 | 16 | 17 | *siftfast.m - matlab/octave mex file that uses sift_fast, just do [frames,descr]=sift_mex(grayscale_image); 18 | frames is a 4xN matrix of [X,Y,scale,orientation], 19 | descr is a 128xN matrix of normalized descriptors 20 | To use the mex files, libsift_fast.so, Octave/Matlab need to be able to load it. A way to do it is to add its path to your LD_LIBRARY_PATH in your ~/.bashrc file, or in matlab with: 21 | setenv('LD_LIBRARY_PATH',[getenv('LD_LIBRARY_PATH') ':' libsift_directory]); 22 | 23 | 24 | SIFT is based on 25 | David G. Lowe, "Distinctive image features from scale-invariant keypoints, 26 | "International Journal of Computer Vision, 60, 2 (2004), pp. 91-110. 27 | 28 | Using the Octave/Matlab mex files 29 | --------------------------------- 30 | 31 | the octave and matlab mex files are installed in $prefix/share/siftfast/octave and $prefix/share/siftfast/matlab where $prefix is the installation directory you've provided (via CMAKE_INSTALL_PREFIX). The default value for $prefix is /usr/local 32 | 33 | Add the path via addpath('$prefix/share/siftfast/matlab'), and then in octave/matlab type: 34 | 35 | > help siftfast 36 | 37 | this should give a help file on how to use it. 38 | 39 | Comparisons with other SIFT Code 40 | -------------------------------- 41 | 42 | The default setting of siftfast produce the same output as Lowe's free sift program. On a quad-core Core2Duo machine with OpenMP, siftfast goes about 6x faster than lowe's sift program for 640x480 images. 43 | -------------------------------------------------------------------------------- /cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 2 | MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 3 | ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | 5 | FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 6 | STRING(REGEX REPLACE "\n" ";" files "${files}") 7 | FOREACH(file ${files}) 8 | MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 9 | IF(EXISTS "$ENV{DESTDIR}${file}") 10 | EXEC_PROGRAM( 11 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 12 | OUTPUT_VARIABLE rm_out 13 | RETURN_VALUE rm_retval 14 | ) 15 | IF(NOT "${rm_retval}" STREQUAL 0) 16 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 17 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 18 | ELSE(EXISTS "$ENV{DESTDIR}${file}") 19 | MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 20 | ENDIF(EXISTS "$ENV{DESTDIR}${file}") 21 | ENDFOREACH(file) 22 | -------------------------------------------------------------------------------- /examples/test0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish2000/libsiftfast/bbce4712d81361a328addfabe695296928a90920/examples/test0.jpg -------------------------------------------------------------------------------- /examples/test1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish2000/libsiftfast/bbce4712d81361a328addfabe695296928a90920/examples/test1.jpg -------------------------------------------------------------------------------- /examples/test2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish2000/libsiftfast/bbce4712d81361a328addfabe695296928a90920/examples/test2.jpg -------------------------------------------------------------------------------- /examples/testsiftfast.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # exact C++ implementation of lowe's sift program 3 | # Copyright (C) zerofrog(@gmail.com), 2008-2009 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # Lesser GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this program. If not, see . 17 | from numpy import * 18 | import time, Image 19 | from optparse import OptionParser 20 | 21 | import siftfastpy 22 | 23 | if __name__=='__main__': 24 | parser = OptionParser(description='Compute SIFT features of an image.') 25 | parser.add_option('--image', 26 | action="store",type='string',dest='image',default='test0.jpg', 27 | help='Image to test') 28 | (options, args) = parser.parse_args() 29 | im = Image.open(options.image) 30 | im = im.convert(mode='L') # convert to greyscale 31 | siftimage = siftfastpy.Image(im.size[0], im.size[1]) 32 | siftimage.setData(reshape(im.getdata(), im.size[::-1])) 33 | 34 | starttime = time.time() 35 | frames, desc = siftfastpy.GetKeypoints(siftimage) 36 | 37 | print '%d keypoints found in %fs' % ( 38 | frames.shape[0], time.time()-starttime) 39 | 40 | # print '%d %d'%(desc.shape[0],desc.shape[1]) 41 | # for i in xrange(frames.shape[0]): 42 | # print '%d %d %f %f'%(frames[i,1],frames[i,0],frames[i,3],frames[i,2]) 43 | # s = '' 44 | # for j,d in enumerate(desc[i]): 45 | # s += str(min(255,int(d*512.0))) + ' ' 46 | # if mod(j,16) == 15: 47 | # s += '\n' 48 | # print s 49 | -------------------------------------------------------------------------------- /install_manifest.txt: -------------------------------------------------------------------------------- 1 | /usr/local/lib/python2.7/site-packages/siftfastpy.dylib 2 | /usr/local/include/siftfast/siftfast.h 3 | /usr/local/bin/siftfast 4 | /usr/local/lib/libsiftfast.dylib 5 | /usr/local/share/siftfast/examples/test0.jpg 6 | /usr/local/share/siftfast/examples/test1.jpg 7 | /usr/local/share/siftfast/examples/test2.jpg 8 | /usr/local/share/siftfast/examples/testsiftfast.py 9 | -------------------------------------------------------------------------------- /libsiftfast.cpp: -------------------------------------------------------------------------------- 1 | // exact C++ implementation of lowe's sift program 2 | // Copyright (C) zerofrog(@gmail.com), 2008-2009 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //Lesser GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU Lesser General Public License 15 | //along with this program. If not, see . 16 | 17 | // This source code was carefully calibrated to match David Lowe's SIFT features program 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include // ftime(), struct timeb 32 | 33 | #ifndef _MSC_VER 34 | #include 35 | #else 36 | #define WIN32_LEAN_AND_MEAN 37 | #include 38 | #endif 39 | 40 | #if defined(__SSE3__) 41 | #include 42 | #elif defined(__SSE2__) 43 | #include 44 | #elif defined(__SSE__) 45 | #include 46 | #else 47 | /*#ifndef _MSC_VER 48 | #warning "Not compiling with SSE extenions" 49 | #endif*/ 50 | #endif 51 | 52 | #ifdef _OPENMP 53 | #include 54 | #else 55 | /*#ifndef _MSC_VER 56 | #warning "OpenMP not enabled. Use -fopenmp (>=gcc-4.2) or -openmp (icc) for speed enhancements on SMP machines." 57 | #endif*/ 58 | #endif 59 | 60 | using namespace std; 61 | 62 | #define PI 3.141592654f 63 | #define SQRT2 1.4142136f 64 | 65 | // if defined, will profile the critical functions and write results to prof.txt 66 | //#define DVPROFILE 67 | 68 | // if defined will align all image rows to 16 bytes 69 | // usually aligning is faster (can save ~100ms), however for 1024x768 70 | // cache misses with the enlarged rows make it ~400-500ms slower 71 | //#define ALIGNED_IMAGE_ROWS 72 | 73 | #ifdef ALIGNED_IMAGE_ROWS 74 | #define _MM_LOAD_ALIGNED _mm_load_ps 75 | #define _MM_STORE_ALIGNED _mm_store_ps 76 | #else 77 | #define _MM_LOAD_ALIGNED _mm_loadu_ps 78 | #define _MM_STORE_ALIGNED _mm_storeu_ps 79 | #endif 80 | 81 | #ifdef DVPROFILE 82 | #include "profiler.h" 83 | #else 84 | #define DVSTARTPROFILE() 85 | #endif 86 | 87 | typedef struct ImageSt { 88 | int rows, cols; // Dimensions of image. 89 | float *pixels; // 2D array of image pixels. 90 | int stride; // how many floats until the next row 91 | // (used to add padding to make rows aligned to 16 bytes) 92 | } *Image; 93 | 94 | 95 | // Data structure for a keypoint. Lists of keypoints are linked by the "next" field. 96 | typedef struct KeypointSt { 97 | float row, col; // Subpixel location of keypoint. 98 | float scale, ori; // Scale and orientation (range [-PI,PI]) 99 | float descrip[128]; // Vector of descriptor values 100 | struct KeypointSt *next; // Pointer to next keypoint in list. 101 | } *Keypoint; 102 | 103 | 104 | int DoubleImSize = 1; 105 | int Scales = 3; 106 | float InitSigma = 1.6f; 107 | float PeakThresh; 108 | 109 | static list s_listKeypoints; 110 | 111 | typedef unsigned short u16; 112 | typedef unsigned int u32; 113 | typedef unsigned long long u64; 114 | 115 | #if defined(__SSE__) && !defined(SIMDMATH_H) 116 | 117 | #ifdef _MSC_VER 118 | typedef __m128 vec_int4; 119 | typedef __m128 vec_float4; 120 | #else 121 | // need an implementation of atan2 in SSE 122 | typedef int vec_int4 __attribute__ ((vector_size (16))); 123 | typedef float vec_float4 __attribute__ ((vector_size (16))); 124 | #endif 125 | 126 | inline vec_float4 atanf4( vec_float4 x ); 127 | inline vec_float4 atan2f4( vec_float4 y, vec_float4 x ); 128 | 129 | #endif 130 | 131 | inline u64 GetMicroTime() 132 | { 133 | #ifdef _WIN32 134 | LARGE_INTEGER count, freq; 135 | QueryPerformanceCounter(&count); 136 | QueryPerformanceFrequency(&freq); 137 | return (count.QuadPart * 1000000) / freq.QuadPart; 138 | #else 139 | struct timeval t; 140 | gettimeofday(&t, NULL); 141 | return (u64)t.tv_sec*1000000+t.tv_usec; 142 | #endif 143 | } 144 | 145 | // aligned malloc and free 146 | inline void* sift_aligned_malloc(size_t size, size_t align) { 147 | assert(align < 0x10000); 148 | char* p = (char*)malloc(size+align); 149 | int off = 2+align - ((int)(size_t)(p+2) % align); 150 | 151 | p += off; 152 | *(u16*)(p-2) = off; 153 | 154 | return p; 155 | } 156 | 157 | void sift_aligned_free(void* pmem) { 158 | if (pmem != NULL) { 159 | char* p = (char*)pmem; 160 | free(p - (int)*(u16*)(p-2)); 161 | } 162 | } 163 | 164 | #if defined(_MSC_VER) 165 | #define SIFT_ALIGNED16(x) __declspec(align(16)) x 166 | #else 167 | #define SIFT_ALIGNED16(x) x __attribute((aligned(16))) 168 | #endif 169 | 170 | extern "C" { 171 | Image CreateImage(int rows, int cols); 172 | Image CreateImageFromMatlabData(double* pdata, int rows, int cols); 173 | void DestroyAllImages(); 174 | Keypoint GetKeypoints(Image porgimage); 175 | Image SiftDoubleSize(Image p); 176 | Image SiftCopyImage(Image p); 177 | Image HalfImageSize(Image curimage); 178 | Keypoint OctaveKeypoints(Image pimage, Image* phalfimage, float fscale, Keypoint prevkeypts); 179 | void SubtractImage(Image imgdst, Image img0, Image img1); 180 | void GaussianBlur(Image imgdst, Image image, float fblur); 181 | void ConvHorizontal(Image imgdst, Image image, float* kernel, int ksize); 182 | void ConvHorizontalFast(Image imgdst, Image image, float* kernel, int ksize); 183 | void ConvVertical(Image image, float* kernel, int ksize); 184 | void ConvVerticalFast(Image image, float* kernel, int ksize); 185 | void ConvBuffer(float* buf, float* kernel, int cols, int ksize); 186 | Keypoint FindMaxMin(Image* imdiff, Image* imgaus, float fscale, Keypoint prevkeypts); 187 | void GradOriImages(Image imgaus, Image imgrad, Image imorient); 188 | 189 | #if !defined(_MSC_VER) && defined(__SSE__) 190 | void GradOriImagesFast(Image imgaus, Image imgrad, Image imorient); 191 | #endif 192 | 193 | int LocalMaxMin(float fval, Image imdiff, int row, int col); 194 | int NotOnEdge(Image imdiff, int row, int col); 195 | Keypoint InterpKeyPoint(Image* imdiff, int index, int rowstart, int colstart, 196 | Image imgrad, Image imorient, char* pMaxMinArray, float fscale,Keypoint keypts, int steps); 197 | float FitQuadratic(float* X, Image* imdiff, int index, int rowstart, int colstart); 198 | void SolveLinearSystem(float* Y, float* H, int dim); 199 | Keypoint AssignOriHist(Image imgrad, Image imorient, float fscale, float fSize, 200 | float frowstart, float fcolstart, Keypoint keypts); 201 | float InterpPeak(float f0, float f1, float f2); 202 | void SmoothHistogram(float* phist, int numbins); 203 | Keypoint MakeKeypoint(Image imgrad, Image imorient, float fscale, float fSize, 204 | float frowstart,float fcolstart,float forient, Keypoint keypts); 205 | void MakeKeypointSample(Keypoint pnewkeypt, Image imgrad, Image imorient, 206 | float fSize, float frowstart, float fcolstart); 207 | void NormalizeVec(float* pf, int num); 208 | void KeySample(float* fdesc, Keypoint pnewkeypt, Image imgrad, Image imorient, 209 | float fSize, float frowstart, float fcolstart); 210 | void AddSample(float* fdesc, Keypoint pkeypt, Image imgrad, Image imorient, int r, int c, 211 | float rpos, float cpos, float rx, float cx); 212 | void PlaceInIndex(float* fdesc, float fgrad, float forient, float fnewrow, float fnewcol); 213 | void FreeKeypoints(Keypoint keypt); 214 | void DestroyAllResources(); 215 | } 216 | 217 | static list s_listImages; 218 | Image CreateImage(int rows, int cols) { 219 | Image im; 220 | 221 | im = (Image) sift_aligned_malloc(sizeof(struct ImageSt),16); 222 | im->rows = rows; 223 | im->cols = cols; 224 | 225 | // cannot make 16 byte aligned since 1024x768 images 226 | #if defined(ALIGNED_IMAGE_ROWS) && defined(__SSE__) 227 | im->stride = (cols+3)&~3; 228 | #else 229 | im->stride = cols; 230 | #endif 231 | 232 | im->pixels = (float*)sift_aligned_malloc(rows*im->stride*sizeof(float)+16,128); // add padding (for sse) 233 | s_listImages.push_back(im); 234 | return im; 235 | } 236 | 237 | void DestroyAllImages() { 238 | for (list::iterator it = s_listImages.begin(); it != s_listImages.end(); ++it) { 239 | sift_aligned_free((*it)->pixels); 240 | sift_aligned_free(*it); 241 | } 242 | s_listImages.clear(); 243 | } 244 | 245 | Image CreateImageFromMatlabData(double* pdata, int rows, int cols) { 246 | Image image = CreateImage(rows,cols); 247 | float* pixels = image->pixels; 248 | int stride = image->stride; 249 | 250 | #ifdef __SSE2__ 251 | for (int i = 0; i < (rows&~1); i += 2, pixels+=2*stride) { 252 | for (int j = 0; j < (cols&~3); j += 4) { 253 | double* pf = &pdata[i+j*rows]; 254 | 255 | #ifdef ALIGNED_IMAGE_ROWS 256 | __m128d m0 = _mm_load_pd(pf); 257 | __m128d m1 = _mm_load_pd(pf+rows); 258 | __m128d m2 = _mm_load_pd(pf+2*rows); 259 | __m128d m3 = _mm_load_pd(pf+3*rows); 260 | #else 261 | __m128d m0 = _mm_loadu_pd(pf); 262 | __m128d m1 = _mm_loadu_pd(pf+rows); 263 | __m128d m2 = _mm_loadu_pd(pf+2*rows); 264 | __m128d m3 = _mm_loadu_pd(pf+3*rows); 265 | #endif 266 | 267 | __m128 mrows0 = _mm_shuffle_ps(_mm_cvtpd_ps(m0),_mm_cvtpd_ps(m1),0x44); 268 | __m128 mrows1 = _mm_shuffle_ps(_mm_cvtpd_ps(m2),_mm_cvtpd_ps(m3),0x44); 269 | 270 | _mm_storeu_ps(pixels+j,_mm_shuffle_ps(mrows0,mrows1,0x88)); 271 | _mm_storeu_ps(pixels+j+stride,_mm_shuffle_ps(mrows0,mrows1,0xdd)); 272 | } 273 | 274 | for (int j = (cols&~3); j < cols; j++) { 275 | pixels[j] = pdata[i+j*rows]; 276 | pixels[j+stride] = pdata[i+j*rows+1]; 277 | } 278 | } 279 | 280 | if (rows & 1) { 281 | for (int j = 0; j < cols; ++j) 282 | pixels[j] = (float)pdata[rows-1+j*rows]; 283 | } 284 | #else 285 | for (int i = 0; i < rows; ++i, pixels+=stride) { 286 | for (int j = 0; j < cols; ++j) 287 | pixels[j] = (float)pdata[i+j*rows]; 288 | } 289 | #endif 290 | 291 | return image; 292 | } 293 | 294 | static Image* s_imgaus = NULL, *s_imdiff = NULL; 295 | static Image s_imgrad = NULL, s_imorient = NULL; 296 | static char* s_MaxMinArray = NULL; 297 | 298 | Keypoint GetKeypoints(Image porgimage) { 299 | #ifdef DVPROFILE 300 | DVProfClear(); 301 | #endif 302 | 303 | Image pimage = NULL; 304 | float fscale = 1.0f; 305 | Image halfimage = NULL; 306 | Keypoint keypts = 0; 307 | 308 | { 309 | DVSTARTPROFILE(); 310 | 311 | PeakThresh = 0.04f/(float)Scales; 312 | s_imgaus = new Image[((27 + 4*Scales)&0xfffffff0)/4]; 313 | s_imdiff = new Image[((23 + 4*Scales)&0xfffffff0)/4]; 314 | 315 | if (DoubleImSize) { 316 | pimage = SiftDoubleSize(porgimage); 317 | fscale = 0.5f; 318 | } else { 319 | pimage = SiftCopyImage(porgimage); 320 | } 321 | 322 | float fnewscale = 1.0f; 323 | if (!DoubleImSize) 324 | fnewscale = 0.5f; 325 | 326 | if (InitSigma > fnewscale) { 327 | GaussianBlur(pimage, pimage, 328 | sqrtf(InitSigma*InitSigma - fnewscale*fnewscale)); 329 | } 330 | // { 331 | // FILE* f = fopen("test.txt","w"); 332 | // int rows = pimage->rows, cols = pimage->cols, stride = pimage->stride; 333 | // float *_pdst = pimage->pixels; 334 | // for(int j = 0; j < rows; ++j, _pdst += stride ) { 335 | // for(int k = 0; k < cols; ++k) { 336 | // fprintf(f,"%f ",_pdst[k]); 337 | // } 338 | // fprintf(f,"\n"); 339 | // } 340 | // fclose(f); 341 | // } 342 | // } 343 | 344 | // create the images 345 | s_imgaus[0] = pimage; 346 | for (int i = 1; i < Scales+3; ++i) 347 | s_imgaus[i] = CreateImage(pimage->rows,pimage->cols); 348 | for (int i = 0; i < Scales+2; ++i) 349 | s_imdiff[i] = CreateImage(pimage->rows,pimage->cols); 350 | s_imgrad = CreateImage(pimage->rows,pimage->cols); 351 | s_imorient = CreateImage(pimage->rows,pimage->cols); 352 | s_MaxMinArray = (char*)sift_aligned_malloc(pimage->rows*pimage->cols,16); 353 | 354 | while (pimage->rows > 12 && pimage->cols > 12) { 355 | keypts = OctaveKeypoints(pimage, &halfimage, fscale, keypts); 356 | pimage = HalfImageSize(halfimage); 357 | fscale += fscale; 358 | } 359 | 360 | delete[] s_imgaus; 361 | delete[] s_imdiff; 362 | sift_aligned_free(s_MaxMinArray); 363 | 364 | } 365 | 366 | #ifdef DVPROFILE 367 | DVProfWrite("prof.txt"); 368 | #endif 369 | 370 | return keypts; 371 | } 372 | 373 | Image SiftDoubleSize(Image im) { 374 | int rows = im->rows, cols = im->cols; 375 | int newrows = 2*rows-2, newcols = 2*cols-2; 376 | Image newim = CreateImage(newrows, newcols); 377 | float* psrc = im->pixels, *pdst = newim->pixels; 378 | int stride = im->stride, newstride = newim->stride; 379 | for (int i = 0; i < rows-1; ++i, psrc += stride, pdst += 2*newstride) { 380 | for (int j = 0; j < cols-1; ++j) { 381 | pdst[2*j] = psrc[j]; 382 | pdst[newstride+2*j] = 0.5f*(psrc[j] + psrc[stride+j]); 383 | pdst[2*j+1] = 0.5f*(psrc[j] + psrc[j+1]); 384 | pdst[newstride+2*j+1] = 0.25f*(psrc[j] + psrc[j+1] + psrc[stride+j] + psrc[stride+j+1]); 385 | } 386 | } 387 | return newim; 388 | } 389 | 390 | Image SiftCopyImage(Image im) { 391 | DVSTARTPROFILE(); 392 | Image newim = CreateImage(im->rows,im->cols); 393 | memcpy(newim->pixels, im->pixels, sizeof(float)*im->rows*im->stride); 394 | return newim; 395 | } 396 | 397 | Image HalfImageSize(Image curimage) { 398 | int cols = curimage->cols; 399 | int newrows = (curimage->rows+(curimage->rows<0))>>1; 400 | int newcols = (cols+(curimage->cols<0))>>1; 401 | 402 | Image halfimage = CreateImage(newrows, newcols); 403 | float* psrc = curimage->pixels, *pdst = halfimage->pixels; 404 | int stride = curimage->stride, newstride = halfimage->stride; 405 | 406 | for (int halfrow = 0; halfrow < newrows; ++halfrow, pdst += newstride, psrc += 2*stride) { 407 | for (int halfcol = 0; halfcol < newcols; ++halfcol) { 408 | pdst[halfcol] = psrc[halfcol*2]; 409 | } 410 | } 411 | return halfimage; 412 | } 413 | 414 | Keypoint OctaveKeypoints(Image pimage, Image* phalfimage, float fscale, Keypoint prevkeypts) { 415 | DVSTARTPROFILE(); 416 | 417 | float fwidth = powf(2.0f,1.0f / (float)Scales); 418 | float fincsigma = sqrtf(fwidth * fwidth - 1.0f); 419 | int rows = pimage->rows, cols = pimage->cols, stride = pimage->stride; 420 | s_imgaus[0] = pimage; 421 | float sigma = InitSigma; 422 | 423 | for (int i = 1; i < Scales+3; ++i) { 424 | 425 | s_imgaus[i]->rows = rows; s_imgaus[i]->cols = cols; s_imgaus[i]->stride = stride; 426 | GaussianBlur(s_imgaus[i], s_imgaus[i-1], fincsigma * sigma); 427 | 428 | s_imdiff[i-1]->rows = rows; s_imdiff[i-1]->cols = cols; s_imdiff[i-1]->stride = stride; 429 | SubtractImage(s_imdiff[i-1],s_imgaus[i-1],s_imgaus[i]); 430 | 431 | sigma *= fwidth; 432 | } 433 | 434 | s_imgrad->rows = rows; s_imgrad->cols = cols; s_imgrad->stride = stride; 435 | s_imorient->rows = rows; s_imorient->cols = cols; s_imorient->stride = stride; 436 | 437 | *phalfimage = s_imgaus[Scales]; 438 | return FindMaxMin(s_imdiff, s_imgaus, fscale, prevkeypts); 439 | } 440 | 441 | // imgdst = img0 - img1 442 | void SubtractImage(Image imgdst, Image img0, Image img1) { 443 | int rows = imgdst->rows, cols = imgdst->cols, stride = imgdst->stride; 444 | float* _pixels0 = img0->pixels, *_pixels1 = img1->pixels, *_pdst = imgdst->pixels; 445 | #ifdef __SSE__ 446 | #pragma omp parallel for schedule(dynamic,32) 447 | for (int j = 0; j < rows; ++j) { 448 | float* pixels0 = _pixels0+j*stride; 449 | float* pixels1 = _pixels1+j*stride; 450 | float* pdst = _pdst + j*stride; 451 | 452 | for (int k = 0; k < (cols&~7); k += 8) { 453 | _MM_STORE_ALIGNED(pdst+k,_mm_sub_ps(_MM_LOAD_ALIGNED(pixels0+k), _MM_LOAD_ALIGNED(pixels1+k))); 454 | _MM_STORE_ALIGNED(pdst+k+4,_mm_sub_ps(_MM_LOAD_ALIGNED(pixels0+k+4), _MM_LOAD_ALIGNED(pixels1+k+4))); 455 | } 456 | 457 | for (int k = (cols&~7); k < cols; ++k) 458 | pdst[k] = pixels0[k]-pixels1[k]; 459 | } 460 | #else 461 | for (int j = 0; j < rows; ++j, _pixels0 += stride, _pixels1 += stride, _pdst += stride) { 462 | for (int k = 0; k < cols; ++k) { 463 | _pdst[k] = _pixels0[k]-_pixels1[k]; 464 | } 465 | } 466 | #endif 467 | } 468 | 469 | static map s_mapkernel; // assumes GaussTruncate doesn't change!, if freeing second, subtract 4 bytes 470 | 471 | void GaussianBlur(Image imgdst, Image image, float fblur) { 472 | DVSTARTPROFILE(); 473 | const float GaussTruncate = 4.0f; 474 | 475 | int ksize = (int)(2.0f * GaussTruncate * fblur + 1.0f); 476 | if( ksize < 3 ) 477 | ksize = 3; 478 | ksize += !(ksize&1); // make it odd 479 | 480 | float* kernel = NULL; 481 | for (map::iterator it = s_mapkernel.begin(); it != s_mapkernel.end(); ++it) { 482 | if (fabsf(fblur-it->first) < 0.001f) { 483 | kernel = it->second; 484 | break; 485 | } 486 | } 487 | 488 | if (kernel == NULL) { 489 | // have to create a new one 490 | double faccum = 0; 491 | 492 | // +4 for alignment and padding issues with sse 493 | kernel = (float*)sift_aligned_malloc((ksize+9)*sizeof(float),16)+1; 494 | 495 | int width = (ksize >= 0 ? ksize : ksize-1)>>1; 496 | for (int i = 0; i <= ksize; ++i) { 497 | float fweight = expf( - (float)(i-width)*(i-width) / (2.0f*fblur*fblur) ); 498 | faccum += (double)fweight; 499 | kernel[i] = fweight; 500 | } 501 | 502 | // shouldn't it be <=? 503 | for (int i = 0; i < ksize; ++i) 504 | kernel[i] /= (float)faccum; 505 | memset(kernel+ksize,0,sizeof(float)*8); 506 | s_mapkernel[fblur] = kernel; 507 | } 508 | 509 | #ifdef __SSE__ 510 | if( image->cols < 12 ) 511 | ConvHorizontal(imgdst, image,kernel,ksize); 512 | else 513 | ConvHorizontalFast(imgdst, image,kernel,ksize); 514 | 515 | ConvVerticalFast(imgdst,kernel,ksize); 516 | #else 517 | ConvHorizontal(imgdst, image,kernel,ksize); 518 | ConvVertical(imgdst,kernel,ksize); 519 | #endif 520 | } 521 | 522 | void ConvHorizontal(Image imgdst, Image image, float* kernel, int ksize) { 523 | DVSTARTPROFILE(); 524 | 525 | static vector _buf; //TODO, make 16 byte aligned 526 | _buf.resize(image->cols + ksize); 527 | float* buf = &_buf[0]; 528 | int rows = image->rows, cols = image->cols, stride = image->stride; 529 | int width = (ksize >= 0 ? ksize : ksize-1)>>1; 530 | float* pixels = image->pixels; 531 | float* pdst = imgdst->pixels; 532 | 533 | for (int i = 0; i < rows; ++i, pixels += stride, pdst += stride) { 534 | for(int j = 0; j < width; ++j) 535 | buf[j] = pixels[0]; 536 | for(int j = 0; j < cols; ++j) 537 | buf[width+j] = pixels[j]; 538 | for(int j = 0; j < width; ++j) 539 | buf[cols+width+j] = pixels[cols-1]; 540 | ConvBuffer(buf,kernel,cols,ksize); 541 | memcpy(pdst,buf,sizeof(float)*cols); 542 | } 543 | } 544 | 545 | void ConvVertical(Image image, float* kernel, int ksize) { 546 | DVSTARTPROFILE(); 547 | 548 | static vector _buf; //TODO, make 16 byte aligned 549 | _buf.resize(image->rows + ksize); 550 | float* buf = &_buf[0]; 551 | int rows = image->rows, cols = image->cols, stride = image->stride; 552 | int width = (ksize >= 0 ? ksize : ksize-1)>>1; 553 | float* pixels = image->pixels; 554 | 555 | for (int j = 0; j < cols; ++j, pixels += 1) { 556 | for (int i = 0; i < width; ++i) 557 | buf[i] = pixels[0]; 558 | for (int i = 0; i < rows; ++i) 559 | buf[width+i] = pixels[i*stride]; 560 | for (int i = 0; i < width; ++i) 561 | buf[rows+width+i] = pixels[(rows-1)*stride]; 562 | ConvBuffer(buf,kernel,rows,ksize); 563 | 564 | for (int i = 0; i < rows; ++i) 565 | pixels[i*stride] = buf[i]; 566 | } 567 | } 568 | 569 | void ConvBuffer(float* buf, float* kernel, int bufsize, int ksize) { 570 | for (int i = 0; i < bufsize; ++i) { 571 | float faccum = 0; 572 | for (int j = 0; j < ksize; ++j) 573 | faccum += buf[i+j]*kernel[j]; 574 | buf[i] = (float)faccum; 575 | } 576 | } 577 | 578 | #ifdef __SSE__ 579 | 580 | typedef vector LISTBUF; 581 | static LISTBUF s_listconvbuf; //TODO, make 16 byte aligned 582 | static int s_convbufsize = 0; // the size of all the buffers in s_listconvbuf 583 | static int SIFT_ALIGNED16(s_convmask[4]) = {0xffffffff,0xffffffff,0xffffffff,0}; 584 | 585 | struct myaccum { float SIFT_ALIGNED16(faccum[2][4]); }; 586 | 587 | void ConvHorizontalFast(Image imgdst, Image image, float* kernel, int ksize) { 588 | int rows = image->rows, cols = image->cols, stride = image->stride; 589 | assert( ksize >= 3 && cols >= 3 ); // 3 is cutting it close 590 | 591 | #ifdef ALIGNED_IMAGE_ROWS 592 | assert( !(image->stride&3) ); 593 | #endif 594 | 595 | DVSTARTPROFILE(); 596 | 597 | int width = (ksize >= 0 ? ksize : ksize-1)>>1; 598 | float* _pixels = image->pixels, *_pdst = imgdst->pixels; 599 | int convsize = max(100000,4*(cols + ksize)+36); 600 | 601 | if (s_listconvbuf.size() == 0 || s_convbufsize < convsize) { 602 | for (LISTBUF::iterator it = s_listconvbuf.begin(); it != s_listconvbuf.end(); ++it) 603 | sift_aligned_free(*it); 604 | s_listconvbuf.clear(); 605 | 606 | // create at least one 607 | s_listconvbuf.push_back((float*)sift_aligned_malloc(convsize,16)); 608 | s_convbufsize = convsize; 609 | 610 | #ifdef _OPENMP 611 | } else { 612 | for(LISTBUF::iterator it = s_listconvbuf.begin(); it != s_listconvbuf.end(); ++it) 613 | memset(*it+cols+ksize+1,0,32); 614 | } 615 | 616 | #else 617 | } 618 | #endif 619 | 620 | #ifdef _OPENMP 621 | for(int i = s_listconvbuf.size(); i < omp_get_max_threads(); ++i) { 622 | s_listconvbuf.push_back((float*)sift_aligned_malloc(convsize,16)); 623 | memset(s_listconvbuf.back()+cols+ksize+1,0,32); 624 | } 625 | #else 626 | float* pconvbuf = s_listconvbuf.back(); 627 | memset(pconvbuf+cols+ksize+1,0,32); 628 | #endif 629 | 630 | #pragma omp parallel for schedule(dynamic,16) 631 | for(int i = 0; i < rows; i++) { 632 | 633 | #ifdef _OPENMP 634 | float* pconvbuf; 635 | #pragma omp critical 636 | { 637 | if (s_listconvbuf.size() == 0 ) { 638 | // for some reason, crashes if this is ever executed.... 639 | pconvbuf = (float*)sift_aligned_malloc(convsize,16); 640 | memset(pconvbuf+cols+ksize+1,0,32); 641 | } else { 642 | pconvbuf = s_listconvbuf.back(); 643 | s_listconvbuf.pop_back(); 644 | } 645 | } 646 | #endif 647 | 648 | // get 16 byte aligned array 649 | myaccum ac; 650 | 651 | float* pixels = _pixels+i*stride; 652 | float* pdst = _pdst + i*stride; 653 | 654 | float* buf = pconvbuf+1; 655 | float f0 = pixels[0], f0e = pixels[cols-1]; 656 | for (int j = 0; j < width; ++j) 657 | buf[j] = f0; 658 | memcpy(buf+width,pixels,cols*sizeof(float)); 659 | for (int j = 0; j < width; ++j) 660 | buf[cols+width+j] = f0e; 661 | 662 | __m128 mkerbase = _mm_and_ps(_mm_loadu_ps(kernel), _mm_load_ps((float*)s_convmask)); 663 | 664 | for (int j = 0; j < 2*(cols>>2); ++j) { 665 | int off = 2*j-(j&1); 666 | buf = pconvbuf+1+off; 667 | __m128 maccum0 = _mm_mul_ps(_mm_loadu_ps(buf), mkerbase); 668 | __m128 maccum1 = _mm_mul_ps(_mm_loadu_ps(buf+2), mkerbase); 669 | 670 | __m128 mbufprev = _mm_loadu_ps(buf+3); 671 | for (int k = 3; k < ksize; k += 8) { 672 | __m128 mbuf0 = mbufprev; 673 | __m128 mker0 = _mm_load_ps(kernel+k); 674 | __m128 mbuf1 = _mm_loadu_ps(buf+k+4); 675 | __m128 mker1 = _mm_load_ps(kernel+k+4); 676 | 677 | // accumulate the first row 678 | maccum0 = _mm_add_ps(maccum0,_mm_mul_ps(mbuf0,mker0)); 679 | maccum0 = _mm_add_ps(maccum0,_mm_mul_ps(mbuf1,mker1)); 680 | 681 | mbufprev = _mm_loadu_ps(buf+k+8); // load new 682 | mbuf0 = _mm_shuffle_ps(mbufprev,mbuf0,0xe4); // remove first 2 elts 683 | 684 | // arrange kernel to match mbuf0 and mbuf1 for second row 685 | __m128 mkertemp = mker0; 686 | mker0 = _mm_shuffle_ps(mker1,mker0,0x4e); 687 | mker1 = _mm_shuffle_ps(mkertemp,mker1,0x4e); 688 | 689 | // accumulate the second row 690 | maccum1 = _mm_add_ps(maccum1,_mm_mul_ps(mbuf0,mker0)); 691 | maccum1 = _mm_add_ps(maccum1,_mm_mul_ps(mbuf1,mker1)); 692 | } 693 | 694 | #ifdef __SSE3__ 695 | maccum0 = _mm_hadd_ps(maccum0,maccum1); 696 | maccum0 = _mm_hadd_ps(maccum0,maccum0); 697 | _mm_storel_pi((__m64*)ac.faccum[0],maccum0); 698 | pdst[off] = ac.faccum[0][0]; 699 | pdst[off+2] = ac.faccum[0][1]; 700 | #else 701 | _mm_store_ps(ac.faccum[0],maccum0); 702 | _mm_store_ps(ac.faccum[1],maccum1); 703 | pdst[off] = ac.faccum[0][0]+ac.faccum[0][1]+ac.faccum[0][2]+ac.faccum[0][3]; 704 | pdst[off+2] = ac.faccum[1][0]+ac.faccum[1][1]+ac.faccum[1][2]+ac.faccum[1][3]; 705 | #endif 706 | } 707 | 708 | // take care of the left over columns 709 | for (int j=(cols&~3); j < cols; ++j) { 710 | buf = pconvbuf+j+1; 711 | __m128 maccum0 = _mm_mul_ps(_mm_loadu_ps(buf), mkerbase); 712 | for (int k = 3; k < ksize; k += 4) { 713 | __m128 mbuf0 = _mm_loadu_ps(buf+k); 714 | __m128 mker0 = _mm_load_ps(kernel+k); 715 | maccum0 = _mm_add_ps(maccum0,_mm_mul_ps(mbuf0,mker0)); 716 | } 717 | 718 | #ifdef __SSE3__ 719 | maccum0 = _mm_hadd_ps(maccum0,maccum0); 720 | maccum0 = _mm_hadd_ps(maccum0,maccum0); 721 | _mm_store_ss(&pdst[j],maccum0); 722 | #else 723 | _mm_store_ps(ac.faccum[0],maccum0); 724 | pdst[j] = ac.faccum[0][0]+ac.faccum[0][1]+ac.faccum[0][2]+ac.faccum[0][3]; 725 | #endif 726 | } 727 | 728 | #ifdef _OPENMP 729 | #pragma omp critical 730 | { 731 | s_listconvbuf.push_back(pconvbuf); 732 | } 733 | #endif 734 | } 735 | } 736 | 737 | void ConvVerticalFast(Image image, float* kernel, int ksize) { 738 | int rows = image->rows, stride = image->stride; 739 | // 3 is cutting it close 740 | assert( ksize >= 3); 741 | 742 | #ifdef ALIGNED_IMAGE_ROWS 743 | assert( !(image->stride&3) ); 744 | #endif 745 | 746 | DVSTARTPROFILE(); 747 | int convsize = max(100000,32*(image->rows + ksize+4)); 748 | if (s_listconvbuf.size() == 0 || s_convbufsize < convsize) { 749 | for (LISTBUF::iterator it = s_listconvbuf.begin(); it != s_listconvbuf.end(); ++it) 750 | sift_aligned_free(*it); 751 | s_listconvbuf.clear(); 752 | 753 | // create at least one 754 | s_listconvbuf.push_back((float*)sift_aligned_malloc(convsize,16)); 755 | s_convbufsize = convsize; 756 | } 757 | 758 | #ifdef _OPENMP 759 | for (int i = s_listconvbuf.size(); i < omp_get_max_threads(); ++i) { 760 | s_listconvbuf.push_back((float*)sift_aligned_malloc(convsize,16)); 761 | } 762 | #else 763 | float* pconvbuf = s_listconvbuf.back(); 764 | #endif 765 | 766 | int width = (ksize >= 0 ? ksize : ksize-1)>>1; 767 | float* _pixels = image->pixels; 768 | 769 | #pragma omp parallel for 770 | for (int j = 0; j < stride; j += 4) { 771 | float* pixels = _pixels+j; 772 | 773 | #ifndef ALIGNED_IMAGE_ROWS 774 | myaccum ac; 775 | #endif 776 | #ifdef _OPENMP 777 | float* pconvbuf; 778 | // need to get a free buffer 779 | #pragma omp critical 780 | { 781 | if( s_listconvbuf.size() == 0 ) { 782 | pconvbuf = (float*)sift_aligned_malloc(convsize,16); 783 | } 784 | else { 785 | pconvbuf = s_listconvbuf.back(); 786 | s_listconvbuf.pop_back(); 787 | } 788 | } 789 | #endif 790 | 791 | __m128 mpprev = _MM_LOAD_ALIGNED(pixels); 792 | __m128 mprev = mpprev; 793 | __m128 mker0 = _mm_load1_ps(kernel); 794 | __m128 mker1 = _mm_load1_ps(kernel+1); 795 | __m128 mker2 = _mm_load1_ps(kernel+2); 796 | 797 | float* buf = pconvbuf; 798 | for (int i = 2; i <= width; ++i) { 799 | _mm_store_ps(buf,mpprev); 800 | __m128 maccum = _mm_add_ps(_mm_mul_ps(mpprev,mker0), _mm_mul_ps(mprev,mker1)); 801 | maccum = _mm_add_ps(maccum,_mm_mul_ps(mprev,mker2)); 802 | _mm_store_ps(buf+4,maccum); 803 | buf += 8; 804 | } 805 | for (int i = 1; i < rows-width+2; ++i) { 806 | __m128 mnew = _MM_LOAD_ALIGNED(pixels+i*stride); 807 | 808 | _mm_store_ps(buf,mpprev); 809 | __m128 maccum = _mm_add_ps(_mm_mul_ps(mpprev,mker0), _mm_mul_ps(mprev,mker1)); 810 | maccum = _mm_add_ps(maccum,_mm_mul_ps(mnew,mker2)); 811 | mpprev = mprev; 812 | _mm_store_ps(buf+4,maccum); 813 | mprev = mnew; 814 | buf += 8; 815 | } 816 | 817 | _mm_store_ps(buf,mpprev); buf += 8; 818 | for (int i = rows-width+2; i < rows; ++i) { 819 | __m128 mnew = _mm_loadu_ps(pixels+i*stride); 820 | _mm_store_ps(buf,mprev); 821 | mprev = mnew; 822 | buf += 8; 823 | } 824 | 825 | // mprev points to the last row 826 | for (int i = 0; i < width; ++i) { 827 | _mm_store_ps(buf,mprev); 828 | buf += 8; 829 | } 830 | // have to pad rest with zeros 831 | memset(buf,0,convsize-((char*)buf-(char*)pconvbuf)); 832 | 833 | //// finally convolve 834 | buf = pconvbuf; 835 | 836 | for (int i = 0; i < rows; ++i, buf += 8) { 837 | __m128 maccum = _mm_load_ps(buf+4); 838 | if (ksize > 3) { 839 | for (int k = 3; k < ksize; k += 4) { 840 | float* psrc = buf + 8*k; 841 | __m128 mkerall = _mm_load_ps(kernel+k); 842 | __m128 mnew0 = _mm_load_ps(psrc); 843 | mker0 = _mm_shuffle_ps(mkerall,mkerall,0); 844 | __m128 mnew1 = _mm_load_ps(psrc + 8); 845 | mker1 = _mm_shuffle_ps(mkerall,mkerall,0x55); 846 | __m128 mnew2 = _mm_load_ps(psrc + 16); 847 | maccum = _mm_add_ps(maccum,_mm_mul_ps(mker0,mnew0)); 848 | maccum = _mm_add_ps(maccum,_mm_mul_ps(mker1,mnew1)); 849 | __m128 mnew3 = _mm_load_ps(psrc + 24); 850 | mker2 = _mm_shuffle_ps(mkerall,mkerall,0xaa); 851 | maccum = _mm_add_ps(maccum,_mm_mul_ps(mker2,mnew2)); 852 | maccum = _mm_add_ps(maccum,_mm_mul_ps(_mm_shuffle_ps(mkerall,mkerall,0xff),mnew3)); 853 | } 854 | } 855 | 856 | #ifdef ALIGNED_IMAGE_ROWS 857 | _mm_store_ps(pixels+i*stride,maccum); 858 | #else 859 | if (j <= stride-4) { 860 | _mm_storeu_ps(pixels+i*stride,maccum); 861 | 862 | } else { 863 | _mm_store_ps(ac.faccum[0],maccum); 864 | for (int k = 0; k < ((stride-j)&3); ++k) 865 | pixels[i*stride+k] = ac.faccum[0][k]; 866 | } 867 | #endif 868 | } 869 | 870 | #ifdef _OPENMP 871 | #pragma omp critical 872 | { 873 | s_listconvbuf.push_back(pconvbuf); 874 | } 875 | #endif 876 | } 877 | } 878 | 879 | #endif 880 | 881 | Keypoint FindMaxMin(Image* imdiff, Image* imgaus, float fscale, Keypoint keypts) { 882 | DVSTARTPROFILE(); 883 | 884 | int rows = imdiff[0]->rows, cols = imdiff[0]->cols, stride = imdiff[0]->stride; 885 | memset(s_MaxMinArray,0,rows*cols); 886 | for (int index = 1; index < Scales+1; ++index) { 887 | #if !defined(_MSC_VER) && defined(__SSE__) 888 | GradOriImagesFast(imgaus[index],s_imgrad,s_imorient); 889 | #else 890 | GradOriImages(imgaus[index],s_imgrad,s_imorient); 891 | #endif 892 | assert(imdiff[index]->stride == stride); 893 | float* _diffpixels = imdiff[index]->pixels; 894 | 895 | // for(int i = 0; i < rows; ++i) { 896 | // for(int j = 0; j < cols; ++j) { 897 | // if( isnan(imgaus[index]->pixels[i*cols+j]) ) { 898 | // fprintf(stderr, "gaus: %d %d %d %d %d %f %f\n", index,i,j,rows,cols,s_imgrad->pixels[i*cols+j],s_imorient->pixels[i*cols+j]); 899 | // //exit(0); 900 | // } 901 | //// if( isnan(s_imorient->pixels[i*cols+j]) ) { 902 | //// //GradOriImagesFast(imgaus[index],s_imgrad,s_imorient); 903 | //// fprintf(stderr,"rc %d %d\n",rows,cols); 904 | //// fprintf(stderr,"wtf %d %d %f %f %f %f\n",i,j, s_imgrad->pixels[i*cols+j], imgaus[index]->pixels[i*cols+j], imgaus[index]->pixels[i*cols+j-1], imgaus[index]->pixels[i*cols+j+1]); 905 | //// fprintf(stderr,"%f %f\n",imgaus[index]->pixels[(i-1)*cols+j], imgaus[index]->pixels[(i+1)*cols+j]); 906 | //// exit(0); 907 | //// } 908 | // } 909 | // } 910 | 911 | #pragma omp parallel for schedule(dynamic,8) 912 | for (int rowstart = 5; rowstart < rows-5; ++rowstart) { 913 | Keypoint newkeypts = NULL; 914 | float* diffpixels = _diffpixels + rowstart*stride; 915 | for (int colstart = 5; colstart < cols-5; ++colstart) { 916 | float fval = diffpixels[colstart]; 917 | if (fabsf(fval) > PeakThresh*0.8f) { 918 | if (LocalMaxMin(fval, imdiff[index],rowstart,colstart) && 919 | LocalMaxMin(fval, imdiff[index-1],rowstart,colstart) && 920 | LocalMaxMin(fval, imdiff[index+1],rowstart,colstart) && 921 | NotOnEdge(imdiff[index],rowstart,colstart)) { 922 | newkeypts = InterpKeyPoint(imdiff,index,rowstart,colstart,s_imgrad,s_imorient,s_MaxMinArray,fscale,newkeypts,5); 923 | } 924 | } 925 | } 926 | 927 | if (newkeypts != NULL) { 928 | // find the last keypoint 929 | Keypoint lastkeypt = newkeypts; 930 | while (lastkeypt->next) 931 | lastkeypt = lastkeypt->next;; 932 | 933 | #pragma omp critical 934 | { 935 | lastkeypt->next = keypts; 936 | keypts = newkeypts; 937 | } 938 | } 939 | } 940 | } 941 | 942 | return keypts; 943 | } 944 | 945 | void GradOriImages(Image image, Image imgrad, Image imorient) { 946 | DVSTARTPROFILE(); 947 | 948 | int rows = image->rows, cols = image->cols, stride = image->stride; 949 | float* _pixels = image->pixels, *_pfgrad = imgrad->pixels, *_pforient = imorient->pixels; 950 | float fdiffc, fdiffr; 951 | 952 | #pragma omp parallel for schedule(dynamic,16) // might crash Matlab mex files 953 | for (int i = 0; i < rows; ++i) { 954 | float* pixels = _pixels + i*stride; 955 | float* pfgrad = _pfgrad + i*stride; 956 | float* pforient = _pforient + i*stride; 957 | 958 | for (int j = 0; j < cols; ++j) { 959 | if (j == 0) 960 | fdiffc = 2.0f*(pixels[1]-pixels[0]); 961 | else if (j == cols-1) 962 | fdiffc = 2.0f*(pixels[j]-pixels[j-1]); 963 | else 964 | fdiffc = pixels[j+1] - pixels[j-1]; 965 | 966 | if (i == 0) 967 | fdiffr = 2.0f*(pixels[j] - pixels[stride+j]); 968 | else if (i == rows-1) 969 | fdiffr = 2.0f*(pixels[-stride+j] - pixels[j]); 970 | else 971 | fdiffr = pixels[-stride+j] - pixels[stride+j]; 972 | 973 | pfgrad[j] = sqrtf(fdiffc*fdiffc + fdiffr*fdiffr); 974 | pforient[j] = atan2f(fdiffr,fdiffc); 975 | } 976 | } 977 | } 978 | 979 | void GradOriImagesFast(Image image, Image imgrad, Image imorient) { 980 | GradOriImages(image, imgrad, imorient); 981 | } 982 | 983 | /* 984 | #if !defined(_MSC_VER) && defined(__SSE__) 985 | void what_GradOriImagesFast(Image image, Image imgrad, Image imorient) 986 | { 987 | ///DVSTARTPROFILE(); 988 | 989 | int rows = image->rows, cols = image->cols, stride = image->stride; 990 | float* _pixels = image->pixels, *_pfgrad = imgrad->pixels, *_pforient = imorient->pixels; 991 | int endcol = ((cols-1)&~3); 992 | 993 | { 994 | // first row is special 2*(_pixels[0]-_pixels[stride]) 995 | float fdiffc, fdiffr; 996 | 997 | // first and last elt is 2*([1]-[0]), have to improvise for sse 998 | __m128 mprevj = _mm_set_ps(_pixels[2],_pixels[1],_pixels[0],2.0f*_pixels[0]-_pixels[1]); 999 | 1000 | for(int j = 0; j < endcol; j += 4) { 1001 | float* pf = _pixels+j; 1002 | __m128 mnewj = _mm_loadu_ps(pf+3); 1003 | __m128 mgradr = _MM_LOAD_ALIGNED(pf); 1004 | __m128 mgradc = _mm_sub_ps(_mm_shuffle_ps(mprevj,mnewj,0x4e),mprevj); 1005 | mgradr = _mm_sub_ps(mgradr, _MM_LOAD_ALIGNED(pf+stride)); 1006 | mgradr = _mm_add_ps(mgradr,mgradr); 1007 | 1008 | __m128 mrad = _mm_sqrt_ps(_mm_add_ps(_mm_mul_ps(mgradr,mgradr),_mm_mul_ps(mgradc,mgradc))); 1009 | __m128 morient = atan2f4(mgradr,mgradc); 1010 | 1011 | _MM_STORE_ALIGNED(_pfgrad+j,mrad); 1012 | mprevj = mnewj; 1013 | _MM_STORE_ALIGNED(_pforient+j,morient); 1014 | } 1015 | 1016 | 1017 | // compute the rest the old way 1018 | for(int j = endcol; j < cols; ++j) { 1019 | if( j == 0 ) 1020 | fdiffc = 2.0f*(_pixels[1]-_pixels[0]); 1021 | else if( j == cols-1 ) 1022 | fdiffc = 2.0f*(_pixels[j]-_pixels[j-1]); 1023 | else 1024 | fdiffc = _pixels[j+1] - _pixels[j-1]; 1025 | 1026 | fdiffr = 2.0f*(_pixels[j] - _pixels[stride+j]); 1027 | 1028 | _pfgrad[j] = sqrtf(fdiffc*fdiffc + fdiffr*fdiffr); 1029 | _pforient[j] = atan2f(fdiffr,fdiffc); 1030 | } 1031 | } 1032 | 1033 | #pragma omp parallel for schedule(dynamic,16) // might crash Matlab mex files 1034 | for(int i = 1; i < rows-1; ++i) { 1035 | 1036 | float fdiffc, fdiffr; 1037 | float* pixels = _pixels + i*stride; 1038 | float* pfgrad = _pfgrad + i*stride; 1039 | float* pforient = _pforient + i*stride; 1040 | 1041 | // first and last elt is 2*([1]-[0]), have to improvise for sse 1042 | __m128 mprevj = _mm_set_ps(pixels[2],pixels[1],pixels[0],2.0f*pixels[0]-pixels[1]); 1043 | 1044 | for(int j = 0; j < endcol; j += 4) { 1045 | float* pf = pixels+j; 1046 | __m128 mnewj = _mm_loadu_ps(pf+3); 1047 | __m128 mgradr = _MM_LOAD_ALIGNED(pf-stride); 1048 | __m128 mgradc = _mm_sub_ps(_mm_shuffle_ps(mprevj,mnewj,0x4e),mprevj); 1049 | mgradr = _mm_sub_ps(mgradr,_MM_LOAD_ALIGNED(pf+stride)); 1050 | 1051 | __m128 mrad = _mm_sqrt_ps(_mm_add_ps(_mm_mul_ps(mgradr,mgradr),_mm_mul_ps(mgradc,mgradc))); 1052 | __m128 morient = atan2f4(mgradr,mgradc); 1053 | 1054 | _MM_STORE_ALIGNED(pfgrad+j,mrad); 1055 | mprevj = mnewj; 1056 | _MM_STORE_ALIGNED(pforient+j,morient); 1057 | } 1058 | 1059 | assert( i != 0 && i != rows-1 ); 1060 | // compute the rest the old way 1061 | for(int j = endcol; j < cols; ++j) { 1062 | if( j == cols-1 ) 1063 | fdiffc = 2.0f*(pixels[j]-pixels[j-1]); 1064 | else 1065 | fdiffc = pixels[j+1] - pixels[j-1]; 1066 | 1067 | fdiffr = pixels[-stride+j] - pixels[stride+j]; 1068 | 1069 | pfgrad[j] = sqrtf(fdiffc*fdiffc + fdiffr*fdiffr); 1070 | pforient[j] = atan2f(fdiffr,fdiffc); 1071 | } 1072 | } 1073 | 1074 | { 1075 | float fdiffc, fdiffr; 1076 | float* pixels = _pixels + (rows-1)*stride; 1077 | float* pfgrad = _pfgrad + (rows-1)*stride; 1078 | float* pforient = _pforient + (rows-1)*stride; 1079 | 1080 | // last row is special 2*(pixels[stride*(cols-1)]-pixels[stride*(cols-2)]) 1081 | // first and last elt is 2*([1]-[0]), have to improvise for sse 1082 | __m128 mprevj = _mm_set_ps(pixels[2],pixels[1],pixels[0],2.0f*pixels[0]-pixels[1]); 1083 | 1084 | for(int j = 0; j < endcol; j += 4) { 1085 | float* pf = pixels+j; 1086 | __m128 mnewj = _mm_loadu_ps(pf+3); 1087 | __m128 mgradr = _MM_LOAD_ALIGNED(pf-stride); 1088 | __m128 mgradc = _mm_sub_ps(_mm_shuffle_ps(mprevj,mnewj,0x4e),mprevj); 1089 | mgradr = _mm_sub_ps(mgradr,_MM_LOAD_ALIGNED(pf)); 1090 | mgradr = _mm_add_ps(mgradr,mgradr); 1091 | 1092 | __m128 mrad = _mm_sqrt_ps(_mm_add_ps(_mm_mul_ps(mgradr,mgradr),_mm_mul_ps(mgradc,mgradc))); 1093 | __m128 morient = atan2f4(mgradr,mgradc); 1094 | 1095 | _MM_STORE_ALIGNED(pfgrad+j,mrad); 1096 | mprevj = mnewj; 1097 | _MM_STORE_ALIGNED(pforient+j,morient); 1098 | } 1099 | 1100 | // compute the rest the old way 1101 | for(int j = endcol; j < cols; ++j) { 1102 | if( j == cols-1 ) 1103 | fdiffc = 2.0f*(pixels[j]-pixels[j-1]); 1104 | else 1105 | fdiffc = pixels[j+1] - pixels[j-1]; 1106 | 1107 | fdiffr = 2.0f*(pixels[-stride+j] - pixels[j]); 1108 | 1109 | pfgrad[j] = sqrtf(fdiffc*fdiffc + fdiffr*fdiffr); 1110 | pforient[j] = atan2f(fdiffr,fdiffc); 1111 | } 1112 | } 1113 | } 1114 | #endif 1115 | */ 1116 | 1117 | int LocalMaxMin(float fval, Image imdiff, int rowstart, int colstart) { 1118 | int stride = imdiff->stride; 1119 | float* pixels = imdiff->pixels; 1120 | 1121 | if (fval > 0) { 1122 | for (int row = rowstart-1; row <= rowstart+1; ++row) { 1123 | float* pf = pixels + row*stride + colstart - 1; 1124 | if (pf[0] > fval || pf[1] > fval || pf[2] > fval) 1125 | return 0; 1126 | } 1127 | } else { 1128 | for (int row = rowstart-1; row <= rowstart+1; ++row) { 1129 | float* pf = pixels + row*stride + colstart-1; 1130 | if (fval > pf[0] || fval > pf[1] || fval > pf[2]) 1131 | return 0; 1132 | } 1133 | } 1134 | 1135 | return 1; 1136 | } 1137 | 1138 | int NotOnEdge(Image imdiff, int row, int col) { 1139 | // probably wrong, something to do with plane normals? 1140 | int stride = imdiff->stride; 1141 | float* pixels = imdiff->pixels + row*stride; 1142 | float f1 = pixels[-stride+col] - pixels[col]*2 + pixels[stride+col]; 1143 | float f2 = pixels[col-1] - pixels[col]*2 + pixels[col+1]; 1144 | float f3 = pixels[stride+col+1] - pixels[stride+col-1]; 1145 | float f4 = pixels[-stride+col+1] - pixels[-stride+col-1]; 1146 | float f5 = (f3 - f4)*0.25f; 1147 | float f6 = f1*f2 - f5*f5; 1148 | float f8 = f1+f2; 1149 | return f6*11*11 > f8*f8*10; 1150 | } 1151 | 1152 | Keypoint InterpKeyPoint(Image* imdiff, int index, int rowstart, int colstart, 1153 | Image imgrad, Image imorient, char* pMaxMinArray, 1154 | float fscale,Keypoint keypts, int steps) { 1155 | float X[3]; 1156 | float fquadvalue = FitQuadratic(X, imdiff, index, rowstart, colstart); 1157 | 1158 | int newrow = rowstart; 1159 | int newcol = colstart; 1160 | if (X[1] > 0.6f && rowstart < imdiff[0]->rows-3) 1161 | newrow++; 1162 | if (X[1] < -0.6f && rowstart>3) 1163 | newrow--; 1164 | if (X[2] > 0.6f && colstart < imdiff[0]->cols-3) 1165 | newcol++; 1166 | if (X[2] < -0.6f && colstart>3) 1167 | newcol--; 1168 | 1169 | // check if local min/max is stable at (newrow,newcol). If not and steps haven't surprassed, 1170 | // recompute at new location 1171 | if (steps > 0 && (newrow != rowstart || newcol != colstart)) 1172 | return InterpKeyPoint(imdiff,index,newrow,newcol,imgrad,imorient,pMaxMinArray,fscale,keypts,steps-1); 1173 | 1174 | if (fabsf(X[0]) <= 1.5f && fabsf(X[1]) <= 1.5f && fabsf(X[2]) <= 1.5f && fabsf(fquadvalue) >= PeakThresh) { 1175 | 1176 | char* pmaxmin = pMaxMinArray + rowstart*imgrad->cols+colstart; 1177 | bool bgetkeypts = false; 1178 | #pragma omp critical 1179 | { 1180 | if (!pmaxmin[0]) { 1181 | bgetkeypts = true; 1182 | pmaxmin[0] = 1; 1183 | } 1184 | } 1185 | 1186 | if (bgetkeypts) { 1187 | float fSize = InitSigma * powf(2.0f,((float)index + X[0])/(float)Scales); 1188 | return AssignOriHist(imgrad,imorient,fscale,fSize,(float)rowstart+X[1],(float)colstart+X[2],keypts); 1189 | } 1190 | } 1191 | 1192 | return keypts; 1193 | } 1194 | 1195 | // fits a quadratic to a 3x3x3 box, returns the value of the quadratic at the center 1196 | float FitQuadratic(float* X, Image* imdiff, int index, int r, int c) { 1197 | float H[9]; 1198 | int stride = imdiff[index-1]->stride; 1199 | assert( stride == imdiff[index]->stride && stride == imdiff[index+1]->stride ); 1200 | float* pixels0 = imdiff[index-1]->pixels + r*stride; 1201 | float* pixels1 = imdiff[index]->pixels + r*stride; 1202 | float* pixels2 = imdiff[index+1]->pixels + r*stride; 1203 | 1204 | float Y[3]; 1205 | Y[0] = 0.5f*(pixels2[c] - pixels0[c]); 1206 | Y[1] = 0.5f*(pixels1[stride+c] - pixels1[-stride+c]); 1207 | Y[2] = 0.5f*(pixels1[c+1] - pixels1[c-1]); 1208 | H[0] = pixels0[c] - 2.0f*pixels1[c] + pixels2[c]; 1209 | H[4] = pixels1[-stride+c] - 2.0f*pixels1[c] + pixels1[stride+c]; 1210 | H[8] = pixels1[c-1] - 2.0f*pixels1[c] + pixels1[c+1]; 1211 | H[3] = H[1] = 0.25f*((pixels2[stride+c] - pixels2[-stride+c]) - (pixels0[stride+c] - pixels0[-stride+c])); 1212 | H[6] = H[2] = 0.25f*((pixels2[c+1] - pixels2[c-1]) - (pixels0[c+1] - pixels0[c-1])); 1213 | H[7] = H[5] = 0.25f*((pixels1[stride+c+1] - pixels1[stride+c-1]) - (pixels1[-stride+c+1] - pixels1[-stride+c-1])); 1214 | 1215 | X[0] = -Y[0]; X[1] = -Y[1]; X[2] = -Y[2]; 1216 | SolveLinearSystem(X,H,3); // writes answer to X? 1217 | return pixels1[c] + 0.5f * (X[0]*Y[0] + X[1]*Y[1] + X[2]*Y[2]); 1218 | } 1219 | 1220 | // solve for X in H*X = Y using Gauss-Jordan method 1221 | // write the result back in Y 1222 | void SolveLinearSystem(float* Y, float* H, int dim) { 1223 | float fmax; 1224 | int bestj = 0; 1225 | 1226 | for (int i = 0; i < dim-1; ++i) { 1227 | fmax = -1; 1228 | 1229 | for(int j = i; j < dim; ++j) { 1230 | float f = H[j*dim+i]; 1231 | if (f < 0) 1232 | f = -f; 1233 | if (f > fmax) { 1234 | fmax = f; 1235 | bestj = j; 1236 | } 1237 | } 1238 | 1239 | if (bestj != i) { 1240 | for (int j = 0; j < dim; ++j) 1241 | swap(H[bestj*dim+j], H[i*dim+j]); 1242 | swap(Y[bestj],Y[i]); 1243 | } 1244 | 1245 | for (int j = i+1; j < dim; ++j) { 1246 | float f = H[j*dim+i]/H[i*dim+i]; 1247 | for (int k = i; k < dim; ++k) 1248 | H[j*dim+k] -= f*H[i*dim+k]; 1249 | Y[j] -= Y[i]*f; 1250 | } 1251 | } 1252 | 1253 | // extract solution 1254 | for (int i = dim-1; i >= 0; --i) { 1255 | for (int j = dim-1; j > i; --j) 1256 | Y[i] -= Y[j]*H[i*dim+j]; 1257 | Y[i] /= H[i*dim+i]; 1258 | } 1259 | } 1260 | 1261 | Keypoint AssignOriHist(Image imgrad, Image imorient, float fscale, float fSize, 1262 | float frowstart, float fcolstart, Keypoint keypts) { 1263 | int rowstart = (int)(frowstart+0.5f); 1264 | int colstart = (int)(fcolstart+0.5f); 1265 | int rows = imgrad->rows, cols = imgrad->cols, stride = imgrad->stride; 1266 | float SIFT_ALIGNED16(hists[36]); 1267 | float fexpmult = -1.0f / (2.0f*1.5f*1.5f*fSize*fSize); 1268 | memset(hists,0,sizeof(hists)); 1269 | 1270 | const float fbinmult = 36.0f/(2*PI); 1271 | const float fbinadd = (float)(PI+0.001f)*fbinmult; 1272 | 1273 | // gather votes for orientation 1274 | int windowsize = (int)(fSize*1.5f*3.0f); 1275 | float* pfgrad = imgrad->pixels + (rowstart-windowsize)*stride, *pforient = imorient->pixels; 1276 | for (int rowcur = rowstart-windowsize; rowcur <= rowstart+windowsize; ++rowcur, pfgrad += stride) { 1277 | 1278 | if( rowcur < 0 || rowcur >= rows-2 ) 1279 | continue; 1280 | 1281 | for (int colcur = colstart-windowsize; colcur <= colstart+windowsize; ++colcur) { 1282 | 1283 | if (colcur < 0 || colcur >= cols-2) 1284 | continue; 1285 | 1286 | float fdx = pfgrad[colcur]; 1287 | if (fdx > 0) { 1288 | float fdrow = (float)rowcur-frowstart, fdcol = (float)colcur-fcolstart; 1289 | float fradius2 = fdrow*fdrow+fdcol*fdcol; 1290 | 1291 | if ((float)(windowsize*windowsize) + 0.5f > fradius2) { 1292 | float fweight = expf(fradius2*fexpmult); 1293 | int binindex = (int)(pforient[rowcur*stride+colcur]*fbinmult+fbinadd); 1294 | 1295 | // there is a bug in pforient where it could be 2*PI sometimes 1296 | if (binindex > 36) { 1297 | fprintf(stderr,"bin %d\n",binindex); 1298 | binindex = 0; 1299 | } 1300 | 1301 | assert(binindex >= 0 && binindex <= 36); 1302 | if (binindex == 36) 1303 | binindex = 35; 1304 | 1305 | hists[binindex] += fdx*fweight; 1306 | } 1307 | } 1308 | } 1309 | } 1310 | 1311 | // pick an orientation with the highest votes 1312 | for (int i = 0; i < 6; ++i) 1313 | SmoothHistogram(hists,36); 1314 | 1315 | #ifdef __SSE__ 1316 | float SIFT_ALIGNED16(fmaxval); 1317 | __m128 m0 = _mm_load_ps(&hists[0]); 1318 | __m128 m1 = _mm_load_ps(&hists[4]); 1319 | __m128 m2 = _mm_load_ps(&hists[8]); 1320 | __m128 m3 = _mm_load_ps(&hists[12]); 1321 | m0 = _mm_max_ps(m0,m1); 1322 | m2 = _mm_max_ps(m2,m3); 1323 | __m128 m4 = _mm_load_ps(&hists[16]); 1324 | __m128 m5 = _mm_load_ps(&hists[20]); 1325 | __m128 m6 = _mm_load_ps(&hists[24]); 1326 | __m128 m7 = _mm_load_ps(&hists[28]); 1327 | m4 = _mm_max_ps(m4,m5); 1328 | m6 = _mm_max_ps(m6,m7); 1329 | m0 = _mm_max_ps(m0,_mm_load_ps(&hists[32])); 1330 | m2 = _mm_max_ps(m2,_mm_max_ps(m4,m6)); 1331 | m0 = _mm_max_ps(m0,m2); 1332 | m0 = _mm_max_ps(m0, _mm_shuffle_ps(m0,m0,0x4e)); 1333 | _mm_store_ss(&fmaxval,_mm_max_ps(m0, _mm_shuffle_ps(m0,m0,0x11))); 1334 | #else 1335 | float fmaxval = 0; 1336 | for (int i = 0; i < 36; ++i) { 1337 | if (hists[i] > fmaxval) 1338 | fmaxval = hists[i]; 1339 | } 1340 | #endif 1341 | 1342 | fmaxval *= 0.8f; 1343 | const float foriadd = 0.5f*2*PI/36.0f - PI, forimult = 2*PI/36.0f; 1344 | 1345 | int previndex = 35; 1346 | for (int index = 0; index < 36; ++index) { 1347 | if(index != 0) 1348 | previndex = index-1; 1349 | 1350 | int nextindex = 0; 1351 | if (index != 35) 1352 | nextindex = index+1; 1353 | 1354 | if (hists[index] <= hists[previndex] || hists[index] <= hists[nextindex] || hists[index] < fmaxval) 1355 | continue; 1356 | 1357 | float fpeak = InterpPeak(hists[previndex],hists[index],hists[nextindex]); 1358 | float forient = (index + fpeak)*forimult + foriadd; 1359 | assert (forient >= -PI && forient <= PI); // error, bad orientation 1360 | 1361 | keypts = MakeKeypoint(imgrad,imorient,fscale,fSize,frowstart,fcolstart,forient,keypts); 1362 | } 1363 | 1364 | return keypts; 1365 | } 1366 | 1367 | float InterpPeak(float f0, float f1, float f2) { 1368 | if (f1 < 0) { 1369 | f0 = -f0; 1370 | f1 = -f1; 1371 | f2 = -f2; 1372 | } 1373 | assert( f1 >= f0 && f1 > f2 ); 1374 | return 0.5f*(f0 - f2) / (f0 - 2.0f*f1 + f2); 1375 | } 1376 | 1377 | void SmoothHistogram(float* phist, int numbins) { 1378 | float ffirst = phist[0]; 1379 | float fprev = phist[numbins-1]; 1380 | for (int i = 0; i < numbins-1; ++i) { 1381 | float forg = phist[i]; 1382 | phist[i] = (fprev + forg + phist[i+1])*0.33333333f; 1383 | fprev = forg; 1384 | } 1385 | 1386 | // TODO: replace phist[0] with ffirst 1387 | phist[numbins-1] = (fprev+phist[numbins-1]+ffirst)*0.3333333f; 1388 | } 1389 | 1390 | Keypoint MakeKeypoint(Image imgrad, Image imorient, float fscale, float fSize, 1391 | float frowstart,float fcolstart,float forient, Keypoint keypts) { 1392 | 1393 | Keypoint pnewkeypt; 1394 | 1395 | #pragma omp critical 1396 | { 1397 | if (s_listKeypoints.size() > 0) { 1398 | pnewkeypt = s_listKeypoints.back(); 1399 | s_listKeypoints.pop_back(); 1400 | } else { 1401 | pnewkeypt = (Keypoint)sift_aligned_malloc(sizeof(KeypointSt),16); 1402 | } 1403 | } 1404 | 1405 | pnewkeypt->next = keypts; 1406 | pnewkeypt->ori = forient; 1407 | pnewkeypt->row = fscale*frowstart; 1408 | pnewkeypt->col = fscale*fcolstart; 1409 | pnewkeypt->scale = fscale*fSize; 1410 | MakeKeypointSample(pnewkeypt,imgrad,imorient,fSize,frowstart,fcolstart); 1411 | return pnewkeypt; 1412 | } 1413 | 1414 | void MakeKeypointSample(Keypoint pkeypt, Image imgrad, Image imorient, 1415 | float fSize, float frowstart, float fcolstart) { 1416 | 1417 | float* fdesc = pkeypt->descrip; 1418 | memset(fdesc,0,sizeof(float)*128); 1419 | KeySample(fdesc, pkeypt, imgrad, imorient, fSize, frowstart, fcolstart); 1420 | 1421 | #ifdef __SSE__ 1422 | __m128 maccum0 = _mm_load_ps(fdesc); 1423 | __m128 maccum1 = _mm_load_ps(fdesc+4); 1424 | maccum0 = _mm_mul_ps(maccum0,maccum0); 1425 | maccum1 = _mm_mul_ps(maccum1,maccum1); 1426 | for(int i = 8; i < 128; i += 8 ) { 1427 | __m128 m0 = _mm_load_ps(fdesc+i); 1428 | __m128 m1 = _mm_load_ps(fdesc+i+4); 1429 | maccum0 = _mm_add_ps(maccum0,_mm_mul_ps(m0,m0)); 1430 | maccum1 = _mm_add_ps(maccum1,_mm_mul_ps(m1,m1)); 1431 | } 1432 | 1433 | maccum0 = _mm_add_ps(maccum0,maccum1); 1434 | #ifdef __SSE3__ 1435 | maccum0 = _mm_hadd_ps(maccum0,maccum0); 1436 | maccum0 = _mm_hadd_ps(maccum0,maccum0); 1437 | #else 1438 | maccum0 = _mm_add_ps(maccum0,_mm_shuffle_ps(maccum0,maccum0,0x4e)); 1439 | maccum0 = _mm_add_ss(maccum0,_mm_shuffle_ps(maccum0,maccum0,0x55)); 1440 | #endif 1441 | 1442 | float fthresh; 1443 | float SIFT_ALIGNED16(flength2); 1444 | _mm_store_ss(&flength2, maccum0); 1445 | fthresh = 0.2f*sqrtf(flength2); 1446 | 1447 | for(int i = 0; i < 128; ++i) { 1448 | if( fdesc[i] > fthresh ) { 1449 | flength2 += fthresh*fthresh-fdesc[i]*fdesc[i]; 1450 | fdesc[i] = fthresh; 1451 | } 1452 | } 1453 | 1454 | // normalizing 1455 | float flength = 1.0f/sqrtf(flength2); 1456 | maccum0 = _mm_load1_ps(&flength); 1457 | for(int i = 0; i < 128; i += 16 ) { 1458 | __m128 m0 = _mm_load_ps(fdesc+i); 1459 | __m128 m1 = _mm_load_ps(fdesc+i+4); 1460 | __m128 m2 = _mm_load_ps(fdesc+i+8); 1461 | __m128 m3 = _mm_load_ps(fdesc+i+12); 1462 | _mm_store_ps(fdesc+i,_mm_mul_ps(m0,maccum0)); 1463 | _mm_store_ps(fdesc+i+4,_mm_mul_ps(m1,maccum0)); 1464 | _mm_store_ps(fdesc+i+8,_mm_mul_ps(m2,maccum0)); 1465 | _mm_store_ps(fdesc+i+12,_mm_mul_ps(m3,maccum0)); 1466 | } 1467 | 1468 | // converting to unsigned char 1469 | // float flength = 512.0f/sqrtf(flength2); 1470 | // maccum0 = _mm_load1_ps(&flength); 1471 | // unsigned char* pkeydesc = pkeypt->descrip; 1472 | // 1473 | // for(int i = 0; i < 128; i += 16 ) { 1474 | // __m128 m0 = _mm_load_ps(fdesc+i); 1475 | // __m128 m1 = _mm_load_ps(fdesc+i+4); 1476 | // __m128 m2 = _mm_load_ps(fdesc+i+8); 1477 | // __m128 m3 = _mm_load_ps(fdesc+i+12); 1478 | // __m128i mi0 = _mm_cvttps_epi32(_mm_mul_ps(m0,maccum0)); 1479 | // __m128i mi1 = _mm_cvttps_epi32(_mm_mul_ps(m1,maccum0)); 1480 | // __m128i mi2 = _mm_cvttps_epi32(_mm_mul_ps(m2,maccum0)); 1481 | // __m128i mi3 = _mm_cvttps_epi32(_mm_mul_ps(m3,maccum0)); 1482 | // _mm_store_si128((__m128i*)(pkeydesc+i), _mm_packus_epi16(_mm_packs_epi32(mi0,mi1),_mm_packs_epi32(mi2,mi3))); 1483 | // } 1484 | #else 1485 | NormalizeVec(fdesc,128); 1486 | 1487 | bool brenormalize = false; 1488 | for(int i = 0; i < 128; ++i) { 1489 | if( fdesc[i] > 0.2f ) { 1490 | fdesc[i] = 0.2f; 1491 | brenormalize = true; 1492 | } 1493 | } 1494 | 1495 | if( brenormalize ) 1496 | NormalizeVec(fdesc,128); 1497 | #endif 1498 | } 1499 | 1500 | void NormalizeVec(float* pf, int num) 1501 | { 1502 | assert( (num&3) == 0 ); 1503 | float faccum = 0; 1504 | for(int i = 0; i < num; ++i) 1505 | faccum += pf[i]*pf[i]; 1506 | faccum = 1/sqrtf(faccum); 1507 | for(int i = 0; i < num; ++i) 1508 | pf[i] *= faccum; 1509 | } 1510 | 1511 | void KeySample(float* fdesc, Keypoint pkeypt, Image imgrad, Image imorient, 1512 | float fSize, float frowstart, float fcolstart) 1513 | { 1514 | int rowstart = (int)(frowstart+0.5f); 1515 | int colstart = (int)(fcolstart+0.5f); 1516 | float sinang = sinf(pkeypt->ori), cosang = cosf(pkeypt->ori); 1517 | float fdrow = frowstart-(float)rowstart; 1518 | float fdcol = fcolstart-(float)colstart; 1519 | float frealsize = 3.0f*fSize; 1520 | float firealsize = 1.0f/(3.0f*fSize); 1521 | int windowsize = (int)(frealsize*SQRT2*5.0f*0.5f+0.5f); 1522 | 1523 | float fsr = sinang*firealsize, fcr = cosang*firealsize, fdrr = -fdrow*firealsize, fdcr = -fdcol*firealsize; 1524 | 1525 | for(int row = -windowsize; row <= windowsize; ++row) { 1526 | //#ifdef _OPENMP 1527 | // float SIFT_ALIGNED16(fnewdesc[128]) = {0}; 1528 | // bool badd = false; 1529 | //#else 1530 | float* fnewdesc = fdesc; 1531 | //#endif 1532 | 1533 | float frow = (float)row; 1534 | float fcol = -(float)windowsize; 1535 | for(int col = -windowsize; col <= windowsize; ++col, fcol += 1) { 1536 | float rpos = fsr*fcol + fcr*frow + fdrr; 1537 | float cpos = fcr*fcol - fsr*frow + fdcr; 1538 | float rx = rpos + (2.0f - 0.5f); 1539 | float cx = cpos + (2.0f - 0.5f); 1540 | 1541 | if( rx > -0.9999f && rx < 3.9999f && cx > -0.9999f && cx < 3.9999f ) { 1542 | AddSample(fnewdesc, pkeypt, imgrad, imorient, rowstart+row, colstart+col, rpos, cpos, rx, cx); 1543 | //#ifdef _OPENMP 1544 | // badd = true; 1545 | //#endif 1546 | } 1547 | } 1548 | 1549 | //#ifdef _OPENMP 1550 | // if( badd ) { 1551 | // #pragma omp critical 1552 | // { 1553 | //#ifdef __SSE__ 1554 | // for(int j = 0; j < 128; j += 16) { 1555 | // _mm_store_ps(&fdesc[j], _mm_add_ps(_mm_load_ps(&fdesc[j]), _mm_load_ps(&fnewdesc[j]))); 1556 | // _mm_store_ps(&fdesc[j+4], _mm_add_ps(_mm_load_ps(&fdesc[j+4]), _mm_load_ps(&fnewdesc[j+4]))); 1557 | // _mm_store_ps(&fdesc[j+8], _mm_add_ps(_mm_load_ps(&fdesc[j+8]), _mm_load_ps(&fnewdesc[j+8]))); 1558 | // _mm_store_ps(&fdesc[j+12], _mm_add_ps(_mm_load_ps(&fdesc[j+12]), _mm_load_ps(&fnewdesc[j+12]))); 1559 | // } 1560 | //#else 1561 | // for(int j = 0; j < 128; ++j) 1562 | // fdesc[j] += fnewdesc[j]; 1563 | //#endif 1564 | // } 1565 | // } 1566 | //#endif 1567 | } 1568 | } 1569 | 1570 | void AddSample(float* fdesc, Keypoint pkeypt, Image imgrad, Image imorient, int r, int c, 1571 | float rpos, float cpos, float rx, float cx) 1572 | { 1573 | int rows = imgrad->rows, cols = imgrad->cols, stride = imgrad->stride; 1574 | if( r < 0 || r >= rows || c < 0 || c >= cols ) 1575 | return; 1576 | 1577 | float fgrad = imgrad->pixels[r*stride+c] * expf(-0.125f*(rpos*rpos+cpos*cpos)); 1578 | float forient = imorient->pixels[r*stride+c] - pkeypt->ori; 1579 | while( forient > 2*PI ) 1580 | forient -= 2*PI; 1581 | while( forient < 0 ) 1582 | forient += 2*PI; 1583 | 1584 | // if( isnan(forient) ) 1585 | // fprintf(stderr,"%f %f (%d,%d,%d,%d)\n", imorient->pixels[r*stride+c],pkeypt->ori,r,c,rows,cols); 1586 | 1587 | PlaceInIndex(fdesc, fgrad, forient, rx, cx); 1588 | } 1589 | 1590 | void PlaceInIndex(float* fdesc, float mag, float ori, float rx, float cx) 1591 | { 1592 | float oribin = ori*(8.0f/(2*(float)PI)); 1593 | int newrow, newcol, neworient; 1594 | float rfrac, cfrac, ofrac; 1595 | if( rx < 0 ) { 1596 | newrow = (int)(rx-1); 1597 | } 1598 | else { 1599 | newrow = (int)rx; 1600 | } 1601 | rfrac = rx-(float)newrow; 1602 | 1603 | if( cx < 0 ) 1604 | newcol = (int)(cx-1); 1605 | else 1606 | newcol = (int)cx; 1607 | cfrac = cx - (float)newcol; 1608 | 1609 | if( oribin < 0 ) 1610 | neworient = (int)(oribin-1); 1611 | else 1612 | neworient = (int)oribin; 1613 | ofrac = oribin-(float)neworient; 1614 | 1615 | assert( newrow >= -1 && newrow < 4 && neworient >= 0 && neworient <= 8 && rfrac >= 0 && rfrac < 1); 1616 | 1617 | for(int i = 0; i < 2; ++i) { 1618 | if( (unsigned int)(i+newrow) >= 4 ) 1619 | continue; 1620 | 1621 | float frowgrad; 1622 | if( i == 0 ) 1623 | frowgrad = mag*(1-rfrac); 1624 | else 1625 | frowgrad = mag*rfrac; 1626 | 1627 | for(int j = 0; j < 2; ++j) { 1628 | if( (unsigned int)(j+newcol) >= 4 ) 1629 | continue; 1630 | 1631 | float fcolgrad; 1632 | if( j == 0 ) 1633 | fcolgrad = frowgrad*(1-cfrac); 1634 | else 1635 | fcolgrad = frowgrad*cfrac; 1636 | 1637 | float* pfdescorient = fdesc + 8*(4*(i+newrow)+j+newcol); 1638 | for(int k = 0; k < 2; ++k) { 1639 | float forigrad; 1640 | if( k == 0 ) 1641 | forigrad = fcolgrad*(1-ofrac); 1642 | else 1643 | forigrad = fcolgrad*ofrac; 1644 | 1645 | pfdescorient[(neworient+k)&7] += forigrad; 1646 | } 1647 | } 1648 | } 1649 | } 1650 | 1651 | void FreeKeypoints(Keypoint keypt) 1652 | { 1653 | while(keypt != NULL) { 1654 | s_listKeypoints.push_back(keypt); 1655 | keypt = keypt->next; 1656 | } 1657 | } 1658 | 1659 | void DestroyAllResources() 1660 | { 1661 | DestroyAllImages(); 1662 | for( map::iterator it = s_mapkernel.begin(); it != s_mapkernel.end(); ++it) 1663 | sift_aligned_free(it->second-1); 1664 | s_mapkernel.clear(); 1665 | #ifdef __SSE__ 1666 | for(LISTBUF::iterator it = s_listconvbuf.begin(); it != s_listconvbuf.end(); ++it) 1667 | sift_aligned_free(*it); 1668 | s_listconvbuf.clear(); 1669 | s_convbufsize = 0; 1670 | #endif 1671 | for(list::iterator it = s_listKeypoints.begin(); it != s_listKeypoints.end(); ++it) 1672 | sift_aligned_free(*it); 1673 | s_listKeypoints.clear(); 1674 | } 1675 | 1676 | /* 1677 | #if !defined(_MSC_VER) && defined(__SSE__) && !defined(SIMDMATH_H) // copied from libsimdmath 1678 | 1679 | #define DEF_CONST(a,b) static const vec_float4 a = {b,b,b,b}; 1680 | #define DEI_CONST(a,b) static const vec_int4 a = {b,b,b,b}; 1681 | 1682 | 1683 | DEF_CONST(CF4_2414213562373095, 2.414213562373095f) 1684 | DEF_CONST(CF4_04142135623730950, 0.4142135623730950f) 1685 | DEF_CONST(CF4_805374449538e_2, 8.05374449538e-2f) 1686 | DEF_CONST(CF4_138776856032E_1, 1.38776856032E-1f) 1687 | DEF_CONST(CF4_199777106478E_1, 1.99777106478E-1f) 1688 | DEF_CONST(CF4_333329491539E_1, 3.33329491539E-1f) 1689 | 1690 | #define VEC_F2I(a,b) asm("cvttps2dq %1, %0":"=x" (a) :"x" (b)) 1691 | #define VEC_I2F(a,b) asm("cvtdq2ps %1, %0":"=x" (a) :"x" (b)) 1692 | */ 1693 | /* definitions for a &= b; etc 1694 | gcc generates very slow code for corresponding 1695 | vec_float4 C-style expressions 1696 | */ 1697 | /* 1698 | #define VEC_AND(a,b) asm ("andps %2, %1":"=x" (a) :"0" (a),"x" (b)) 1699 | #define VEC_NAND(a,b) asm ("andnps %2, %1":"=x" (a) :"0" (a),"x" (b)) 1700 | #define VEC_NAND3(a,b,c) a=(typeof(a))_mm_andnot_ps((vec_float4)(c),(vec_float4)(b)) 1701 | #define VEC_OR(a,b) asm ("orps %2, %1":"=x" (a) :"0" (a),"x" (b)) 1702 | #define VEC_XOR(a,b) asm ("xorps %2, %1":"=x" (a) :"0" (a),"x" (b)) 1703 | #define VEC_SUB(a,b) asm ("subps %2, %1":"=x" (a) :"0" (a),"x" (b)) 1704 | 1705 | #define VEC_GT(a,b) __builtin_ia32_cmpgtps((vec_float4)a,(vec_float4)b) 1706 | #define VEC_LT(a,b) __builtin_ia32_cmpltps(a,b) 1707 | #define VEC_EQ(a,b) __builtin_ia32_cmpeqps(a,b) 1708 | #define VEC_NE(a,b) __builtin_ia32_cmpneqps(a,b) 1709 | #define VEC_GE(a,b) __builtin_ia32_cmpgeps(a,b) 1710 | #define VEC_SR(v,n) _mm_srli_epi32(v,n) 1711 | #define VEC_SL(v,n) _mm_slli_epi32(v,n) 1712 | 1713 | 1714 | #define vec_re(x) _mm_rcp_ps(x) 1715 | #define vec_sr(x,y) _mm_srli_epi32(x,y) 1716 | #define vec_sl(x,y) _mm_slli_epi32(x,y) 1717 | #define vec_or(a,b) ((a)|(b)) 1718 | #define vec_and(a,b) ((a)&(b)) 1719 | #define vec_add(a,b) ((a)+(b)) 1720 | #define vec_madd(a,b,c) ((a)*(b)+(c)) 1721 | #define vec_nmsub(a,b,c) ((c)-(a)*(b)) 1722 | #define vec_splat(x,n) (typeof(x))_mm_shuffle_ps(x,x,_MM_SHUFFLE(n,n,n,n)) 1723 | 1724 | DEF_CONST(CF4_0, 0.0f) 1725 | DEF_CONST(CF4_2, 2.0f) 1726 | DEI_CONST(CI4_SIGN, 0x80000000u) 1727 | DEF_CONST(CF4__1, -1.0f) 1728 | DEF_CONST(CF4_1, 1.0f) 1729 | DEF_CONST(CF4_SMALL, 1.0E-35f) 1730 | DEF_CONST(CF4_PIO2F, 1.570796326794896619f) 1731 | DEF_CONST(CF4_PIO4F, 0.7853981633974483096f) 1732 | DEF_CONST(CF4_PIF, 3.14159265358979323846f) 1733 | 1734 | inline vec_int4 __attribute__((__always_inline__)) 1735 | _signf4( vec_float4 x ){ 1736 | vec_int4 a = CI4_SIGN; 1737 | VEC_AND(a, x); 1738 | return a; 1739 | } 1740 | 1741 | inline vec_float4 __attribute__((__always_inline__)) 1742 | _atanf4( vec_float4 x ){ 1743 | vec_float4 y, z,z1,z2; 1744 | vec_int4 a1, a2, a3; 1745 | 1746 | vec_int4 sign = _signf4( x ); 1747 | VEC_XOR(x, sign); 1748 | 1749 | a1 = (vec_int4)VEC_GT (x , CF4_2414213562373095 ); 1750 | a2 = (vec_int4)VEC_GT (x , CF4_04142135623730950 ); 1751 | a3 = ~a2; 1752 | a2 ^= a1; 1753 | 1754 | z1 = CF4__1 / (x+CF4_SMALL); 1755 | z2 = (x-CF4_1)/(x+CF4_1); 1756 | VEC_AND(z1, a1); 1757 | VEC_AND(z2, a2); 1758 | VEC_AND(x, a3); 1759 | VEC_OR(x, z1); 1760 | VEC_OR(x, z2); 1761 | 1762 | y = CF4_PIO2F; 1763 | z1 = CF4_PIO4F; 1764 | VEC_AND(y, a1); 1765 | VEC_AND(z1, a2); 1766 | VEC_OR(y, z1); 1767 | 1768 | z = x * x; 1769 | y += 1770 | ((( CF4_805374449538e_2 * z 1771 | - CF4_138776856032E_1) * z 1772 | + CF4_199777106478E_1) * z 1773 | - CF4_333329491539E_1) * z * x 1774 | + x; 1775 | 1776 | VEC_XOR(y, sign); 1777 | return y; 1778 | } 1779 | 1780 | inline vec_float4 __attribute__((__always_inline__)) 1781 | atan2f4( vec_float4 y, vec_float4 x ){ 1782 | vec_float4 z, w; 1783 | vec_float4 x_neg_PI = CF4_PIF; 1784 | VEC_AND(x_neg_PI, VEC_GT( CF4_0, x )); 1785 | vec_float4 y_negativ_2 = CF4_2; 1786 | VEC_AND(y_negativ_2, VEC_GT( CF4_0, y )); 1787 | 1788 | vec_int4 i_x_zero = (vec_int4)VEC_EQ ( CF4_0, x ); 1789 | vec_int4 i_y_zero = (vec_int4)VEC_EQ ( CF4_0, y ); 1790 | vec_float4 x_zero_PIO2 = CF4_PIO2F; 1791 | VEC_AND(x_zero_PIO2, i_x_zero); 1792 | vec_float4 y_zero = CF4_1; 1793 | VEC_AND(y_zero, i_y_zero); 1794 | 1795 | 1796 | w = x_neg_PI * ( CF4_1 - y_negativ_2 ); 1797 | 1798 | z = _atanf4( y / (x+x_zero_PIO2)); 1799 | VEC_AND(z, ~(i_x_zero|i_y_zero)); 1800 | 1801 | return w + z + x_zero_PIO2 * ( CF4_1 - y_zero - y_negativ_2 ); 1802 | } 1803 | 1804 | #endif 1805 | */ 1806 | -------------------------------------------------------------------------------- /makerelease.sh: -------------------------------------------------------------------------------- 1 | version=1.2 2 | rm -rf libsiftfast-$version libsiftfast-$version-src 3 | make prefix=`pwd`/libsiftfast-$version 4 | make install 5 | cp README LICENSE libsiftfast-$version/ 6 | tar czf libsiftfast-$version-linux-i386.tgz libsiftfast-$version 7 | svn export . libsiftfast-$version-src/ 8 | tar czf libsiftfast-$version-src.tgz libsiftfast-$version-src 9 | rm -rf libsiftfast-$version libsiftfast-$version-src 10 | -------------------------------------------------------------------------------- /profiler.cpp: -------------------------------------------------------------------------------- 1 | // exact C++ implementation of lowe's sift program 2 | // author: zerofrog(@gmail.com), Sep 2008 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //Lesser GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU Lesser General Public License 15 | //along with this program. If not, see . 16 | 17 | // This source code was carefully calibrated to match David Lowe's SIFT features program 18 | #include "profiler.h" 19 | 20 | //////////////////// 21 | // Small profiler // 22 | //////////////////// 23 | #include 24 | #include 25 | #include 26 | #include // ftime(), struct timeb 27 | #include 28 | 29 | using namespace std; 30 | 31 | int g_bWriteProfile=1; 32 | 33 | static u64 luPerfFreq = 1000000; 34 | inline u64 GET_PROFILE_TIME() 35 | { 36 | struct timeval t; 37 | gettimeofday(&t, NULL); 38 | return (u64)t.tv_sec*1000000+t.tv_usec; 39 | } 40 | 41 | 42 | struct DVPROFSTRUCT; 43 | 44 | struct DVPROFSTRUCT 45 | { 46 | struct DATA 47 | { 48 | DATA(u64 time, u32 user = 0) : dwTime(time), dwUserData(user) {} 49 | DATA() : dwTime(0), dwUserData(0) {} 50 | 51 | u64 dwTime; 52 | u32 dwUserData; 53 | }; 54 | 55 | ~DVPROFSTRUCT() { 56 | list::iterator it = listpChild.begin(); 57 | while(it != listpChild.end() ) { 58 | delete *it; *it = NULL; 59 | ++it; 60 | } 61 | } 62 | 63 | list listTimes; // before DVProfEnd is called, contains the global time it started 64 | // after DVProfEnd is called, contains the time it lasted 65 | // the list contains all the tracked times 66 | char pname[256]; 67 | 68 | list listpChild; // other profilers called during this profiler period 69 | }; 70 | 71 | struct DVPROFTRACK 72 | { 73 | u32 dwUserData; 74 | DVPROFSTRUCT::DATA* pdwTime; 75 | DVPROFSTRUCT* pprof; 76 | }; 77 | 78 | list g_listCurTracking; // the current profiling functions, the back element is the 79 | // one that will first get popped off the list when DVProfEnd is called 80 | // the pointer is an element in DVPROFSTRUCT::listTimes 81 | list g_listProfilers; // the current profilers, note that these are the parents 82 | // any profiler started during the time of another is held in 83 | // DVPROFSTRUCT::listpChild 84 | list g_listAllProfilers; // ignores the hierarchy, pointer to elements in g_listProfilers 85 | 86 | void DVProfRegister(const char* pname) 87 | { 88 | if( !g_bWriteProfile ) 89 | return; 90 | list::iterator it = g_listAllProfilers.begin(); 91 | 92 | // while(it != g_listAllProfilers.end() ) { 93 | // 94 | // if( _tcscmp(pname, (*it)->pname) == 0 ) { 95 | // (*it)->listTimes.push_back(timeGetTime()); 96 | // DVPROFTRACK dvtrack; 97 | // dvtrack.pdwTime = &(*it)->listTimes.back(); 98 | // dvtrack.pprof = *it; 99 | // g_listCurTracking.push_back(dvtrack); 100 | // return; 101 | // } 102 | // 103 | // ++it; 104 | // } 105 | 106 | // else add in a new profiler to the appropriate parent profiler 107 | DVPROFSTRUCT* pprof = NULL; 108 | 109 | if( g_listCurTracking.size() > 0 ) { 110 | assert( g_listCurTracking.back().pprof != NULL ); 111 | g_listCurTracking.back().pprof->listpChild.push_back(new DVPROFSTRUCT()); 112 | pprof = g_listCurTracking.back().pprof->listpChild.back(); 113 | } 114 | else { 115 | g_listProfilers.push_back(DVPROFSTRUCT()); 116 | pprof = &g_listProfilers.back(); 117 | } 118 | 119 | strncpy(pprof->pname, pname, 256); 120 | 121 | // setup the profiler for tracking 122 | pprof->listTimes.push_back(DVPROFSTRUCT::DATA(GET_PROFILE_TIME())); 123 | 124 | DVPROFTRACK dvtrack; 125 | dvtrack.pdwTime = &pprof->listTimes.back(); 126 | dvtrack.pprof = pprof; 127 | dvtrack.dwUserData = 0; 128 | 129 | g_listCurTracking.push_back(dvtrack); 130 | 131 | // add to all profiler list 132 | g_listAllProfilers.push_back(pprof); 133 | } 134 | 135 | void DVProfEnd(u32 dwUserData) 136 | { 137 | if( !g_bWriteProfile ) 138 | return; 139 | if( g_listCurTracking.size() == 0 ) 140 | return; 141 | 142 | DVPROFTRACK dvtrack = g_listCurTracking.back(); 143 | 144 | assert( dvtrack.pdwTime != NULL && dvtrack.pprof != NULL ); 145 | 146 | dvtrack.pdwTime->dwTime = GET_PROFILE_TIME()- dvtrack.pdwTime->dwTime; 147 | dvtrack.pdwTime->dwUserData= dwUserData; 148 | 149 | g_listCurTracking.pop_back(); 150 | } 151 | 152 | struct DVTIMEINFO 153 | { 154 | DVTIMEINFO() : uInclusive(0), uExclusive(0) {} 155 | u64 uInclusive, uExclusive; 156 | }; 157 | 158 | map mapAggregateTimes; 159 | 160 | u64 DVProfWriteStruct(FILE* f, DVPROFSTRUCT* p, int ident) 161 | { 162 | fprintf(f, "%*s%s - ", ident, "", p->pname); 163 | 164 | list::iterator ittime = p->listTimes.begin(); 165 | 166 | u64 utime = 0; 167 | 168 | while(ittime != p->listTimes.end() ) { 169 | // if( ittime->dwTime > luPerfFreq*10 ) { 170 | // ++ittime; 171 | // continue; 172 | // } 173 | 174 | utime += ittime->dwTime; 175 | 176 | if( ittime->dwUserData ) 177 | fprintf(f, "time: %d, user: 0x%8.8x", (u32)ittime->dwTime, ittime->dwUserData); 178 | else 179 | fprintf(f, "time: %d", (u32)ittime->dwTime); 180 | ++ittime; 181 | } 182 | 183 | // yes this is necessary, maps have problems with constructors on their type 184 | map::iterator ittimes = mapAggregateTimes.find(p->pname); 185 | if( ittimes == mapAggregateTimes.end() ) { 186 | ittimes = mapAggregateTimes.insert(map::value_type(p->pname, DVTIMEINFO())).first; 187 | ittimes->second.uExclusive = 0; 188 | ittimes->second.uInclusive = 0; 189 | } 190 | 191 | ittimes->second.uInclusive += utime; 192 | 193 | fprintf(f, "\n"); 194 | 195 | list::iterator itprof = p->listpChild.begin(); 196 | 197 | u64 uex = utime; 198 | while(itprof != p->listpChild.end() ) { 199 | uex -= DVProfWriteStruct(f, *itprof, ident+4); 200 | ++itprof; 201 | } 202 | 203 | if( uex > utime ) { 204 | uex = 0; 205 | //RAVEPRINT(L"profiling precision error!\n"); 206 | } 207 | 208 | ittimes->second.uExclusive += uex; 209 | return utime; 210 | } 211 | 212 | void DVProfWrite(const char* pfilename, u32 frames) 213 | { 214 | assert( pfilename != NULL ); 215 | FILE* f = fopen(pfilename, "w"); 216 | 217 | // pop back any unused 218 | mapAggregateTimes.clear(); 219 | list::iterator it = g_listProfilers.begin(); 220 | 221 | while(it != g_listProfilers.end() ) { 222 | DVProfWriteStruct(f, &(*it), 0); 223 | ++it; 224 | } 225 | 226 | { 227 | map::iterator it; 228 | fprintf(f, "\n\n--------------------------------------------------------------\n\n"); 229 | 230 | u64 uTotal[2]; uTotal[0] = uTotal[1] = 0; 231 | double fiTotalTime[2]; fiTotalTime[0] = fiTotalTime[1] = 0; 232 | 233 | for(it = mapAggregateTimes.begin(); it != mapAggregateTimes.end(); ++it) { 234 | uTotal[0] += it->second.uExclusive; 235 | uTotal[1] += it->second.uInclusive; 236 | } 237 | 238 | fprintf(f, "total times (%d): ex: %Lu ", frames, 1000000*uTotal[0]/(luPerfFreq*(u64)frames)); 239 | fprintf(f, "inc: %Lu\n", 1000000 * uTotal[1]/(luPerfFreq*(u64)frames)); 240 | 241 | if( uTotal[0] > 0 ) 242 | fiTotalTime[0] = 1.0 / (double)uTotal[0]; 243 | if( uTotal[1] > 0 ) 244 | fiTotalTime[1] = 1.0 / (double)uTotal[1]; 245 | 246 | // output the combined times 247 | for(it = mapAggregateTimes.begin(); it != mapAggregateTimes.end(); ++it) { 248 | fprintf(f, "%s - ex: %f%% (%fs) inc: %f%%\n", it->first.c_str(), 249 | 100.0f*(float)((double)it->second.uExclusive * fiTotalTime[0]), 250 | (double)it->second.uExclusive/(double)luPerfFreq, 251 | 100.0f*(float)((double)it->second.uInclusive * fiTotalTime[1])); 252 | } 253 | } 254 | 255 | 256 | fclose(f); 257 | } 258 | 259 | void DVProfClear() 260 | { 261 | g_listCurTracking.clear(); 262 | g_listProfilers.clear(); 263 | g_listAllProfilers.clear(); 264 | } 265 | -------------------------------------------------------------------------------- /profiler.h: -------------------------------------------------------------------------------- 1 | // exact C++ implementation of lowe's sift program 2 | // author: zerofrog(@gmail.com), Sep 2008 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //Lesser GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU Lesser General Public License 15 | //along with this program. If not, see . 16 | 17 | // This source code was carefully calibrated to match David Lowe's SIFT features program 18 | #ifndef SMALL_PROFILER_H 19 | #define SMALL_PROFILER_H 20 | 21 | typedef unsigned int u32; 22 | typedef unsigned long long u64; 23 | typedef signed long long s64; 24 | 25 | #include 26 | 27 | //// 28 | // profiling 29 | /// 30 | 31 | extern int g_bWriteProfile; // global variable to enable/disable profiling (if DVPROFILE is defined) 32 | 33 | // IMPORTANT: For every Reigster there must be an End 34 | void DVProfRegister(const char* pname); // first checks if this profiler exists in g_listProfilers 35 | void DVProfEnd(u32 dwUserData); 36 | void DVProfWrite(const char* pfilename, u32 frames = 1); 37 | void DVProfClear(); // clears all the profilers 38 | 39 | #if defined(DVPROFILE) 40 | 41 | #ifdef _MSC_VER 42 | 43 | #ifndef __PRETTY_FUNCTION__ 44 | #define __PRETTY_FUNCTION__ __FUNCTION__ 45 | #endif 46 | 47 | #endif 48 | 49 | #define DVSTARTPROFILE() DVProfileFunc _pf(__FUNCTION__); 50 | 51 | class DVProfileFunc 52 | { 53 | public: 54 | u32 dwUserData; 55 | DVProfileFunc(const char* pname) { DVProfRegister(pname); dwUserData = 0; } 56 | DVProfileFunc(const char* pname, u32 dwUserData) : dwUserData(dwUserData) { DVProfRegister(pname); } 57 | ~DVProfileFunc() { DVProfEnd(dwUserData); } 58 | }; 59 | 60 | #else 61 | 62 | #define DVSTARTPROFILE() 63 | 64 | class DVProfileFunc 65 | { 66 | public: 67 | u32 dwUserData; 68 | inline DVProfileFunc(const char* pname) {} 69 | inline DVProfileFunc(const char* pname, u32 dwUserData) { } 70 | ~DVProfileFunc() {} 71 | }; 72 | 73 | #endif 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /runcmake.bat: -------------------------------------------------------------------------------- 1 | mkdir build 2 | cd build 3 | cmake .. 4 | -------------------------------------------------------------------------------- /siftfast.cpp: -------------------------------------------------------------------------------- 1 | // exact C++ implementation of lowe's sift program 2 | // Copyright (C) zerofrog(@gmail.com), 2008-2009 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //Lesser GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU Lesser General Public License 15 | //along with this program. If not, see . 16 | 17 | // This source code was carefully calibrated to match David Lowe's SIFT features program 18 | #include "siftfast.h" 19 | 20 | #include 21 | 22 | #include // ftime(), struct timeb 23 | 24 | #ifdef _WIN32 25 | #include 26 | #include 27 | #endif 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | using namespace std; 34 | 35 | typedef unsigned short u16; 36 | typedef unsigned int u32; 37 | typedef unsigned long long u64; 38 | 39 | inline u32 timeGetTime() 40 | { 41 | #ifdef _WIN32 42 | _timeb t; 43 | _ftime(&t); 44 | #else 45 | timeb t; 46 | ftime(&t); 47 | #endif 48 | 49 | return (u32)(t.time*1000+t.millitm); 50 | } 51 | 52 | // code from david lowe 53 | void SkipComments(FILE *fp) 54 | { 55 | int ch; 56 | 57 | fscanf(fp," "); // Skip white space. 58 | while ((ch = fgetc(fp)) == '#') { 59 | while ((ch = fgetc(fp)) != '\n' && ch != EOF) 60 | ; 61 | fscanf(fp," "); 62 | } 63 | ungetc(ch, fp); // Replace last character read. 64 | } 65 | 66 | // code from david lowe 67 | Image ReadPGM(FILE *fp) 68 | { 69 | int char1, char2, width, height, max, c1, c2, c3, r, c; 70 | Image image, nextimage; 71 | 72 | char1 = fgetc(fp); 73 | char2 = fgetc(fp); 74 | SkipComments(fp); 75 | c1 = fscanf(fp, "%d", &width); 76 | SkipComments(fp); 77 | c2 = fscanf(fp, "%d", &height); 78 | SkipComments(fp); 79 | c3 = fscanf(fp, "%d", &max); 80 | 81 | if (char1 != 'P' || char2 != '5' || c1 != 1 || c2 != 1 || c3 != 1 || max > 255) { 82 | cerr << "Input is not a standard raw 8-bit PGM file." << endl 83 | << "Use xv or pnmdepth to convert file to 8-bit PGM format." << endl; 84 | exit(1); 85 | } 86 | 87 | fgetc(fp); // Discard exactly one byte after header. 88 | 89 | // Create floating point image with pixels in range [0,1]. 90 | image = CreateImage(height, width); 91 | for (r = 0; r < height; r++) 92 | for (c = 0; c < width; c++) 93 | image->pixels[r*image->stride+c] = ((float) fgetc(fp)) / 255.0; 94 | 95 | //Check if there is another image in this file, as the latest PGM 96 | // standard allows for multiple images. 97 | SkipComments(fp); 98 | if (getc(fp) == 'P') { 99 | cerr << "ignoring other images" << endl; 100 | ungetc('P', fp); 101 | nextimage = ReadPGM(fp); 102 | //image->next = nextimage; 103 | } 104 | return image; 105 | } 106 | 107 | int main(int argc, char **argv) 108 | { 109 | #ifdef _WIN32 110 | // have to set to binary 111 | _setmode(_fileno(stdin),_O_BINARY); 112 | #endif 113 | 114 | Image image = ReadPGM(stdin); 115 | Keypoint keypts; 116 | float fproctime; 117 | 118 | cerr << "Finding keypoints (image " << image->cols << "x" << image->rows << ")..." << endl; 119 | { 120 | u32 basetime = timeGetTime(); 121 | keypts = GetKeypoints(image); 122 | fproctime = (timeGetTime()-basetime)*0.001f; 123 | } 124 | 125 | // write the keys to the output 126 | int numkeys = 0; 127 | Keypoint key = keypts; 128 | while(key) { 129 | numkeys++; 130 | key = key->next; 131 | } 132 | 133 | cerr << numkeys << " keypoints found in " << fproctime << " seconds." << endl; 134 | 135 | cout << numkeys << " " << 128 << endl; 136 | key = keypts; 137 | while(key) { 138 | cout << key->row << " " << key->col << " " << key->scale << " " << key->ori << endl; 139 | 140 | for(int i = 0; i < 128; ++i) { 141 | int intdesc = (int)(key->descrip[i]*512.0f); 142 | assert( intdesc >= 0 ); 143 | 144 | if( intdesc > 255 ) 145 | intdesc = 255; 146 | cout << intdesc << " "; 147 | if( (i&15)==15 ) 148 | cout << endl; 149 | } 150 | cout << endl; 151 | key = key->next; 152 | } 153 | 154 | FreeKeypoints(keypts); 155 | DestroyAllResources(); 156 | 157 | return 0; 158 | } 159 | -------------------------------------------------------------------------------- /siftfast.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) zerofrog(@gmail.com), 2008-2009 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Lesser General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // at your option) any later version. 7 | // 8 | //This program is distributed in the hope that it will be useful, 9 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | //Lesser GNU General Public License for more details. 12 | // 13 | //You should have received a copy of the GNU Lesser General Public License 14 | //along with this program. If not, see . 15 | #ifndef SIFT_FAST_H 16 | #define SIFT_FAST_H 17 | 18 | typedef struct ImageSt { 19 | int rows, cols; // Dimensions of image. 20 | float *pixels; // 2D array of image pixels. 21 | int stride; // how many floats until the next row 22 | // (used to add padding to make rows aligned to 16 bytes) 23 | } *Image; 24 | 25 | typedef struct KeypointSt { 26 | float row, col; // Subpixel location of keypoint. 27 | float scale, ori; // Scale and orientation (range [-PI,PI]) 28 | float descrip[128]; // Vector of descriptor values 29 | struct KeypointSt *next; // Pointer to next keypoint in list. 30 | } *Keypoint; 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | Keypoint GetKeypoints(Image porgimage); 37 | Image CreateImage(int rows, int cols); 38 | Image CreateImageFromMatlabData(double* pdata, int rows, int cols); 39 | void DestroyAllImages(); 40 | void DestroyAllResources(); 41 | void FreeKeypoints(Keypoint keypt); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /siftfast.m: -------------------------------------------------------------------------------- 1 | % [frames, descriptors] = siftfast(I) 2 | % 3 | % Returns the sift feature of a grayscale image 4 | % I - grayscale in real format, all values have to be in [0,1] 5 | % frames - 4xN matrix of the sift locations each column is (X,Y,Scale,Orientation) 6 | % descriptors - KxN matrix (usually K=128) of the sift descriptors 7 | function [frames, descriptors] = siftfast(I) 8 | -------------------------------------------------------------------------------- /siftfastpy.cpp: -------------------------------------------------------------------------------- 1 | // exact C++ implementation of lowe's sift program 2 | // Copyright (C) zerofrog(@gmail.com), 2008-2009 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //Lesser GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU Lesser General Public License 15 | //along with this program. If not, see . 16 | #define BOOST_ENABLE_ASSERT_HANDLER 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "siftfast.h" 32 | 33 | #include 34 | #define PY_ARRAY_UNIQUE_SYMBOL PyArrayHandle 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | 43 | 44 | #define CHECK_POINTER(p) { \ 45 | if( (p) == NULL ) throw siftfast_exception("invalid pointer"); \ 46 | } 47 | 48 | using namespace boost::python; 49 | using namespace std; 50 | 51 | extern int DoubleImSize; 52 | extern int Scales; 53 | extern float InitSigma; 54 | extern float PeakThresh; 55 | 56 | struct siftfast_exception : std::exception { 57 | 58 | siftfast_exception() : std::exception(), _s("unknown exception") {} 59 | siftfast_exception(const string& s) : std::exception() { _s = "siftfast: " + s; } 60 | 61 | virtual ~siftfast_exception() throw() {} 62 | char const* what() const throw() { return _s.c_str(); } 63 | 64 | string _s; 65 | 66 | }; 67 | 68 | #if defined(BOOST_ENABLE_ASSERT_HANDLER) 69 | namespace boost { 70 | inline void assertion_failed( 71 | char const * expr, 72 | char const * function, 73 | char const * file, long line) { 74 | throw siftfast_exception(str(boost::format("[%s:%d] -> %s, expr: %s")%file%line%function%expr)); 75 | } 76 | } 77 | #endif 78 | 79 | void translate_siftfast_exception(siftfast_exception const& e) { 80 | // Use the Python 'C' API to set up an exception object 81 | PyErr_SetString(PyExc_RuntimeError, e.what()); 82 | } 83 | 84 | inline object toPyArrayN(const float* pvalues, int N) { 85 | npy_intp dims[] = {N}; 86 | PyObject *pyvalues = PyArray_SimpleNew(1,dims, PyArray_FLOAT); 87 | if( pvalues != NULL ) { 88 | memcpy(PyArray_DATA(pyvalues), 89 | pvalues, N*sizeof(float)); 90 | } 91 | return static_cast(handle<>(pyvalues)); 92 | } 93 | 94 | template 95 | inline vector ExtractArray(object o) 96 | { 97 | vector v(len(o)); 98 | for(size_t i = 0; i < v.size(); ++i) 99 | v[i] = extract(o[i]); 100 | return v; 101 | } 102 | 103 | inline vector ExtractFloatArray(object oraw) { 104 | 105 | object o = oraw.attr("flat"); 106 | 107 | // check the types of o 108 | extract xr(o[0]); 109 | if (xr.check()) 110 | return ExtractArray(o); 111 | 112 | vector v(len(o)); 113 | object onew = ((numeric::array)oraw).astype("f8").attr("flat"); 114 | for(size_t i = 0; i < v.size(); ++i) 115 | v[i] = (float)(extract(onew[i])); 116 | 117 | return v; 118 | } 119 | 120 | /// a few forward declares. 121 | class SiftFastImage { 122 | public: 123 | SiftFastImage(int width, int height) : width(width), height(height) { 124 | BOOST_ASSERT(width>0&&height>0); 125 | stride = (width+3)&~3; 126 | vimage.resize(height*stride); 127 | } 128 | 129 | SiftFastImage(object oimage) { 130 | object shape = oimage.attr("shape"); 131 | BOOST_ASSERT(len(shape)==2); 132 | 133 | width = extract(shape[1]); 134 | height = extract(shape[0]); 135 | stride = (width+3)&~3; 136 | vimage.resize(height*stride); 137 | 138 | SetData(oimage); 139 | } 140 | 141 | SiftFastImage() {} 142 | 143 | virtual void SetData(object arr) { 144 | object shape = arr.attr("shape"); 145 | if (len(shape) != 2) 146 | throw siftfast_exception("array needs 2 dimensions"); 147 | if (height != extract(shape[0])) 148 | throw siftfast_exception("array rows do not match height"); 149 | if (width != extract(shape[1])) 150 | throw siftfast_exception("array columns do not match width"); 151 | 152 | string dtype = extract(arr.attr("dtype").attr("name")); 153 | 154 | if ((dtype.size() >= 3 && dtype[0] == 'i' && dtype[1] == 'n' && dtype[2] == 't') || 155 | (dtype.size() >= 4 && dtype[1] == 'i' && dtype[2] == 'n' && dtype[3] == 't')) { 156 | 157 | extract xi(arr[0][0]); 158 | if (xi.check()) { 159 | for (int i = 0; i < height; ++i) 160 | for (int j = 0; j < width; ++j) 161 | vimage[i*stride+j] = extract(arr[i][j]) * (1.0f / 255.0f); 162 | return; 163 | } 164 | } 165 | 166 | extract xr(arr[0][0]); 167 | if (xr.check()) { 168 | for (int i = 0; i < height; ++i) 169 | for (int j = 0; j < width; ++j) 170 | vimage[i*stride+j] = extract(arr[i][j]); 171 | return; 172 | } 173 | 174 | extract xd(arr[0][0]); 175 | if (xd.check()) { 176 | for (int i = 0; i < height; ++i) 177 | for (int j = 0; j < width; ++j) 178 | vimage[i*stride+j] = extract(arr[i][j]); 179 | return; 180 | } 181 | 182 | throw siftfast_exception("array not in correct format"); 183 | } 184 | 185 | public: 186 | int width, height, stride; 187 | vector vimage; 188 | }; 189 | 190 | 191 | class PyImage : public SiftFastImage { 192 | public: 193 | PyImage(int width, int height) : SiftFastImage(width, height) {} 194 | PyImage(object oimage) : SiftFastImage(oimage) {} 195 | const PyImage() {} 196 | 197 | object Keypoints(SiftFastImage* im = NULL) { 198 | if (im == NULL) { im = (SiftFastImage*)this; } 199 | 200 | struct ImageSt siftimage; 201 | siftimage.rows = im->height; 202 | siftimage.cols = im->width; 203 | siftimage.pixels = &im->vimage[0]; 204 | siftimage.stride = im->stride; 205 | 206 | Keypoint keypts = GetKeypoints(&siftimage); 207 | 208 | int numkeys = 0; 209 | Keypoint key = keypts; 210 | while(key) { 211 | numkeys++; 212 | key = key->next; 213 | } 214 | 215 | npy_intp dims[2] = {numkeys, 4}; 216 | PyObject *pyframes = PyArray_SimpleNew(2, dims, PyArray_FLOAT); 217 | float* pframes = (float*)PyArray_DATA(pyframes); 218 | 219 | dims[1] = 128; 220 | PyObject *pydesc = PyArray_SimpleNew(2, dims, PyArray_FLOAT); 221 | float* pdesc = (float*)PyArray_DATA(pydesc); 222 | 223 | int index = 0; 224 | key = keypts; 225 | 226 | while(key) { 227 | for(int j = 0; j < 128; ++j) 228 | pdesc[128*index+j] = key->descrip[j]; 229 | 230 | pframes[4*index+0] = key->col; 231 | pframes[4*index+1] = key->row; 232 | pframes[4*index+2] = key->ori; 233 | pframes[4*index+3] = key->scale; 234 | 235 | key = key->next; 236 | ++index; 237 | } 238 | 239 | FreeKeypoints(keypts); 240 | DestroyAllImages(); 241 | 242 | return make_tuple( 243 | static_cast(handle<>(pyframes)), 244 | static_cast(handle<>(pydesc))); 245 | } 246 | }; 247 | 248 | object PyGetKeypoints(SiftFastImage& im) { 249 | return PyImage().Keypoints(&im); 250 | } 251 | object PyGetKeypoints(numeric::array oarray) { 252 | SiftFastImage pimage(oarray); 253 | return PyGetKeypoints(pimage); 254 | } 255 | 256 | 257 | class Image_pickle_suite : public pickle_suite { 258 | public: 259 | static tuple getinitargs(const PyImage& im) { 260 | return make_tuple( 261 | im.width, im.height, im.stride, 262 | toPyArrayN( 263 | &im.vimage[0], 264 | im.vimage.size())); 265 | } 266 | }; 267 | 268 | struct DummyStruct {}; 269 | 270 | struct int_from_int { 271 | int_from_int() { 272 | converter::registry::push_back(&convertible, &construct, type_id()); 273 | } 274 | 275 | static void* convertible(PyObject* obj) { 276 | PyObject* newobj = PyNumber_Int(obj); 277 | 278 | if (!PyString_Check(obj) && newobj) { 279 | Py_DECREF(newobj); 280 | return obj; 281 | 282 | } else { 283 | if (newobj) { Py_DECREF(newobj); } 284 | PyErr_Clear(); 285 | return 0; 286 | } 287 | } 288 | 289 | static void construct(PyObject* _obj, 290 | converter::rvalue_from_python_stage1_data* data) { 291 | 292 | PyObject* newobj = PyNumber_Int(_obj); 293 | int* storage = (int*)((converter::rvalue_from_python_storage*)data)->storage.bytes; 294 | 295 | *storage = extract(newobj); 296 | Py_DECREF(newobj); 297 | data->convertible = storage; 298 | } 299 | }; 300 | 301 | template 302 | struct T_from_number { 303 | T_from_number() { 304 | converter::registry::push_back(&convertible, &construct, type_id()); 305 | } 306 | 307 | static void* convertible( PyObject* obj) { 308 | PyObject* newobj = PyNumber_Float(obj); 309 | if (!PyString_Check(obj) && newobj) { 310 | Py_DECREF(newobj); 311 | return obj; 312 | } else { 313 | if (newobj) { Py_DECREF(newobj); } 314 | PyErr_Clear(); 315 | return 0; 316 | } 317 | } 318 | 319 | static void construct(PyObject* _obj, 320 | converter::rvalue_from_python_stage1_data* data) { 321 | 322 | PyObject* newobj = PyNumber_Float(_obj); 323 | T* storage = (T*)((converter::rvalue_from_python_storage*)data)->storage.bytes; 324 | 325 | *storage = extract(newobj); 326 | Py_DECREF(newobj); 327 | data->convertible = storage; 328 | } 329 | }; 330 | 331 | 332 | int GetDoubleImSize() { return DoubleImSize; } 333 | void SetDoubleImSize(int i) { DoubleImSize = i; } 334 | 335 | int GetScales() { return Scales; } 336 | void SetScales(int i) { Scales = i; } 337 | 338 | float GetInitSigma() { return InitSigma; } 339 | void SetInitSigma(float f) { InitSigma = f; } 340 | 341 | float GetPeakThresh() { return PeakThresh; } 342 | void SetPeakThresh(float f) { PeakThresh = f; } 343 | 344 | 345 | BOOST_PYTHON_MODULE(siftfastpy) { 346 | import_array(); 347 | numeric::array::set_module_and_type("numpy", "ndarray"); 348 | register_exception_translator(&translate_siftfast_exception); 349 | 350 | int_from_int(); 351 | T_from_number(); 352 | T_from_number(); 353 | 354 | def("DestroyAllResources", DestroyAllResources); 355 | 356 | object (*pkeypoints1)(SiftFastImage&) = PyGetKeypoints; 357 | object (*pkeypoints2)(numeric::array) = PyGetKeypoints; 358 | def("GetKeypoints", pkeypoints1, args("image")); 359 | def("GetKeypoints", pkeypoints2, args("array")); 360 | 361 | class_("SFImage", no_init) 362 | .def(init()) 363 | .def(init()) 364 | 365 | .def_readonly("width", &SiftFastImage::width) 366 | .def_readonly("height", &SiftFastImage::height) 367 | .def("SetData", &SiftFastImage::SetData, args("array")) 368 | .def("setData", &SiftFastImage::SetData, args("array")) 369 | 370 | .def_pickle(Image_pickle_suite()); 371 | 372 | 373 | class_ >("Image", no_init) 374 | .def(init()) 375 | .def(init()) 376 | 377 | .def_readonly("width", &SiftFastImage::width) 378 | .def_readonly("height", &SiftFastImage::height) 379 | .def("SetData", &SiftFastImage::SetData, args("array")) 380 | .def("setData", &SiftFastImage::SetData, args("array")) 381 | 382 | .def_pickle(Image_pickle_suite()); 383 | 384 | 385 | { 386 | scope options = class_("options") 387 | 388 | .add_property("DoubleImSize", GetDoubleImSize, SetDoubleImSize) 389 | .add_property("Scales", GetScales, SetScales) 390 | .add_property("InitSigma", GetInitSigma, SetInitSigma) 391 | .add_property("PeakThresh", GetPeakThresh, SetPeakThresh); 392 | 393 | } 394 | } 395 | -------------------------------------------------------------------------------- /siftmex.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) zerofrog(@gmail.com), 2008-2009 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU Lesser General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // at your option) any later version. 7 | // 8 | //This program is distributed in the hope that it will be useful, 9 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | //Lesser GNU General Public License for more details. 12 | // 13 | //You should have received a copy of the GNU Lesser General Public License 14 | //along with this program. If not, see . 15 | 16 | #include "mex.h" 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | using namespace std; 23 | 24 | #ifdef DVPROFILE 25 | #include "profiler.h" 26 | #endif 27 | 28 | #include "siftfast.h" 29 | 30 | typedef unsigned long long u64; 31 | 32 | // [frames,descr]=sift_mex(I,...) 33 | // takes an image and outputs frames and a descriptor 34 | void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) 35 | { 36 | if(nin == 0 || !mxIsDouble(in[0]) ) 37 | mexErrMsgTxt("sift_fast takes 1 argument: a grayscale image in real format "); 38 | 39 | const int* dimensions = mxGetDimensions(in[0]); 40 | Image image = CreateImageFromMatlabData(mxGetPr(in[0]), dimensions[0], dimensions[1]); 41 | Keypoint keypts = GetKeypoints(image); 42 | 43 | // write the keys to the output 44 | int numkeys = 0; 45 | Keypoint key = keypts; 46 | while(key) { 47 | numkeys++; 48 | key = key->next; 49 | } 50 | 51 | double* frames = NULL, *descr = NULL; 52 | if( nout > 0 ) { 53 | out[0] = mxCreateDoubleMatrix(4,numkeys,mxREAL); 54 | frames = mxGetPr(out[0]); 55 | } 56 | if( nout > 1 ) { 57 | out[1] = mxCreateDoubleMatrix(128,numkeys,mxREAL); 58 | descr = mxGetPr(out[1]); 59 | } 60 | 61 | key = keypts; 62 | while(key) { 63 | 64 | if( frames != NULL ) { 65 | frames[0] = key->col; frames[1] = key->row; frames[2] = key->scale; frames[3] = key->ori; 66 | frames += 4; 67 | } 68 | 69 | if( descr != NULL ) { 70 | for(int i = 0; i < 128; ++i) 71 | descr[i] = (double)key->descrip[i]; 72 | descr += 128; 73 | } 74 | 75 | key = key->next; 76 | } 77 | 78 | FreeKeypoints(keypts); 79 | 80 | #ifdef DVPROFILE 81 | DVProfWrite("prof.txt"); 82 | DVProfClear(); 83 | #endif 84 | 85 | DestroyAllImages(); 86 | } 87 | --------------------------------------------------------------------------------