├── COPYING ├── NEWS ├── TODO ├── INSTALL ├── .gitignore ├── android ├── README.android ├── scripts │ ├── cmake_android.sh │ ├── cmake_android_armeabi.sh │ ├── cmake_android_neon.sh │ ├── wincfg.cmd.tmpl │ └── package.sh ├── Aruco.mk └── CMakeCache.android.initial.cmake ├── src ├── ar_omp.cpp ├── subpixelcorner.h ├── cuda_aruco.h ├── cudaImage.h ├── ar_omp.h ├── CMakeLists.txt ├── exports.h ├── cvdrawingutils.h ├── cudautils.h ├── cudaImage.cu ├── chromaticmask.h ├── marker.h ├── cameraparameters.h ├── arucofidmarkers.h ├── subpixelcorner.cpp ├── boarddetector.h ├── board.h ├── cuda_aruco.cu ├── aruco.h └── highlyreliablemarkers.h ├── AUTHORS ├── aruco-uninstalled.pc.in ├── aruco.pc.in ├── utils_hrm ├── CMakeLists.txt ├── aruco_hrm_create_dictionary.cpp └── aruco_hrm_create_board.cpp ├── cmake_uninstall.cmake.in ├── utils ├── CMakeLists.txt ├── aruco_create_marker.cpp ├── aruco_board_pix2meters.cpp ├── aruco_create_board.cpp ├── aruco_simple.cpp ├── aruco_simple_board.cpp ├── common.h ├── aruco_selectoptimalmarkers.cpp ├── aruco_test_gl.cpp ├── aruco_calibration.cpp ├── aruco_test_board.cpp └── aruco_test.cpp ├── LICENSE ├── config.cmake.in ├── generateDoc.cmake ├── ChangeLog ├── README └── dox.in /COPYING: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | read the README file -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *~ 3 | *.user 4 | -------------------------------------------------------------------------------- /android/README.android: -------------------------------------------------------------------------------- 1 | See http://opencv.willowgarage.com/wiki/Android 2 | -------------------------------------------------------------------------------- /src/ar_omp.cpp: -------------------------------------------------------------------------------- 1 | #ifndef USE_OMP 2 | int omp_get_max_threads() { return 1; } 3 | int omp_get_thread_num() { return 0; } 4 | #endif 5 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | The ARUCO Library has been developed by the Ava group of the Univeristy of Cordoba(Spain) 2 | Contact to Rafael Muñoz Salinas 3 | -------------------------------------------------------------------------------- /android/scripts/cmake_android.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd `dirname $0`/.. 3 | 4 | mkdir -p build 5 | cd build 6 | 7 | cmake -C ../CMakeCache.android.initial.cmake -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake $@ ../.. 8 | 9 | -------------------------------------------------------------------------------- /android/scripts/cmake_android_armeabi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd `dirname $0`/.. 3 | 4 | mkdir -p build_armeabi 5 | cd build_armeabi 6 | 7 | cmake -C ../CMakeCache.android.initial.cmake -DARM_TARGET=armeabi -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake $@ ../.. 8 | 9 | -------------------------------------------------------------------------------- /android/scripts/cmake_android_neon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd `dirname $0`/.. 3 | 4 | mkdir -p build_neon 5 | cd build_neon 6 | 7 | cmake -C ../CMakeCache.android.initial.cmake -DARM_TARGET="armeabi-v7a with NEON" -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake $@ ../.. 8 | 9 | -------------------------------------------------------------------------------- /aruco-uninstalled.pc.in: -------------------------------------------------------------------------------- 1 | 2 | libdir=@CMAKE_CURRENT_BINARY_DIR@ 3 | includedir=@CMAKE_CURRENT_SOURCE_DIR@/src 4 | 5 | Name: @PROJECT_NAME@ 6 | Description: ArUco: a minimal library for Augmented Reality applications based on OpenCv, uninstalled Version. 7 | Version: @PROJECT_VERSION@ 8 | Requires: opencv >= 2.1.0 9 | Libs: -L${libdir} -laruco 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /android/Aruco.mk: -------------------------------------------------------------------------------- 1 | USER_LOCAL_PATH:=$(LOCAL_PATH) 2 | LOCAL_PATH:=$(call my-dir) 3 | ### GLOBAL VARIABLES 4 | ARUCO_STATIC_LIBRARIES:= aruco 5 | ARUCO_C_INCLUDES:= $(LOCAL_PATH)/include 6 | 7 | ##ADD THE MODULE TO THE PROJECT 8 | include $(CLEAR_VARS) 9 | LOCAL_MODULE:= aruco 10 | LOCAL_SRC_FILES:=libs/$(TARGET_ARCH_ABI)/libaruco.a 11 | include $(PREBUILT_STATIC_LIBRARY) 12 | 13 | LOCAL_PATH:=$(USER_LOCAL_PATH) 14 | 15 | 16 | -------------------------------------------------------------------------------- /aruco.pc.in: -------------------------------------------------------------------------------- 1 | A novel approach to fuse the information from multiple keypoint descriptors using the Dempster-Shafer Theory of evidence is proposed 2 | The matching results of each descriptor are transformed into an evidence distribution on which a confidence factor is computed making use of its entropy. T 3 | Our method has been tested with the SIFT, SURF, ORB, BRISK and FREAK obtaining an improvement of up to 10 compared to the best one. 4 | -------------------------------------------------------------------------------- /utils_hrm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src ${GNULIBS_INCLUDE_DIR}) 2 | LINK_LIBRARIES(${PROJECT_NAME} ${REQUIRED_LIBRARIES} ) 3 | 4 | ADD_EXECUTABLE(aruco_hrm_create_dictionary aruco_hrm_create_dictionary.cpp) 5 | ADD_EXECUTABLE(aruco_hrm_test aruco_hrm_test.cpp) 6 | ADD_EXECUTABLE(aruco_hrm_create_board aruco_hrm_create_board.cpp) 7 | ADD_EXECUTABLE(aruco_hrm_test_board aruco_hrm_test_board.cpp) 8 | 9 | INSTALL(TARGETS aruco_hrm_create_dictionary aruco_hrm_test aruco_hrm_create_board aruco_hrm_test_board RUNTIME DESTINATION bin) 10 | 11 | -------------------------------------------------------------------------------- /src/subpixelcorner.h: -------------------------------------------------------------------------------- 1 | #ifndef aruco_SUBPIXELCORNER_HPP 2 | #define aruco_SUBPIXELCORNER_HPP 3 | 4 | #include // Basic OpenCV structures (cv::Mat) 5 | 6 | namespace aruco { 7 | 8 | class SubPixelCorner { 9 | private: 10 | int _winSize; 11 | int _apertureSize; 12 | cv::TermCriteria _term; 13 | double eps; 14 | cv::Mat mask; 15 | int _max_iters; 16 | 17 | public: 18 | bool enable; 19 | SubPixelCorner(); 20 | 21 | void checkTerm(); 22 | 23 | double pointDist(cv::Point2f estimate_corner, cv::Point2f curr_corner); 24 | 25 | /// method to refine the corners 26 | void RefineCorner(cv::Mat image, std::vector< cv::Point2f > &corners); 27 | 28 | // function to generate the mask 29 | void generateMask(); 30 | }; 31 | } 32 | 33 | #endif // SUBPIXELCORNER_HPP 34 | -------------------------------------------------------------------------------- /src/cuda_aruco.h: -------------------------------------------------------------------------------- 1 | #ifndef _CUDA_ARUCO_H_ 2 | #define _CUDA_ARUCO_H_ 3 | 4 | #include 5 | 6 | #include "cudaImage.h" 7 | 8 | namespace cuda_aruco { 9 | 10 | class CudaProcessor { 11 | private: 12 | unsigned char* buffer; 13 | size_t width; 14 | size_t height; 15 | size_t pitch; 16 | 17 | public: 18 | void createBuffer(int _width, int _height, std::vector& _buffers, int _nimages); 19 | void freeBuffer(); 20 | void allocHost(void** _buff, size_t _bytes); 21 | void sync(int i=-1); 22 | void cuda_threshold(CudaImage& _src, float* _tmp, size_t _pp, 23 | CudaImage &_dst, double *t1, 24 | double t2); 25 | void readbackAndCopy(CudaImage& _src, unsigned char* _dst, int _stream); 26 | 27 | void mallocPitch(void** d, size_t* p, size_t w, size_t h); 28 | 29 | }; 30 | 31 | } // namespace cuda_aruco 32 | 33 | #endif // _CUDA_ARUCO_H_ 34 | -------------------------------------------------------------------------------- /android/CMakeCache.android.initial.cmake: -------------------------------------------------------------------------------- 1 | ######################## 2 | # Initial cache settings for opencv on android 3 | # run cmake with: 4 | # cmake -C 5 | ######################## 6 | 7 | #Build shared libraries (.dll/.so CACHE BOOL "" ) instead of static ones (.lib/.a CACHE BOOL "" ) 8 | set(BUILD_SHARED_LIBS OFF CACHE BOOL "" ) 9 | 10 | #Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel. 11 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" ) 12 | 13 | # 14 | set(ANDROID_CREATION ON CACHE INTERNAL "" FORCE ) 15 | 16 | #Enable SSE instructions 17 | SET( USE_SSE OFF CACHE INTERNAL "" FORCE ) 18 | 19 | #Enable SSE2 instructions 20 | SET( USE_SSE2 OFF CACHE INTERNAL "" FORCE ) 21 | 22 | #Enable SSE3 instructions 23 | SET( USE_SSE3 OFF CACHE INTERNAL "" FORCE ) 24 | 25 | #Enable SSE3 instructions 26 | SET( GL_FOUND OFF CACHE INTERNAL "" FORCE ) 27 | 28 | #Set output folder to ${CMAKE_BINARY_DIR} 29 | set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_BINARY_DIR} CACHE PATH "root for library output, set this to change where android libs are compiled to" ) 30 | -------------------------------------------------------------------------------- /src/cudaImage.h: -------------------------------------------------------------------------------- 1 | //********************************************************// 2 | // CUDA SIFT extractor by Marten Bjorkman aka Celebrandil // 3 | //********************************************************// 4 | 5 | #ifndef CUDAIMAGE_H 6 | #define CUDAIMAGE_H 7 | 8 | class CudaImage { 9 | public: 10 | int width, height; 11 | int pitch; 12 | int pitch_h; 13 | unsigned char *h_data; 14 | unsigned char *d_data; 15 | unsigned char *t_data; 16 | bool d_internalAlloc; 17 | bool h_internalAlloc; 18 | public: 19 | CudaImage(); 20 | ~CudaImage(); 21 | void Allocate(int width, int height, int pitch, bool withHost, unsigned char *devMem = NULL, unsigned char *hostMem = NULL); 22 | double Download(); 23 | double Readback(); 24 | double InitTexture(); 25 | double CopyToTexture(CudaImage &dst, bool host); 26 | }; 27 | 28 | int iDivUp(int a, int b); 29 | int iDivDown(int a, int b); 30 | int iAlignUp(int a, int b); 31 | int iAlignDown(int a, int b); 32 | void StartTimer(unsigned int *hTimer); 33 | double StopTimer(unsigned int hTimer); 34 | 35 | #endif // CUDAIMAGE_H 36 | -------------------------------------------------------------------------------- /android/scripts/wincfg.cmd.tmpl: -------------------------------------------------------------------------------- 1 | :: variables required for OpenCV build :: 2 | :: Note: all pathes should be specified without tailing slashes! 3 | SET ANDROID_NDK=C:\full\path\to\your\copy\of\android\NDK\android-ndk-r6 4 | SET CMAKE_EXE=C:\full\path\to\cmake\utility\cmake.exe 5 | SET MAKE_EXE=C:\full\path\to\native\port\of\make\utility\make.exe 6 | 7 | :: variables required for android-opencv build :: 8 | SET ANDROID_SDK=C:\full\path\to\your\copy\of\android\SDK\android-sdk-windows 9 | SET ANT_DIR=C:\full\path\to\ant\directory\apache-ant-1.8.2 10 | SET JAVA_HOME=C:\full\path\to\JDK\jdk1.6.0_25 11 | 12 | :: configuration options :: 13 | :::: general ARM-V7 settings 14 | SET ARM_TARGET=armeabi-v7a 15 | SET BUILD_DIR=build 16 | 17 | :::: uncomment following lines to compile for emulator or old device 18 | ::SET ARM_TARGET=armeabi 19 | ::SET BUILD_DIR=build_armeabi 20 | 21 | :::: uncomment following lines to compile for ARM-V7 with NEON support 22 | ::SET ARM_TARGET=armeabi-v7a with NEON 23 | ::SET BUILD_DIR=build_neon 24 | 25 | :::: other options 26 | ::SET ANDROID_API_LEVEL=8 &:: android-3 is enough for native part of OpenCV but android-8 is required for Java API and samples 27 | -------------------------------------------------------------------------------- /cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------- 2 | # File that provides "make uninstall" target 3 | # We use the file 'install_manifest.txt' 4 | # ----------------------------------------------- 5 | IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 6 | MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 7 | ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 8 | 9 | FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 10 | STRING(REGEX REPLACE "\n" ";" files "${files}") 11 | FOREACH(file ${files}) 12 | MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 13 | # IF(EXISTS "$ENV{DESTDIR}${file}") 14 | # EXEC_PROGRAM( 15 | # "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 16 | # OUTPUT_VARIABLE rm_out 17 | # RETURN_VALUE rm_retval 18 | # ) 19 | EXECUTE_PROCESS(COMMAND rm $ENV{DESTDIR}${file}) 20 | # IF(NOT "${rm_retval}" STREQUAL 0) 21 | # MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 22 | # ENDIF(NOT "${rm_retval}" STREQUAL 0) 23 | # ELSE(EXISTS "$ENV{DESTDIR}${file}") 24 | # MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 25 | # ENDIF(EXISTS "$ENV{DESTDIR}${file}") 26 | ENDFOREACH(file) 27 | 28 | 29 | -------------------------------------------------------------------------------- /utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src ${GNULIBS_INCLUDE_DIR}) 2 | LINK_LIBRARIES(${PROJECT_NAME} ${REQUIRED_LIBRARIES} ) 3 | 4 | ADD_EXECUTABLE(aruco_test aruco_test.cpp) 5 | ADD_EXECUTABLE(aruco_simple aruco_simple.cpp) 6 | ADD_EXECUTABLE(aruco_create_marker aruco_create_marker.cpp) 7 | ADD_EXECUTABLE(aruco_create_board aruco_create_board.cpp) 8 | ADD_EXECUTABLE(aruco_selectoptimalmarkers aruco_selectoptimalmarkers.cpp) 9 | ADD_EXECUTABLE(aruco_simple_board aruco_simple_board.cpp) 10 | ADD_EXECUTABLE(aruco_test_board aruco_test_board.cpp) 11 | ADD_EXECUTABLE(aruco_board_pix2meters aruco_board_pix2meters.cpp) 12 | ADD_EXECUTABLE(aruco_calibration aruco_calibration.cpp) 13 | #ADD_EXECUTABLE(aruco_test_board_stability aruco_test_board_stability.cpp) 14 | 15 | INSTALL(TARGETS aruco_test aruco_board_pix2meters aruco_simple aruco_create_marker aruco_create_board aruco_simple_board aruco_test_board aruco_selectoptimalmarkers RUNTIME DESTINATION bin) 16 | IF(GL_FOUND AND BUILD_GLSAMPLES) 17 | ADD_EXECUTABLE(aruco_test_gl aruco_test_gl.cpp) 18 | TARGET_LINK_LIBRARIES(aruco_test_gl ${OPENGL_LIBS}) 19 | 20 | ADD_EXECUTABLE(aruco_test_board_gl aruco_test_board_gl.cpp) 21 | TARGET_LINK_LIBRARIES(aruco_test_board_gl ${OPENGL_LIBS}) 22 | 23 | ADD_EXECUTABLE(aruco_test_board_gl_mask aruco_test_board_gl_mask.cpp) 24 | TARGET_LINK_LIBRARIES(aruco_test_board_gl_mask ${OPENGL_LIBS}) 25 | 26 | INSTALL(TARGETS aruco_test_gl aruco_test_board_gl aruco_test_board_gl_mask RUNTIME DESTINATION bin) 27 | ENDIF() 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | -------------------------------------------------------------------------------- /src/ar_omp.h: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are 6 | permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | of conditions and the following disclaimer in the documentation and/or other materials 13 | provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 16 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 17 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 18 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 22 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | The views and conclusions contained in the software and documentation are those of the 26 | authors and should not be interpreted as representing official policies, either expressed 27 | or implied, of Rafael Muñoz Salinas. 28 | */ 29 | 30 | #ifdef USE_OMP 31 | #include 32 | #else 33 | int omp_get_max_threads(); 34 | int omp_get_thread_num(); 35 | #endif 36 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | INCLUDE_DIRECTORIES(.) 2 | FILE(GLOB hdrs "*.h*") 3 | FILE(GLOB srcs "*.c*") 4 | 5 | 6 | SET(hdrs ${hdrs}) 7 | SET(srcs ${srcs}) 8 | 9 | # ---------------------------------------------------------------------------- 10 | # CUDA 11 | # ---------------------------------------------------------------------------- 12 | FIND_PACKAGE(CUDA REQUIRED) 13 | include_directories(${CUDA_INCLUDE_DIRS}) 14 | LIST(APPEND CUDA_NVCC_FLAGS "-arch=sm_60;-lineinfo;--compiler-options;-O2") 15 | SET(CUDA_PROPAGATE_HOST_FLAGS ON) 16 | set(cuda_src cuda_aruco.cu cudaImage.cu) 17 | cuda_add_library(cuda_aruco ${cuda_src}) 18 | 19 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") 20 | 21 | ADD_LIBRARY(${PROJECT_NAME} ${srcs} ${hdrs}) 22 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ) 23 | MESSAGE(STATUS "OpenCV_LIB_DIR=${OpenCV_LIB_DIR}") 24 | SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES # create *nix style library versions + symbolic links 25 | DEFINE_SYMBOL DSO_EXPORTS 26 | VERSION ${PROJECT_VERSION} 27 | SOVERSION ${PROJECT_SOVERSION} 28 | CLEAN_DIRECT_OUTPUT 1 # allow creating static and shared libs without conflicts 29 | OUTPUT_NAME "${PROJECT_NAME}${PROJECT_DLLVERSION}" # avoid conflicts between library and binary target names 30 | ) 31 | 32 | TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${REQUIRED_LIBRARIES} cuda_aruco) 33 | 34 | INSTALL(TARGETS ${PROJECT_NAME} cuda_aruco 35 | RUNTIME DESTINATION bin COMPONENT main # Install the dll file in bin directory 36 | LIBRARY DESTINATION lib PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE COMPONENT main 37 | ARCHIVE DESTINATION lib COMPONENT main) # Install the dll.a file in lib directory 38 | 39 | INSTALL(FILES ${hdrs} 40 | DESTINATION include/${PROJECT_NAME} 41 | COMPONENT main) 42 | 43 | -------------------------------------------------------------------------------- /config.cmake.in: -------------------------------------------------------------------------------- 1 | # =================================================================================== 2 | # @PROJECT_NAME@ CMake configuration file 3 | # 4 | # ** File generated automatically, do not modify ** 5 | # 6 | # Usage from an external project: 7 | # In your CMakeLists.txt, add these lines: 8 | # 9 | # FIND_PACKAGE(@PROJECT_NAME@ REQUIRED ) 10 | # TARGET_LINK_LIBRARIES(MY_TARGET_NAME ${@PROJECT_NAME@_LIBS}) 11 | # 12 | # This file will define the following variables: 13 | # - @PROJECT_NAME@_LIBS : The list of libraries to links against. 14 | # - @PROJECT_NAME@_LIB_DIR : The directory where lib files are. Calling LINK_DIRECTORIES 15 | # with this path is NOT needed. 16 | # - @PROJECT_NAME@_VERSION : The version of this PROJECT_NAME build. Example: "1.2.0" 17 | # - @PROJECT_NAME@_VERSION_MAJOR : Major version part of VERSION. Example: "1" 18 | # - @PROJECT_NAME@_VERSION_MINOR : Minor version part of VERSION. Example: "2" 19 | # - @PROJECT_NAME@_VERSION_PATCH : Patch version part of VERSION. Example: "0" 20 | # 21 | # =================================================================================== 22 | INCLUDE_DIRECTORIES("@CMAKE_INSTALL_PREFIX@/include") 23 | SET(@PROJECT_NAME@_INCLUDE_DIRS "@CMAKE_INSTALL_PREFIX@/include") 24 | 25 | LINK_DIRECTORIES("@CMAKE_INSTALL_PREFIX@/lib") 26 | SET(@PROJECT_NAME@_LIB_DIR "@CMAKE_INSTALL_PREFIX@/lib") 27 | 28 | SET(@PROJECT_NAME@_LIBS @REQUIRED_LIBRARIES@ @PROJECT_NAME@@PROJECT_DLLVERSION@ @CUDA_LIBRARIES@) 29 | 30 | SET(@PROJECT_NAME@_FOUND 1) 31 | SET(@PROJECT_NAME@_VERSION @PROJECT_VERSION@) 32 | SET(@PROJECT_NAME@_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) 33 | SET(@PROJECT_NAME@_VERSION_MINOR @PROJECT_VERSION_MINOR@) 34 | SET(@PROJECT_NAME@_VERSION_PATCH @PROJECT_VERSION_PATCH@) 35 | -------------------------------------------------------------------------------- /src/exports.h: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | 29 | 30 | 31 | #ifndef __OPENARUCO_CORE_TYPES_H__ 32 | #define __OPENARUCO_CORE_TYPES_H__ 33 | 34 | #if !defined _CRT_SECURE_NO_DEPRECATE && _MSC_VER > 1300 35 | #define _CRT_SECURE_NO_DEPRECATE /* to avoid multiple Visual Studio 2005 warnings */ 36 | #endif 37 | 38 | 39 | #if (defined WIN32 || defined _WIN32 || defined WINCE) && defined DSO_EXPORTS 40 | #define ARUCO_EXPORTS __declspec(dllexport) 41 | #else 42 | #define ARUCO_EXPORTS 43 | #endif 44 | 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/cvdrawingutils.h: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | #ifndef _ArUco_DrawUtils_H_ 29 | #define _ArUco_DrawUtils_H_ 30 | #include "exports.h" 31 | #include "aruco.h" 32 | namespace aruco { 33 | /**\brief A set of functions to draw in opencv images 34 | */ 35 | class ARUCO_EXPORTS CvDrawingUtils { 36 | public: 37 | static void draw3dAxis(cv::Mat &Image, Marker &m, const CameraParameters &CP); 38 | 39 | static void draw3dCube(cv::Mat &Image, Marker &m, const CameraParameters &CP, bool setYperpendicular = false); 40 | 41 | static void draw3dAxis(cv::Mat &Image, Board &m, const CameraParameters &CP); 42 | 43 | static void draw3dCube(cv::Mat &Image, Board &m, const CameraParameters &CP, bool setYperpendicular = false); 44 | }; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /utils/aruco_create_marker.cpp: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | #include 29 | #include 30 | #include "aruco.h" 31 | #include "arucofidmarkers.h" 32 | using namespace cv; 33 | using namespace std; 34 | 35 | int main(int argc, char **argv) { 36 | try { 37 | if (argc < 3) { 38 | 39 | // You can also use ids 2000-2007 but it is not safe since there are a lot of false positives. 40 | cerr << "Usage: outfile.(jpg|png|ppm|bmp) [sizeInPixels:500 default] [locked (0,1) : 0 default]" << endl; 41 | return -1; 42 | } 43 | int pixSize = 500; 44 | if (argc >= 4) 45 | pixSize = atoi(argv[3]); 46 | bool locked = false; 47 | if (argc >= 5) 48 | locked = atoi(argv[4]); 49 | 50 | Mat marker = aruco::FiducidalMarkers::createMarkerImage(atoi(argv[1]), pixSize, true, locked); 51 | 52 | cv::imwrite(argv[2], marker); 53 | 54 | } catch (std::exception &ex) { 55 | cout << ex.what() << endl; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /utils/aruco_board_pix2meters.cpp: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2012 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | 29 | // This program converts a boardconfiguration file expressed in pixel to another one expressed in meters 30 | #include 31 | #include "board.h" 32 | using namespace std; 33 | using namespace aruco; 34 | int main(int argc, char **argv) { 35 | try { 36 | 37 | if (argc < 4) { 38 | cerr << "Usage: in_boardConfiguration.yml markerSize_meters out_boardConfiguration.yml" << endl; 39 | return -1; 40 | } 41 | aruco::BoardConfiguration BInfo; 42 | BInfo.readFromFile(argv[1]); 43 | if (BInfo.size() == 0) { 44 | cerr << "Invalid bord with no markers" << endl; 45 | return -1; 46 | } 47 | if (!BInfo.isExpressedInPixels()) { 48 | cerr << "The board is not expressed in pixels" << endl; 49 | return -1; 50 | } 51 | // first, we are assuming all markers are equally sized. So, lets get the size in pixels 52 | 53 | int markerSizePix = cv::norm(BInfo[0][0] - BInfo[0][1]); 54 | BInfo.mInfoType = BoardConfiguration::METERS; 55 | // now, get the size of a pixel, and change scale 56 | float markerSize_meters = atof(argv[2]); 57 | float pixSize = markerSize_meters / float(markerSizePix); 58 | cout << markerSize_meters << " " << float(markerSizePix) << " " << pixSize << endl; 59 | for (size_t i = 0; i < BInfo.size(); i++) 60 | for (int c = 0; c < 4; c++) { 61 | BInfo[i][c] *= pixSize; 62 | } 63 | // save to file 64 | BInfo.saveToFile(argv[3]); 65 | } catch (std::exception &ex) { 66 | cout << ex.what() << endl; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/cudautils.h: -------------------------------------------------------------------------------- 1 | #ifndef CUDAUTILS_H 2 | #define CUDAUTILS_H 3 | 4 | #include 5 | #include 6 | 7 | #ifdef WIN32 8 | #include 9 | #endif 10 | 11 | #define safeCall(err) __safeCall(err, __FILE__, __LINE__) 12 | #define safeThreadSync() __safeThreadSync(__FILE__, __LINE__) 13 | #define checkMsg(msg) __checkMsg(msg, __FILE__, __LINE__) 14 | 15 | inline void __safeCall(cudaError err, const char *file, const int line) 16 | { 17 | if (cudaSuccess != err) { 18 | fprintf(stderr, "safeCall() Runtime API error in file <%s>, line %i : %s.\n", file, line, cudaGetErrorString(err)); 19 | exit(-1); 20 | } 21 | } 22 | 23 | inline void __safeThreadSync(const char *file, const int line) 24 | { 25 | cudaError err = cudaThreadSynchronize(); 26 | if (cudaSuccess != err) { 27 | fprintf(stderr, "threadSynchronize() Driver API error in file '%s' in line %i : %s.\n", file, line, cudaGetErrorString(err)); 28 | exit(-1); 29 | } 30 | } 31 | 32 | inline void __checkMsg(const char *errorMessage, const char *file, const int line) 33 | { 34 | cudaError_t err = cudaGetLastError(); 35 | if (cudaSuccess != err) { 36 | fprintf(stderr, "checkMsg() CUDA error: %s in file <%s>, line %i : %s.\n", errorMessage, file, line, cudaGetErrorString(err)); 37 | exit(-1); 38 | } 39 | } 40 | 41 | inline bool deviceInit(int dev) 42 | { 43 | int deviceCount; 44 | safeCall(cudaGetDeviceCount(&deviceCount)); 45 | if (deviceCount == 0) { 46 | fprintf(stderr, "CUDA error: no devices supporting CUDA.\n"); 47 | return false; 48 | } 49 | if (dev < 0) dev = 0; 50 | if (dev > deviceCount-1) dev = deviceCount - 1; 51 | cudaDeviceProp deviceProp; 52 | safeCall(cudaGetDeviceProperties(&deviceProp, dev)); 53 | if (deviceProp.major < 1) { 54 | fprintf(stderr, "error: device does not support CUDA.\n"); 55 | return false; 56 | } 57 | safeCall(cudaSetDevice(dev)); 58 | return true; 59 | } 60 | 61 | class TimerGPU { 62 | public: 63 | cudaEvent_t start, stop; 64 | cudaStream_t stream; 65 | TimerGPU(cudaStream_t stream_ = 0) : stream(stream_) { 66 | cudaEventCreate(&start); 67 | cudaEventCreate(&stop); 68 | cudaEventRecord(start, stream); 69 | } 70 | ~TimerGPU() { 71 | cudaEventDestroy(start); 72 | cudaEventDestroy(stop); 73 | } 74 | float read() { 75 | cudaEventRecord(stop, stream); 76 | cudaEventSynchronize(stop); 77 | float time; 78 | cudaEventElapsedTime(&time, start, stop); 79 | return time; 80 | } 81 | }; 82 | 83 | class TimerCPU 84 | { 85 | static const int bits = 10; 86 | public: 87 | long long beg_clock; 88 | float freq; 89 | TimerCPU(float freq_) : freq(freq_) { // freq = clock frequency in MHz 90 | beg_clock = getTSC(bits); 91 | } 92 | long long getTSC(int bits) { 93 | #ifdef WIN32 94 | return __rdtsc()/(1LL<>bits); 99 | #endif 100 | } 101 | float read() { 102 | long long end_clock = getTSC(bits); 103 | long long Kcycles = end_clock - beg_clock; 104 | float time = (float)(1< 30 | #include 31 | #include "arucofidmarkers.h" 32 | using namespace std; 33 | using namespace cv; 34 | int main(int argc, char **argv) { 35 | try { 36 | if (argc < 4) { 37 | cerr << "Usage: X:Y boardImage.png boardConfiguration.yml [pixSize] [Type(0: panel,1: chessboard, 2: frame)] [interMarkerDistance(0,1)]" << endl; 38 | return -1; 39 | } 40 | int XSize, YSize; 41 | if (sscanf(argv[1], "%d:%d", &XSize, &YSize) != 2) { 42 | cerr << "Incorrect X:Y specification" << endl; 43 | return -1; 44 | } 45 | int pixSize = 100; 46 | float interMarkerDistance = 0.2; 47 | bool isChessBoard = false; 48 | int typeBoard = 0; 49 | if (argc >= 5) 50 | pixSize = atoi(argv[4]); 51 | if (argc >= 6) 52 | typeBoard = atoi(argv[5]); 53 | if (argc >= 7) 54 | interMarkerDistance = atof(argv[6]); 55 | if ((interMarkerDistance > 1.f) || (interMarkerDistance < 0.f)) { 56 | cerr << "Incorrect interMarkerDistance '" << interMarkerDistance << "' -- needs to be [0,1]" << endl; 57 | return -1; 58 | } 59 | aruco::BoardConfiguration BInfo; 60 | Mat BoardImage; 61 | if (typeBoard == 0) 62 | BoardImage = aruco::FiducidalMarkers::createBoardImage(Size(XSize, YSize), pixSize, pixSize * interMarkerDistance, BInfo); 63 | else if (typeBoard == 1) 64 | BoardImage = aruco::FiducidalMarkers::createBoardImage_ChessBoard(Size(XSize, YSize), pixSize, BInfo); 65 | else if (typeBoard == 2) 66 | BoardImage = aruco::FiducidalMarkers::createBoardImage_Frame(Size(XSize, YSize), pixSize, pixSize * interMarkerDistance, BInfo); 67 | 68 | else { 69 | cerr << "Incorrect board type" << typeBoard << endl; 70 | return -1; 71 | } 72 | 73 | imwrite(argv[2], BoardImage); 74 | BInfo.saveToFile(argv[3]); 75 | 76 | } catch (std::exception &ex) { 77 | cout << ex.what() << endl; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /android/scripts/package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd `dirname $0`/.. 3 | 4 | ANDROID_DIR=`pwd` 5 | 6 | rm -rf package 7 | mkdir -p package 8 | cd package 9 | 10 | PRG_DIR=`pwd` 11 | mkdir opencv 12 | 13 | # neon-enabled build 14 | #cd $PRG_DIR 15 | #mkdir build-neon 16 | #cd build-neon 17 | 18 | #cmake -C "$ANDROID_DIR/CMakeCache.android.initial.cmake" -DARM_TARGET="armeabi-v7a with NEON" -DBUILD_DOCS=OFF -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_ANDROID_EXAMPLES=OFF -DCMAKE_TOOLCHAIN_FILE="$ANDROID_DIR/android.toolchain.cmake" -DCMAKE_INSTALL_PREFIX="$PRG_DIR/opencv" "$ANDROID_DIR/.." || exit 1 19 | #make -j8 install/strip || exit 1 20 | 21 | #cd "$PRG_DIR/opencv" 22 | #rm -rf doc include src .classpath .project AndroidManifest.xml default.properties share/OpenCV/haarcascades share/OpenCV/lbpcascades share/OpenCV/*.cmake share/OpenCV/OpenCV.mk 23 | #mv libs/armeabi-v7a libs/armeabi-v7a-neon 24 | #mv share/OpenCV/3rdparty/libs/armeabi-v7a share/OpenCV/3rdparty/libs/armeabi-v7a-neon 25 | 26 | 27 | # armeabi-v7a build 28 | cd "$PRG_DIR" 29 | mkdir build 30 | cd build 31 | 32 | cmake -C "$ANDROID_DIR/CMakeCache.android.initial.cmake" -DARM_TARGET="armeabi-v7a" -DBUILD_DOCS=OFF -DBUILD_TESTS=ON -DBUILD_EXAMPLES=OFF -DBUILD_ANDROID_EXAMPLES=ON -DCMAKE_TOOLCHAIN_FILE="$ANDROID_DIR/android.toolchain.cmake" -DCMAKE_INSTALL_PREFIX="$PRG_DIR/opencv" "$ANDROID_DIR/.." || exit 1 33 | make -j8 install/strip || exit 1 34 | 35 | cd "$PRG_DIR/opencv" 36 | rm -rf doc include src .classpath .project AndroidManifest.xml default.properties share/OpenCV/haarcascades share/OpenCV/lbpcascades share/OpenCV/*.cmake share/OpenCV/OpenCV.mk 37 | 38 | 39 | # armeabi build 40 | cd "$PRG_DIR/build" 41 | rm -rf CMakeCache.txt 42 | 43 | cmake -C "$ANDROID_DIR/CMakeCache.android.initial.cmake" -DARM_TARGET="armeabi" -DBUILD_DOCS=ON -DBUILD_TESTS=ON -DBUILD_EXAMPLES=OFF -DBUILD_ANDROID_EXAMPLES=ON -DINSTALL_ANDROID_EXAMPLES=ON -DCMAKE_TOOLCHAIN_FILE="$ANDROID_DIR/android.toolchain.cmake" -DCMAKE_INSTALL_PREFIX="$PRG_DIR/opencv" "$ANDROID_DIR/.." || exit 1 44 | make -j8 install/strip docs || exit 1 45 | 46 | find doc -name "*.pdf" -exec cp {} $PRG_DIR/opencv/doc \; 47 | 48 | cd $PRG_DIR 49 | rm -rf opencv/doc/CMakeLists.txt 50 | cp "$ANDROID_DIR/README.android" opencv/ 51 | cp "$ANDROID_DIR/../README" opencv/ 52 | 53 | 54 | # get opencv version 55 | CV_VERSION=`grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+" opencv/share/OpenCV/OpenCVConfig-version.cmake` 56 | OPENCV_NAME=OpenCV-$CV_VERSION 57 | mv opencv $OPENCV_NAME 58 | 59 | #samples 60 | cp -r "$ANDROID_DIR/../samples/android" "$PRG_DIR/samples" 61 | cd "$PRG_DIR/samples" 62 | 63 | #enable for loops over items with spaces in their name 64 | IFS=" 65 | " 66 | for dir in `ls -1` 67 | do 68 | if [ -f "$dir/default.properties" ] 69 | then 70 | HAS_REFERENCE=`cat "$dir/default.properties" | grep -c android.library.reference.1` 71 | if [ $HAS_REFERENCE = 1 ] 72 | then 73 | echo -n > "$dir/default.properties" 74 | android update project --name "$dir" --target "android-8" --library "../../$OPENCV_NAME" --path "$dir" 75 | #echo 'android update project --name "$dir" --target "android-8" --library "../opencv$CV_VERSION" --path "$dir"' 76 | fi 77 | else 78 | rm -rf "$dir" 79 | fi 80 | done 81 | 82 | echo "OPENCV_MK_PATH:=../../$OPENCV_NAME/share/OpenCV/OpenCV.mk" > includeOpenCV.mk 83 | 84 | 85 | #clean samples 86 | cd "$PRG_DIR/samples" 87 | #remove ignored files/folders 88 | svn status --no-ignore | grep ^I | cut -c9- | xargs -d \\n rm -rf 89 | #remove unversioned files/folders 90 | svn status | grep ^\? | cut -c9- | xargs -d \\n rm -rf 91 | 92 | 93 | #generate "gen" folders to eliminate eclipse warnings 94 | cd "$PRG_DIR/samples" 95 | for dir in `ls -1` 96 | do 97 | if [ -d "$dir" ] 98 | then 99 | mkdir "$dir/gen" 100 | fi 101 | done 102 | 103 | 104 | #generate folders "gen" and "res" for opencv (dummy eclipse stiff) 105 | cd $PRG_DIR 106 | mkdir "$OPENCV_NAME/gen" 107 | mkdir "$OPENCV_NAME/res" 108 | 109 | # pack all files 110 | cd $PRG_DIR 111 | PRG_NAME=OpenCV-$CV_VERSION-tp-android-bin.tar.bz2 112 | tar cjpf $PRG_NAME --exclude-vcs $OPENCV_NAME samples || exit -1 113 | echo 114 | echo "Package $PRG_NAME is successfully created" 115 | -------------------------------------------------------------------------------- /src/cudaImage.cu: -------------------------------------------------------------------------------- 1 | //********************************************************// 2 | // CUDA SIFT extractor by Marten Bjorkman aka Celebrandil // 3 | //********************************************************// 4 | 5 | #include 6 | 7 | #include "cudautils.h" 8 | #include "cudaImage.h" 9 | 10 | int iDivUp(int a, int b) { return (a%b != 0) ? (a/b + 1) : (a/b); } 11 | int iDivDown(int a, int b) { return a/b; } 12 | int iAlignUp(int a, int b) { return (a%b != 0) ? (a - a%b + b) : a; } 13 | int iAlignDown(int a, int b) { return a - a%b; } 14 | 15 | void CudaImage::Allocate(int w, int h, int p, bool host, unsigned char *devmem, unsigned char *hostmem) 16 | { 17 | width = w; 18 | height = h; 19 | pitch = p; 20 | pitch_h = width; 21 | d_data = devmem; 22 | h_data = hostmem; 23 | t_data = NULL; 24 | if (devmem==NULL) { 25 | safeCall(cudaMallocPitch((void **)&d_data, (size_t*)&pitch, (size_t)(sizeof(unsigned char)*width), (size_t)height)); 26 | pitch /= sizeof(unsigned char); 27 | if (d_data==NULL) 28 | printf("Failed to allocate device data\n"); 29 | d_internalAlloc = true; 30 | } 31 | if (host && hostmem==NULL) { 32 | printf("--- Allocated pinned memory\n"); 33 | pitch_h = pitch; 34 | cudaMallocHost( (void**)&h_data, sizeof(unsigned char)*pitch*height ); 35 | //h_data = (float *)malloc(sizeof(float)*pitch*height); 36 | h_internalAlloc = true; 37 | } 38 | } 39 | 40 | CudaImage::CudaImage() : 41 | width(0), height(0), d_data(NULL), h_data(NULL), t_data(NULL), d_internalAlloc(false), h_internalAlloc(false) 42 | { 43 | 44 | } 45 | 46 | CudaImage::~CudaImage() 47 | { 48 | if (d_internalAlloc && d_data!=NULL) 49 | safeCall(cudaFree(d_data)); 50 | d_data = NULL; 51 | if (h_internalAlloc && h_data!=NULL) 52 | free(h_data); 53 | h_data = NULL; 54 | if (t_data!=NULL) 55 | safeCall(cudaFreeArray((cudaArray *)t_data)); 56 | t_data = NULL; 57 | } 58 | 59 | double CudaImage::Download() 60 | { 61 | //TimerGPU timer(0); 62 | int p = sizeof(unsigned char)*pitch; 63 | if (d_data!=NULL && h_data!=NULL) 64 | safeCall(cudaMemcpy2DAsync(d_data, p, h_data, sizeof(unsigned char)*pitch_h, sizeof(unsigned char)*width, height, cudaMemcpyHostToDevice)); 65 | //double gpuTime = timer.read(); 66 | #ifdef VERBOSE 67 | printf("Download time = %.2f ms\n", gpuTime); 68 | #endif 69 | return 0;//gpuTime; 70 | } 71 | 72 | double CudaImage::Readback() 73 | { 74 | //TimerGPU timer(0); 75 | int p = sizeof(unsigned char)*pitch; 76 | safeCall(cudaMemcpy2DAsync(h_data, sizeof(unsigned char)*pitch_h, d_data, p, sizeof(unsigned char)*width, height, cudaMemcpyDeviceToHost)); 77 | //double gpuTime = timer.read(); 78 | #ifdef VERBOSE 79 | printf("Readback time = %.2f ms\n", gpuTime); 80 | #endif 81 | return 0;//gpuTime; 82 | } 83 | 84 | double CudaImage::InitTexture() 85 | { 86 | TimerGPU timer(0); 87 | cudaChannelFormatDesc t_desc = cudaCreateChannelDesc(); 88 | safeCall(cudaMallocArray((cudaArray **)&t_data, &t_desc, pitch, height)); 89 | if (t_data==NULL) 90 | printf("Failed to allocated texture data\n"); 91 | double gpuTime = timer.read(); 92 | #ifdef VERBOSE 93 | printf("InitTexture time = %.2f ms\n", gpuTime); 94 | #endif 95 | return gpuTime; 96 | } 97 | 98 | double CudaImage::CopyToTexture(CudaImage &dst, bool host) 99 | { 100 | if (dst.t_data==NULL) { 101 | printf("Error CopyToTexture: No texture data\n"); 102 | return 0.0; 103 | } 104 | if ((!host || h_data==NULL) && (host || d_data==NULL)) { 105 | printf("Error CopyToTexture: No source data\n"); 106 | return 0.0; 107 | } 108 | TimerGPU timer(0); 109 | if (host) 110 | safeCall(cudaMemcpyToArray((cudaArray *)dst.t_data, 0, 0, h_data, sizeof(unsigned char)*pitch*dst.height, cudaMemcpyHostToDevice)); 111 | else 112 | safeCall(cudaMemcpyToArray((cudaArray *)dst.t_data, 0, 0, d_data, sizeof(unsigned char)*pitch*dst.height, cudaMemcpyDeviceToDevice)); 113 | safeCall(cudaThreadSynchronize()); 114 | double gpuTime = timer.read(); 115 | #ifdef VERBOSE 116 | printf("CopyToTexture time = %.2f ms\n", gpuTime); 117 | #endif 118 | return gpuTime; 119 | } 120 | -------------------------------------------------------------------------------- /generateDoc.cmake: -------------------------------------------------------------------------------- 1 | # -helper macro to add a "doc" target with CMake build system. 2 | # and configure doxy.config.in to doxy.config 3 | # 4 | # target "doc" allows building the documentation with doxygen/dot on WIN32 and Linux 5 | # Creates .chm windows help file if MS HTML help workshop 6 | # (available from http://msdn.microsoft.com/workshop/author/htmlhelp) 7 | # is installed with its DLLs in PATH. 8 | # 9 | # 10 | # Please note, that the tools, e.g.: 11 | # doxygen, dot, latex, dvips, makeindex, gswin32, etc. 12 | # must be in path. 13 | # 14 | # Note about Visual Studio Projects: 15 | # MSVS hast its own path environment which may differ from the shell. 16 | # See "Menu Tools/Options/Projects/VC++ Directories" in VS 7.1 17 | # 18 | # author Jan Woetzel 2004-2006 19 | # www.mip.informatik.uni-kiel.de/~jw 20 | # 21 | # Modified by Luis Díaz 2009 http://plagatux.es 22 | 23 | MACRO(GENERATE_DOCUMENTATION DOX_CONFIG_FILE) 24 | FIND_PACKAGE(Doxygen) 25 | IF (DOXYGEN_FOUND) 26 | #Define variables 27 | SET(SRCDIR "${PROJECT_SOURCE_DIR}/src") 28 | SET(TAGFILE "${PROJECT_BINARY_DIR}/doc/${PROJECT_NAME}.tag") 29 | 30 | IF (USE_CHM AND WIN32) 31 | SET(WIN_CHM "YES") 32 | SET(CHM_FILE "${PROJECT_SOURCE_DIR}/doc/help.chm") 33 | SET (BINARY_TOC "YES") 34 | SET (TOC_EXPAND "YES") 35 | ELSE() 36 | SET(WIN_CHM "NO") 37 | SET (BINARY_TOC "NO") 38 | SET (TOC_EXPAND "NO") 39 | ENDIF() 40 | 41 | IF (USE_LATEX) 42 | SET(GENERATE_PDF "YES") 43 | SET(GENERATE_LATEX "YES") 44 | SET(LATEXOUT "latex") 45 | ELSE() 46 | SET(GENERATE_PDF "NO") 47 | SET(GENERATE_LATEX "NO") 48 | ENDIF() 49 | 50 | IF (NOT USE_DOT) 51 | SET(DOXYGEN_DOT_FOUND "NO") 52 | ENDIF() 53 | 54 | #click+jump in Emacs and Visual Studio (for doxy.config) (jw) 55 | IF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") 56 | SET(DOXY_WARN_FORMAT "\"$file($line) : $text \"") 57 | ELSE (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") 58 | SET(DOXY_WARN_FORMAT "\"$file:$line: $text \"") 59 | ENDIF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") 60 | 61 | # we need latex for doxygen because of the formulas 62 | FIND_PACKAGE(LATEX) 63 | IF (NOT LATEX_COMPILER) 64 | MESSAGE(STATUS "latex command LATEX_COMPILER not found but usually required. You will probably get warnings and user inetraction on doxy run.") 65 | ENDIF (NOT LATEX_COMPILER) 66 | IF (NOT MAKEINDEX_COMPILER) 67 | MESSAGE(STATUS "makeindex command MAKEINDEX_COMPILER not found but usually required.") 68 | ENDIF (NOT MAKEINDEX_COMPILER) 69 | IF (NOT DVIPS_CONVERTER) 70 | MESSAGE(STATUS "dvips command DVIPS_CONVERTER not found but usually required.") 71 | ENDIF (NOT DVIPS_CONVERTER) 72 | 73 | # Check config file 74 | IF (EXISTS "${DOX_CONFIG_FILE}") 75 | CONFIGURE_FILE(${DOX_CONFIG_FILE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config @ONLY ) #OUT-OF-PLACE LOCATION 76 | SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config") 77 | ELSE () 78 | MESSAGE(SEND_ERROR "Please create configuration file for doxygen in ${CMAKE_CURRENT_SOURCE_DIR}") 79 | ENDIF() 80 | 81 | # Add target 82 | ADD_CUSTOM_TARGET(doc ${DOXYGEN_EXECUTABLE} ${DOXY_CONFIG}) 83 | 84 | IF (WIN32 AND GENERATE_WIN_CHM STREQUAL "YES") 85 | FIND_PACKAGE(HTMLHelp) 86 | IF (HTML_HELP_COMPILER) 87 | ADD_CUSTOM_TARGET(winhelp ${HTML_HELP_COMPILER} ${HHP_FILE}) 88 | ADD_DEPENDENCIES (winhelp doc) 89 | IF (EXISTS ${CHM_FILE}) 90 | IF (PROJECT_NAME) 91 | SET(OUT "${PROJECT_NAME}") 92 | ELSE () 93 | SET(OUT "Documentation") # default 94 | ENDIF() 95 | IF (${PROJECT_NAME}_VERSION_MAJOR) 96 | SET(OUT "${OUT}-${${PROJECT_NAME}_VERSION_MAJOR}") 97 | IF (${PROJECT_NAME}_VERSION_MINOR) 98 | SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_MINOR}") 99 | IF (${PROJECT_NAME}_VERSION_PATCH) 100 | SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_PATCH}") 101 | ENDIF() 102 | ENDIF() 103 | ENDIF() 104 | SET(OUT "${OUT}.chm") 105 | INSTALL(FILES ${CHM_FILE} DESTINATION "doc" RENAME "${OUT}") 106 | ENDIF() 107 | ELSE() 108 | MESSAGE(FATAL_ERROR "You have not Microsoft Help Compiler") 109 | ENDIF() 110 | ENDIF () 111 | 112 | INSTALL(DIRECTORY "${PROJECT_BINARY_DIR}/html/" DESTINATION "share/doc/lib${PROJECT_NAME}") 113 | 114 | ENDIF(DOXYGEN_FOUND) 115 | ENDMACRO(GENERATE_DOCUMENTATION) 116 | -------------------------------------------------------------------------------- /utils/aruco_simple.cpp: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | 29 | 30 | #include 31 | #include "aruco.h" 32 | #include "cvdrawingutils.h" 33 | #include 34 | using namespace cv; 35 | using namespace aruco; 36 | int main(int argc, char **argv) { 37 | try { 38 | if (argc < 2) { 39 | cerr << "Usage: (in.jpg|in.avi) [cameraParams.yml] [markerSize] [outImage]" << endl; 40 | exit(0); 41 | } 42 | 43 | 44 | aruco::CameraParameters CamParam; 45 | MarkerDetector MDetector; 46 | vector< Marker > Markers; 47 | float MarkerSize = -1; 48 | // read the input image 49 | cv::Mat InImage; 50 | // try opening first as video 51 | VideoCapture vreader(argv[1]); 52 | if (vreader.isOpened()) { 53 | vreader.grab(); 54 | vreader.retrieve(InImage); 55 | } else { 56 | InImage = cv::imread(argv[1]); 57 | } 58 | // at this point, we should have the image in InImage 59 | // if empty, exit 60 | if (InImage.total() == 0) { 61 | cerr << "Could not open input" << endl; 62 | return 0; 63 | } 64 | 65 | // read camera parameters if specifed 66 | if (argc >= 3) { 67 | CamParam.readFromXMLFile(argv[2]); 68 | // resizes the parameters to fit the size of the input image 69 | CamParam.resize(InImage.size()); 70 | } 71 | // read marker size if specified 72 | if (argc >= 4) 73 | MarkerSize = atof(argv[3]); 74 | cv::namedWindow("in", 1); 75 | 76 | 77 | // Ok, let's detect 78 | MDetector.detect(InImage, Markers, CamParam, MarkerSize); 79 | // for each marker, draw info and its boundaries in the image 80 | for (unsigned int i = 0; i < Markers.size(); i++) { 81 | cout << Markers[i] << endl; 82 | Markers[i].draw(InImage, Scalar(0, 0, 255), 2); 83 | } 84 | // draw a 3d cube in each marker if there is 3d info 85 | if (CamParam.isValid() && MarkerSize != -1) 86 | for (unsigned int i = 0; i < Markers.size(); i++) { 87 | CvDrawingUtils::draw3dCube(InImage, Markers[i], CamParam); 88 | } 89 | // show input with augmented information 90 | cv::imshow("in", InImage); 91 | // show also the internal image resulting from the threshold operation 92 | cv::imshow("thes", MDetector.getThresholdedImage()); 93 | cv::waitKey(0); // wait for key to be pressed 94 | 95 | 96 | if (argc >= 5) 97 | cv::imwrite(argv[4], InImage); 98 | } catch (std::exception &ex) 99 | 100 | { 101 | cout << "Exception :" << ex.what() << endl; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /utils/aruco_simple_board.cpp: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "aruco.h" 34 | #include "boarddetector.h" 35 | #include "cvdrawingutils.h" 36 | using namespace cv; 37 | using namespace aruco; 38 | /************************************ 39 | * 40 | * 41 | * 42 | * 43 | ************************************/ 44 | int main(int argc, char **argv) { 45 | try { 46 | if (argc < 3) { 47 | cerr << "Usage: image boardConfig.yml [cameraParams.yml] [markerSize] [outImage]" << endl; 48 | exit(0); 49 | } 50 | aruco::CameraParameters CamParam; 51 | MarkerDetector MDetector; 52 | vector< Marker > Markers; 53 | float MarkerSize = -1; 54 | BoardConfiguration TheBoardConfig; 55 | BoardDetector TheBoardDetector; 56 | Board TheBoardDetected; 57 | 58 | cv::Mat InImage = cv::imread(argv[1]); 59 | TheBoardConfig.readFromFile(argv[2]); 60 | if (argc >= 4) { 61 | CamParam.readFromXMLFile(argv[3]); 62 | // resizes the parameters to fit the size of the input image 63 | CamParam.resize(InImage.size()); 64 | } 65 | 66 | if (argc >= 5) 67 | MarkerSize = atof(argv[4]); 68 | 69 | cv::namedWindow("in", 1); 70 | MDetector.detect(InImage, Markers); // detect markers without computing R and T information 71 | // Detection of the board 72 | float probDetect = TheBoardDetector.detect(Markers, TheBoardConfig, TheBoardDetected, CamParam, MarkerSize); 73 | 74 | // for each marker, draw info and its boundaries in the image 75 | for (unsigned int i = 0; i < Markers.size(); i++) { 76 | cout << Markers[i] << endl; 77 | Markers[i].draw(InImage, Scalar(0, 0, 255), 2); 78 | } 79 | 80 | // draw a 3d cube in each marker if there is 3d info 81 | if (CamParam.isValid()) { 82 | for (unsigned int i = 0; i < Markers.size(); i++) { 83 | CvDrawingUtils::draw3dCube(InImage, Markers[i], CamParam); 84 | CvDrawingUtils::draw3dAxis(InImage, Markers[i], CamParam); 85 | } 86 | CvDrawingUtils::draw3dAxis(InImage, TheBoardDetected, CamParam); 87 | cout << TheBoardDetected.Rvec << " " << TheBoardDetected.Tvec << endl; 88 | } 89 | // draw board axis 90 | 91 | // show input with augmented information 92 | cv::imshow("in", InImage); 93 | cv::waitKey(0); // wait for key to be pressed 94 | if (argc >= 6) 95 | cv::imwrite(argv[5], InImage); 96 | 97 | } catch (std::exception &ex) 98 | 99 | { 100 | cout << "Exception :" << ex.what() << endl; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /utils/common.h: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | #ifndef _COMMON_ARUCO_ 29 | #define _COMMON_ARUCO_ 30 | #include 31 | using namespace cv; 32 | /**This function reads the matrix intrinsics and the distorsion coefficients from a file. 33 | * The format of the file is 34 | * \code 35 | * # comments 36 | * fx fy cx cy k1 k2 p1 p2 width height 1 37 | * \endcode 38 | * @param TheIntrinsicFile path to the file with the info 39 | * @param TheIntriscCameraMatrix output matrix with the intrinsics 40 | * @param TheDistorsionCameraParams output vector with distorsion params 41 | * @param size of the images captured. Note that the images you are using might be different from these employed for calibration (which are in the file). 42 | * If so, the intrinsic must be adapted properly. That is why you must pass here the size of the images you are employing 43 | * @return true if params are readed properly 44 | */ 45 | 46 | bool readIntrinsicFile(string TheIntrinsicFile,Mat & TheIntriscCameraMatrix,Mat &TheDistorsionCameraParams,Size size) 47 | { 48 | //open file 49 | ifstream InFile(TheIntrinsicFile.c_str()); 50 | if (!InFile) return false; 51 | char line[1024]; 52 | InFile.getline(line,1024); //skype first line that should contain only comments 53 | InFile.getline(line,1024);//read the line with real info 54 | 55 | //transfer to a proper container 56 | stringstream InLine; 57 | InLine<>TheIntriscCameraMatrix.at(0,0);//fx 65 | InLine>>TheIntriscCameraMatrix.at(1,1); //fy 66 | InLine>>TheIntriscCameraMatrix.at(0,2); //cx 67 | InLine>>TheIntriscCameraMatrix.at(1,2);//cy 68 | //read distorion parameters 69 | for(int i=0;i<4;i++) InLine>>TheDistorsionCameraParams.at(i,0); 70 | 71 | //now, read the camera size 72 | float width,height; 73 | InLine>>width>>height; 74 | //resize the camera parameters to fit this image size 75 | float AxFactor= float(size.width)/ width; 76 | float AyFactor= float(size.height)/ height; 77 | TheIntriscCameraMatrix.at(0,0)*=AxFactor; 78 | TheIntriscCameraMatrix.at(0,2)*=AxFactor; 79 | TheIntriscCameraMatrix.at(1,1)*=AyFactor; 80 | TheIntriscCameraMatrix.at(1,2)*=AyFactor; 81 | 82 | //debug 83 | cout<<"fx="<(0,0)< _classifier; 60 | #else 61 | cv::EM _classifier; 62 | #endif 63 | vector< uchar > _samples; 64 | bool _inside[256]; 65 | double _prob[256]; 66 | double _histogram[256]; 67 | unsigned int _nelem; 68 | double _threshProb; 69 | }; 70 | 71 | 72 | class ARUCO_EXPORTS ChromaticMask { 73 | public: 74 | ChromaticMask() : _cellSize(20) { _isValid = false; }; 75 | 76 | void setParams(unsigned int mc, unsigned int nc, double threshProb, aruco::CameraParameters CP, aruco::BoardConfiguration BC, 77 | vector< cv::Point3f > corners); 78 | void setParams(unsigned int mc, unsigned int nc, double threshProb, aruco::CameraParameters CP, aruco::BoardConfiguration BC, float markersize = -1.); 79 | 80 | void calculateGridImage(const aruco::Board &board); 81 | 82 | cv::Mat getCellMap() { return _cellMap; }; 83 | cv::Mat getMask() { return _mask; }; 84 | 85 | void train(const cv::Mat &in, const aruco::Board &board); 86 | void classify(const cv::Mat &in, const aruco::Board &board); 87 | void classify2(const cv::Mat &in, const aruco::Board &board); 88 | void update(const cv::Mat &in); 89 | 90 | bool isValid() { return _isValid; }; 91 | void resetMask(); 92 | 93 | private: 94 | double getDistance(cv::Point2d pixel, unsigned int classifier) { 95 | cv::Vec2b canPos = _canonicalPos.at< cv::Vec2b >(pixel.y, pixel.x)[0]; 96 | return norm(_cellCenters[classifier] - cv::Point2f(canPos[0], canPos[1])); 97 | } 98 | 99 | vector< cv::Point2f > _imgCornerPoints; 100 | vector< cv::Point3f > _objCornerPoints; 101 | cv::Mat _perpTrans; 102 | vector< EMClassifier > _classifiers; 103 | vector< cv::Point2f > _centers; 104 | vector< cv::Point2f > _pixelsVector; 105 | vector< cv::Point2f > _cellCenters; 106 | vector< vector< size_t > > _cell_neighbours; 107 | const float _cellSize; 108 | 109 | 110 | unsigned int _mc, _nc; 111 | aruco::BoardDetector _BD; 112 | aruco::CameraParameters _CP; 113 | cv::Mat _canonicalPos, _cellMap, _mask, _maskAux; 114 | bool _isValid; 115 | double _threshProb; 116 | }; 117 | 118 | #endif // CHROMATICMASK_H 119 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | VERSION 1.3 2 | - Compatibility with OpenCV 3 3 | - In Marker Detector: 4 | - Paralelization using OpenMP 5 | - Marked as deprecated enableErosion and pyrDown 6 | - Added functionality for markers with "locked corners". We refer to marker whose corners are connected 7 | either to another marker (formaing a chessboard pattern), or to another black square. In this mode, 8 | the use of subcorner refinement methods is expected to be more precise. See enableLockedCornersMethod() 9 | - Added funcionality to search for the first threshold parameter simultaneously in several 10 | values. The process is parallelized in multiple threads. See setMultiThresholdSearch() 11 | - In HRM markers: 12 | - Speed up marker identification process 13 | - Improve performance of dictionary generation process. 14 | - Added LICENSE file 15 | 16 | VERSION 1.2.5 17 | - New type of markers: highly reliable markers (hrm) including utils to use them 18 | - Added chromaticmask class to create occlusion mask based on chromatic boards 19 | - Added watermark with the id to the markers to allow easy identification of printed markers 20 | - Now, by default, setYPerpendicular=false. So, Z is now pointing out of the board. 21 | - Added a reprjection test in boardetector see BoardDetector::set_repj_err_thres() and BoardDetector::get_repj_err_thres () 22 | - Added support for 5 distortion parameters in CameraParameters class 23 | - Removed experimental code for removing the deformation that occurs when a marker is in a cylinder 24 | - Omp support in linux (in markerdetector) 25 | - Added an static function in BoardDetector::detect to do everything in a single line. 26 | - New BoardConfiguration constructor receving a path with the configuration to be read. 27 | - Revised opencv #includes to include just the necessary modules 28 | - Added aruco_calibration.cpp to perform camera calibration using aruco boards 29 | - Changes in LINES refinement to perform undistortion automatically 30 | - Method setYPerperdicular in BoardDetector changed to setYPerpendicular (spelling error) 31 | - Added getWarpSize() and setWarpSize methods in MarkerDetector to allow changing the canonical image size 32 | - Bug fixed in aruco_create_board 33 | 34 | VERSION 1.2.4 35 | - Bugs fixed for MSVC2010 36 | 37 | VERSION 1.2.3 38 | - Changes in boardconfiguration and boardetector to allow arbitrary located markers. No API changes involved, except for the config files that have changed their format. 39 | - Changes in arucofidmarkers to allow the creation of chessboard like boards (FiducidalMarkers::createBoardImage_ChessBoard). 40 | Added the corresponding change in aruco_create_board to support such feature 41 | - Added experimental code for removing the deformation that occurs when a marker is in a cylinder 42 | - Added the corner refinement method LINES. It is based on intersecting the lines of the marker's sides using the contour points. 43 | We believe this is the best refinement method of the library so far. 44 | - Added functionality in aruco::BoarDetector to perform the whole detection process in it if desired 45 | - Changed aruco_test_board to use the new functionality described above 46 | - Changed old way of obtaining extrinsics FindExtrinsicParam2 for the new one solvePnp in BoardDetector and in Marker 47 | 48 | VERSION 1.1.0 49 | - Ogre integration ( Board::OgreGetPoseParameters and Marker::OgreGetPoseParameters). 50 | - Changes to make it compile with MSVC 2010 51 | - Remove getopt.h dependency. Command line are simpler now 52 | - MarkerDetector: Externalization of the marker detector to allow using user-defined markers. The function setMakerDetectorFunction allows to define this function 53 | - Added class FiducidalMarkers to detect the original aruco markers 54 | - MarkerDetector: function glGetProjectionMatrix is moved to the CameraParameters class. Sorry, but it is more logical. 55 | - MarkerDetector: Clear separation between the detection phases into separated functions that can be externally called (thresHold and detectRectangles) for more sohpisticated user needs 56 | - MarkerDetector: new corner refinement method based on harris detector. Also, added the possibility of not refining corners at all. 57 | - Added an option to work on a reduced version of the images (pyrDown). 58 | - Changes the adaptive threshold method. Now we employ the MEAN. As a consequence, the process is faster and do not depen on the window size. 59 | - Initial tests with android 60 | - Bugs fixed 61 | 62 | VERSION 1.0.0 63 | - New names for the main classes Marker,MarkerDector... etc. Sorry, but I needed to clear up things. It wont be difficult to adapt. 64 | - A new class for the camera parameters. It can be readed from the calibration.cpp application in OpenCv2.2 65 | - Refactorization of code to make it more maintainable 66 | - Better support for Windows (Cmake) and OpenGL 67 | - Improved documentation. Windows users should read the README file that explains how to build the library 68 | - A new class for drawing markers and boards in opencv images 69 | - A couple of new very simple examples to teach the use of the library(aruco_simple and aruco_simple_board) 70 | 71 | VERSION 0.9.5 72 | Added support for Boards 73 | Added cmake support 74 | Bugs fixed 75 | -------------------------------------------------------------------------------- /src/marker.h: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | #ifndef _Aruco_Marker_H 29 | #define _Aruco_Marker_H 30 | #include 31 | #include 32 | #include 33 | #include "exports.h" 34 | #include "cameraparameters.h" 35 | using namespace std; 36 | namespace aruco { 37 | /**\brief This class represents a marker. It is a vector of the fours corners ot the marker 38 | * 39 | */ 40 | 41 | class ARUCO_EXPORTS Marker : public std::vector< cv::Point2f > { 42 | public: 43 | // id of the marker 44 | int id; 45 | // size of the markers sides in meters 46 | float ssize; 47 | // matrices of rotation and translation respect to the camera 48 | cv::Mat Rvec, Tvec; 49 | 50 | /** 51 | */ 52 | Marker(); 53 | /** 54 | */ 55 | Marker(const Marker &M); 56 | /** 57 | */ 58 | Marker(const std::vector< cv::Point2f > &corners, int _id = -1); 59 | /** 60 | */ 61 | ~Marker() {} 62 | /**Indicates if this object is valid 63 | */ 64 | bool isValid() const { return id != -1 && size() == 4; } 65 | 66 | /**Draws this marker in the input image 67 | */ 68 | void draw(cv::Mat &in, cv::Scalar color, int lineWidth = 1, bool writeId = true) const; 69 | 70 | /**Calculates the extrinsics (Rvec and Tvec) of the marker with respect to the camera 71 | * @param markerSize size of the marker side expressed in meters 72 | * @param CP parmeters of the camera 73 | * @param setYPerpendicular If set the Y axis will be perpendicular to the surface. Otherwise, it will be the Z axis 74 | */ 75 | void calculateExtrinsics(float markerSize, const CameraParameters &CP, bool setYPerpendicular = true) throw(cv::Exception); 76 | /**Calculates the extrinsics (Rvec and Tvec) of the marker with respect to the camera 77 | * @param markerSize size of the marker side expressed in meters 78 | * @param CameraMatrix matrix with camera parameters (fx,fy,cx,cy) 79 | * @param Distorsion matrix with distorsion parameters (k1,k2,p1,p2) 80 | * @param setYPerpendicular If set the Y axis will be perpendicular to the surface. Otherwise, it will be the Z axis 81 | */ 82 | void calculateExtrinsics(float markerSize, cv::Mat CameraMatrix, cv::Mat Distorsion = cv::Mat(), bool setYPerpendicular = true) throw(cv::Exception); 83 | 84 | /**Given the extrinsic camera parameters returns the GL_MODELVIEW matrix for opengl. 85 | * Setting this matrix, the reference coordinate system will be set in this marker 86 | */ 87 | void glGetModelViewMatrix(double modelview_matrix[16]) throw(cv::Exception); 88 | 89 | /** 90 | * Returns position vector and orientation quaternion for an Ogre scene node or entity. 91 | * Use: 92 | * ... 93 | * Ogre::Vector3 ogrePos (position[0], position[1], position[2]); 94 | * Ogre::Quaternion ogreOrient (orientation[0], orientation[1], orientation[2], orientation[3]); 95 | * mySceneNode->setPosition( ogrePos ); 96 | * mySceneNode->setOrientation( ogreOrient ); 97 | * ... 98 | */ 99 | void OgreGetPoseParameters(double position[3], double orientation[4]) throw(cv::Exception); 100 | 101 | /**Returns the centroid of the marker 102 | */ 103 | cv::Point2f getCenter() const; 104 | /**Returns the perimeter of the marker 105 | */ 106 | float getPerimeter() const; 107 | /**Returns the area 108 | */ 109 | float getArea() const; 110 | /** 111 | */ 112 | /** 113 | */ 114 | friend bool operator<(const Marker &M1, const Marker &M2) { return M1.id < M2.id; } 115 | /** 116 | */ 117 | friend ostream &operator<<(ostream &str, const Marker &M) { 118 | str << M.id << "="; 119 | for (int i = 0; i < 4; i++) 120 | str << "(" << M[i].x << "," << M[i].y << ") "; 121 | str << "Txyz="; 122 | for (int i = 0; i < 3; i++) 123 | str << M.Tvec.ptr< float >(0)[i] << " "; 124 | str << "Rxyz="; 125 | for (int i = 0; i < 3; i++) 126 | str << M.Rvec.ptr< float >(0)[i] << " "; 127 | 128 | return str; 129 | } 130 | 131 | 132 | private: 133 | void rotateXAxis(cv::Mat &rotation); 134 | }; 135 | } 136 | #endif 137 | -------------------------------------------------------------------------------- /utils_hrm/aruco_hrm_create_dictionary.cpp: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | 29 | #include "highlyreliablemarkers.h" 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | using namespace std; 36 | 37 | typedef std::vector< int > Word; 38 | 39 | 40 | 41 | 42 | class MarkerGenerator { 43 | 44 | private: 45 | int _nTransitions; 46 | std::vector< int > _transitionsWeigth; 47 | int _totalWeigth; 48 | int _n; 49 | 50 | public: 51 | MarkerGenerator(int n) { 52 | _n = n; 53 | _nTransitions = n - 1; 54 | _transitionsWeigth.resize(_nTransitions); 55 | _totalWeigth = 0; 56 | for (int i = 0; i < _nTransitions; i++) { 57 | _transitionsWeigth[i] = i; 58 | _totalWeigth += i; 59 | } 60 | } 61 | 62 | aruco::MarkerCode generateMarker() { 63 | 64 | aruco::MarkerCode emptyMarker(_n); 65 | 66 | for (int w = 0; w < _n; w++) { 67 | Word currentWord(_n, 0); 68 | int randomNum = rand() % _totalWeigth; 69 | int currentNTransitions = _nTransitions - 1; 70 | for (int k = 0; k < _nTransitions; k++) { 71 | if (_transitionsWeigth[k] > randomNum) { 72 | currentNTransitions = k; 73 | break; 74 | } 75 | } 76 | std::vector< int > transitionsIndexes(_nTransitions); 77 | for (int i = 0; i < _nTransitions; i++) 78 | transitionsIndexes[i] = i; 79 | std::random_shuffle(transitionsIndexes.begin(), transitionsIndexes.end()); 80 | 81 | std::vector< int > selectedIndexes; 82 | for (int k = 0; k < currentNTransitions; k++) 83 | selectedIndexes.push_back(transitionsIndexes[k]); 84 | std::sort(selectedIndexes.begin(), selectedIndexes.end()); 85 | int currBit = rand() % 2; 86 | int currSelectedIndexesIdx = 0; 87 | for (int k = 0; k < _n; k++) { 88 | currentWord[k] = currBit; 89 | if (currSelectedIndexesIdx < selectedIndexes.size() && k == selectedIndexes[currSelectedIndexesIdx]) { 90 | currBit = 1 - currBit; 91 | currSelectedIndexesIdx++; 92 | } 93 | } 94 | 95 | for (int k = 0; k < _n; k++) 96 | emptyMarker.set(w * _n + k, bool(currentWord[k]), false); 97 | } 98 | 99 | return emptyMarker; 100 | } 101 | }; 102 | 103 | 104 | 105 | 106 | int main(int argc, char **argv) { 107 | if (argc < 4) { 108 | cerr << "Invalid number of arguments" << endl; 109 | cerr << "Usage: outputfile.yml dictSize n \n \ 110 | outputfile.yml: output file for the dictionary \n \ 111 | dictSize: number of markers to add to the dictionary \n \ 112 | n: marker size." << endl; 113 | exit(-1); 114 | } 115 | 116 | aruco::Dictionary D; 117 | unsigned int dictSize = atoi(argv[2]); 118 | unsigned int n = atoi(argv[3]); 119 | 120 | unsigned int tau = 2 * ((4 * ((n * n) / 4)) / 3); 121 | std::cout << "Tau: " << tau << std::endl; 122 | 123 | srand(time(NULL)); 124 | 125 | MarkerGenerator MG(n); 126 | 127 | const int MAX_UNPRODUCTIVE_ITERATIONS = 100000; 128 | int currentMaxUnproductiveIterations = MAX_UNPRODUCTIVE_ITERATIONS; 129 | 130 | unsigned int countUnproductive = 0; 131 | while (D.size() < dictSize) { 132 | 133 | aruco::MarkerCode candidate; 134 | candidate = MG.generateMarker(); 135 | 136 | if (candidate.selfDistance() >= tau && D.distance(candidate) >= tau) { 137 | D.push_back(candidate); 138 | std::cout << "Accepted Marker " << D.size() << "/" << dictSize << std::endl; 139 | countUnproductive = 0; 140 | } else { 141 | countUnproductive++; 142 | if (countUnproductive == currentMaxUnproductiveIterations) { 143 | tau--; 144 | countUnproductive = 0; 145 | std::cout << "Reducing Tau to: " << tau << std::endl; 146 | if (tau == 0) { 147 | std::cerr << "Error: Tau=0. Small marker size for too high number of markers. Stop" << std::endl; 148 | break; 149 | } 150 | if (D.size() >= 2) 151 | currentMaxUnproductiveIterations = MAX_UNPRODUCTIVE_ITERATIONS; 152 | else 153 | currentMaxUnproductiveIterations = MAX_UNPRODUCTIVE_ITERATIONS / 15; 154 | } 155 | } 156 | } 157 | 158 | D.tau0 = tau; 159 | D.toFile(argv[1]); 160 | } 161 | -------------------------------------------------------------------------------- /src/cameraparameters.h: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | #ifndef _Aruco_CameraParameters_H 29 | #define _Aruco_CameraParameters_H 30 | #include "exports.h" 31 | #include 32 | #include 33 | using namespace std; 34 | namespace aruco { 35 | /**\brief Parameters of the camera 36 | */ 37 | 38 | class ARUCO_EXPORTS CameraParameters { 39 | public: 40 | // 3x3 matrix (fx 0 cx, 0 fy cy, 0 0 1) 41 | cv::Mat CameraMatrix; 42 | // 4x1 matrix (k1,k2,p1,p2) 43 | cv::Mat Distorsion; 44 | // size of the image 45 | cv::Size CamSize; 46 | 47 | /**Empty constructor 48 | */ 49 | CameraParameters(); 50 | /**Creates the object from the info passed 51 | * @param cameraMatrix 3x3 matrix (fx 0 cx, 0 fy cy, 0 0 1) 52 | * @param distorsionCoeff 4x1 matrix (k1,k2,p1,p2) 53 | * @param size image size 54 | */ 55 | CameraParameters(cv::Mat cameraMatrix, cv::Mat distorsionCoeff, cv::Size size) throw(cv::Exception); 56 | /**Sets the parameters 57 | * @param cameraMatrix 3x3 matrix (fx 0 cx, 0 fy cy, 0 0 1) 58 | * @param distorsionCoeff 4x1 matrix (k1,k2,p1,p2) 59 | * @param size image size 60 | */ 61 | void setParams(cv::Mat cameraMatrix, cv::Mat distorsionCoeff, cv::Size size) throw(cv::Exception); 62 | /**Copy constructor 63 | */ 64 | CameraParameters(const CameraParameters &CI); 65 | 66 | /**Indicates whether this object is valid 67 | */ 68 | bool isValid() const { 69 | return CameraMatrix.rows != 0 && CameraMatrix.cols != 0 && Distorsion.rows != 0 && Distorsion.cols != 0 && CamSize.width != -1 && CamSize.height != -1; 70 | } 71 | /**Assign operator 72 | */ 73 | CameraParameters &operator=(const CameraParameters &CI); 74 | /**Reads the camera parameters from a file generated using saveToFile. 75 | */ 76 | void readFromFile(string path) throw(cv::Exception); 77 | /**Saves this to a file 78 | */ 79 | void saveToFile(string path, bool inXML = true) throw(cv::Exception); 80 | 81 | /**Reads from a YAML file generated with the opencv2.2 calibration utility 82 | */ 83 | void readFromXMLFile(string filePath) throw(cv::Exception); 84 | 85 | /**Adjust the parameters to the size of the image indicated 86 | */ 87 | void resize(cv::Size size) throw(cv::Exception); 88 | 89 | /**Returns the location of the camera in the reference system given by the rotation and translation vectors passed 90 | * NOT TESTED 91 | */ 92 | static cv::Point3f getCameraLocation(cv::Mat Rvec, cv::Mat Tvec); 93 | 94 | /**Given the intrinsic camera parameters returns the GL_PROJECTION matrix for opengl. 95 | * PLease NOTE that when using OpenGL, it is assumed no camera distorsion! So, if it is not true, you should have 96 | * undistor image 97 | * 98 | * @param orgImgSize size of the original image 99 | * @param size of the image/window where to render (can be different from the real camera image). Please not that it must be related to CamMatrix 100 | * @param proj_matrix output projection matrix to give to opengl 101 | * @param gnear,gfar: visible rendering range 102 | * @param invert: indicates if the output projection matrix has to yield a horizontally inverted image because image data has not been stored in the order of 103 | *glDrawPixels: bottom-to-top. 104 | */ 105 | void glGetProjectionMatrix(cv::Size orgImgSize, cv::Size size, double proj_matrix[16], double gnear, double gfar, bool invert = false) throw(cv::Exception); 106 | 107 | /** 108 | * setup camera for an Ogre project. 109 | * Use: 110 | * ... 111 | * Ogre::Matrix4 PM(proj_matrix[0], proj_matrix[1], ... , proj_matrix[15]); 112 | * yourCamera->setCustomProjectionMatrix(true, PM); 113 | * yourCamera->setCustomViewMatrix(true, Ogre::Matrix4::IDENTITY); 114 | * ... 115 | * As in OpenGL, it assumes no camera distorsion 116 | */ 117 | void OgreGetProjectionMatrix(cv::Size orgImgSize, cv::Size size, double proj_matrix[16], double gnear, double gfar, 118 | bool invert = false) throw(cv::Exception); 119 | 120 | 121 | /**Returns the 4x4 homogeneous transform matrix from the R and T vectors computed 122 | */ 123 | static cv::Mat getRTMatrix(const cv::Mat &R_, const cv::Mat &T_, int forceType); 124 | 125 | private: 126 | // GL routines 127 | 128 | static void argConvGLcpara2(double cparam[3][4], int width, int height, double gnear, double gfar, double m[16], bool invert) throw(cv::Exception); 129 | static int arParamDecompMat(double source[3][4], double cpara[3][4], double trans[3][4]) throw(cv::Exception); 130 | static double norm(double a, double b, double c); 131 | static double dot(double a1, double a2, double a3, double b1, double b2, double b3); 132 | }; 133 | } 134 | #endif 135 | -------------------------------------------------------------------------------- /src/arucofidmarkers.h: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | 29 | #ifndef ArucoFiducicalMarkerDetector_H 30 | #define ArucoFiducicalMarkerDetector_H 31 | #include 32 | #include "exports.h" 33 | #include "marker.h" 34 | #include "board.h" 35 | namespace aruco { 36 | 37 | class ARUCO_EXPORTS FiducidalMarkers { 38 | public: 39 | /** 40 | * \brief Creates an ar marker with the id specified using a modified version of the hamming code. 41 | * There are two type of markers: a) These of 10 bits b) these of 3 bits. The latter are employed for applications 42 | * that need few marker but they must be small. The two type of markers are distinguished by their ids. While the first type 43 | * of markers have ids in the interval [0-1023], the second type ids in the interval [2000-2006]. 44 | * 45 | * 46 | * 10 bits markers 47 | * ----------------------- 48 | * There are a total of 5 rows of 5 cols. Each row encodes a total of 2 bits, so there are 2^10 bits:(0-1023). 49 | * 50 | * The least significative bytes are first (from left-up to to right-bottom) 51 | * 52 | * Example: the id = 110 (decimal) is be represented in binary as : 00 01 10 11 10. 53 | * 54 | * Then, it will generate the following marker: 55 | * 56 | * -# 1st row encodes 00: 1 0 0 0 0 : hex 0x10 57 | * -# 2nd row encodes 01: 1 0 1 1 1 : hex 0x17 58 | * -# 3nd row encodes 10: 0 1 0 0 1 : hex 0x09 59 | * -# 4th row encodes 11: 0 1 1 1 0 : hex 0x0e 60 | * -# 5th row encodes 10: 0 1 0 0 1 : hex 0x09 61 | * 62 | * Note that : The first bit, is the inverse of the hamming parity. This avoids the 0 0 0 0 0 to be valid 63 | * These marker are detected by the function getFiduciadlMarker_Aruco_Type1 64 | * @param writeIdWaterMark if true, writes a watermark with the marker id 65 | * @param locked if true, creates etra rectangles lcoking the corners of the marker (new in version 1.2.6) 66 | */ 67 | static cv::Mat createMarkerImage(int id, int size, bool writeIdWaterMark = true, bool locked = false) throw(cv::Exception); 68 | 69 | /** Detection of fiducidal aruco markers (10 bits) 70 | * @param in input image with the patch that contains the possible marker 71 | * @param nRotations number of 90deg rotations in clockwise direction needed to set the marker in correct position 72 | * @return -1 if the image passed is a not a valid marker, and its id in case it really is a marker 73 | */ 74 | static int detect(const cv::Mat &in, int &nRotations); 75 | 76 | /**Similar to createMarkerImage. Instead of returning a visible image, returns a 8UC1 matrix of 0s and 1s with the marker info 77 | */ 78 | static cv::Mat getMarkerMat(int id) throw(cv::Exception); 79 | 80 | 81 | /**Creates a printable image of a board 82 | * @param gridSize grid layout (numer of sqaures in x and Y) 83 | * @param MarkerSize size of markers sides in pixels 84 | * @param MarkerDistance distance between the markers 85 | * @param TInfo output 86 | * @param excludedIds set of ids excluded from the board 87 | */ 88 | static cv::Mat createBoardImage(cv::Size gridSize, int MarkerSize, int MarkerDistance, BoardConfiguration &TInfo, 89 | vector< int > *excludedIds = NULL) throw(cv::Exception); 90 | 91 | 92 | /**Creates a printable image of a board in chessboard_like manner 93 | * @param gridSize grid layout (numer of sqaures in x and Y) 94 | * @param MarkerSize size of markers sides in pixels 95 | * @param TInfo output 96 | * @param setDataCentered indicates if the center is set at the center of the board. Otherwise it is the left-upper corner 97 | * 98 | */ 99 | static cv::Mat createBoardImage_ChessBoard(cv::Size gridSize, int MarkerSize, BoardConfiguration &TInfo, bool setDataCentered = true, 100 | vector< int > *excludedIds = NULL) throw(cv::Exception); 101 | 102 | /**Creates a printable image of a board in a frame fashion 103 | * @param gridSize grid layout (numer of sqaures in x and Y) 104 | * @param MarkerSize size of markers sides in pixels 105 | * @param MarkerDistance distance between the markers 106 | * @param TInfo output 107 | * @param setDataCentered indicates if the center is set at the center of the board. Otherwise it is the left-upper corner 108 | * 109 | */ 110 | static cv::Mat createBoardImage_Frame(cv::Size gridSize, int MarkerSize, int MarkerDistance, BoardConfiguration &TInfo, bool setDataCentered = true, 111 | vector< int > *excludedIds = NULL) throw(cv::Exception); 112 | 113 | private: 114 | static vector< int > getListOfValidMarkersIds_random(int nMarkers, vector< int > *excluded) throw(cv::Exception); 115 | static cv::Mat rotate(const cv::Mat &in); 116 | static int hammDistMarker(cv::Mat bits); 117 | static int analyzeMarkerImage(cv::Mat &grey, int &nRotations); 118 | static bool correctHammMarker(cv::Mat &bits); 119 | }; 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /utils_hrm/aruco_hrm_create_board.cpp: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | 29 | #include "highlyreliablemarkers.h" 30 | #include 31 | #include 32 | #include "board.h" 33 | 34 | int main(int argc, char **argv) { 35 | if (argc < 6) { 36 | cerr << "Invalid number of arguments" << endl; 37 | cerr << "Usage: dictionary.yml outputboard.yml outputimage.png height width [chromatic=0] [outdictionary.yml] \n \ 38 | dictionary.yml: input dictionary from where markers are taken to create the board \n \ 39 | outputboard.yml: output board configuration file in aruco format \n \ 40 | outputimage.png: output image for the created board \n \ 41 | height: height of the board (num of markers) \n \ 42 | width: width of the board (num of markers) \n \ 43 | chromatic: 0 for black&white markers, 1 for green&blue chromatic markers \n \ 44 | outdictionary.yml: output dictionary with only the markers included in the board" << endl; 45 | exit(-1); 46 | } 47 | 48 | // read parameters 49 | std::string dictionaryfile = argv[1]; 50 | std::string outboard = argv[2]; 51 | std::string outimg = argv[3]; 52 | cv::Size gridSize; 53 | gridSize.height = atoi(argv[4]); 54 | gridSize.width = atoi(argv[5]); 55 | bool chromatic = false; 56 | if (argc >= 7) 57 | chromatic = (argv[6][0] == '1'); 58 | 59 | aruco::Dictionary D; 60 | D.fromFile(dictionaryfile); 61 | if (D.size() == 0) { 62 | std::cerr << "Error: Dictionary is empty" << std::endl; 63 | exit(-1); 64 | } 65 | 66 | int nMarkers = gridSize.height * gridSize.width; 67 | unsigned int MarkerSize = (D[0].n() + 2) * 20; 68 | unsigned int MarkerDistance = MarkerSize / 5; 69 | 70 | int sizeY = gridSize.height * MarkerSize + (gridSize.height - 1) * MarkerDistance; 71 | int sizeX = gridSize.width * MarkerSize + (gridSize.width - 1) * MarkerDistance; 72 | // find the center so that the ref systeem is in it 73 | float centerX = sizeX / 2.; 74 | float centerY = sizeY / 2.; 75 | 76 | aruco::Dictionary outD; 77 | 78 | aruco::BoardConfiguration BC; 79 | BC.mInfoType = aruco::BoardConfiguration::PIX; 80 | 81 | // indicate the data is expressed in pixels 82 | cv::Mat tableImage(sizeY, sizeX, CV_8UC1); 83 | tableImage.setTo(cv::Scalar(255)); 84 | int idp = 0; 85 | for (int y = 0; y < gridSize.height; y++) 86 | for (int x = 0; x < gridSize.width; x++, idp += 1) { 87 | // create image 88 | cv::Mat subrect(tableImage, cv::Rect(x * (MarkerDistance + MarkerSize), y * (MarkerDistance + MarkerSize), MarkerSize, MarkerSize)); 89 | cv::Mat marker = D[idp].getImg(MarkerSize); 90 | marker.copyTo(subrect); 91 | outD.push_back(D[idp]); 92 | 93 | // add to board configuration 94 | aruco::MarkerInfo MI; 95 | MI.resize(4); 96 | MI.id = idp; 97 | for (unsigned int i = 0; i < 4; i++) 98 | MI[i].z = 0; 99 | MI[0].x = x * (MarkerDistance + MarkerSize) - centerX; 100 | MI[0].y = y * (MarkerDistance + MarkerSize) - centerY; 101 | MI[1].x = x * (MarkerDistance + MarkerSize) + MarkerSize - centerX; 102 | MI[1].y = y * (MarkerDistance + MarkerSize) - centerY; 103 | MI[2].x = x * (MarkerDistance + MarkerSize) + MarkerSize - centerX; 104 | MI[2].y = y * (MarkerDistance + MarkerSize) + MarkerSize - centerY; 105 | MI[3].x = x * (MarkerDistance + MarkerSize) - centerX; 106 | MI[3].y = y * (MarkerDistance + MarkerSize) + MarkerSize - centerY; 107 | // makes y negative so z axis is pointing up 108 | MI[0].y *= -1; 109 | MI[1].y *= -1; 110 | MI[2].y *= -1; 111 | MI[3].y *= -1; 112 | BC.push_back(MI); 113 | } 114 | 115 | BC.saveToFile(outboard); // save board configuration 116 | if (argc >= 8) { 117 | outD.tau0 = outD.minimunDistance(); 118 | outD.toFile(argv[7]); // save new dictionary just with the used markers, if desired 119 | } 120 | 121 | if (chromatic) { 122 | cv::Scalar color1 = cv::Scalar(250, 134, 4); 123 | // cv::Scalar color2 = cv::Scalar(0,255,0); 124 | cv::Vec3b color2Vec3b = cv::Vec3b(0, 255, 0); // store as a Vec3b to assign easily to the image 125 | 126 | // create new image with border and with color 1 127 | cv::Mat chromaticImg(tableImage.rows + 2 * MarkerDistance, tableImage.cols + 2 * MarkerDistance, CV_8UC3, color1); 128 | 129 | // now use color2 in black pixels 130 | for (unsigned int i = 0; i < tableImage.rows; i++) { 131 | for (unsigned int j = 0; j < tableImage.cols; j++) { 132 | if (tableImage.at< uchar >(i, j) == 0) 133 | chromaticImg.at< cv::Vec3b >(MarkerDistance + i, MarkerDistance + j) = color2Vec3b; 134 | } 135 | } 136 | tableImage = chromaticImg; 137 | } 138 | 139 | 140 | cv::imshow("Board", tableImage); 141 | cv::waitKey(0); 142 | 143 | cv::imwrite(outimg, tableImage); // save output image 144 | } 145 | -------------------------------------------------------------------------------- /src/subpixelcorner.cpp: -------------------------------------------------------------------------------- 1 | #include "subpixelcorner.h" 2 | #include 3 | using namespace cv; 4 | 5 | namespace aruco { 6 | 7 | SubPixelCorner::SubPixelCorner() { 8 | _winSize = 15; 9 | _apertureSize = 3; 10 | _term.maxCount = 10; 11 | _term.epsilon = 0.1; 12 | _term.type = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS; 13 | enable = true; 14 | } 15 | 16 | void SubPixelCorner::checkTerm() { 17 | switch (_term.type) { 18 | case CV_TERMCRIT_ITER: 19 | _term.epsilon = 0.f; 20 | _term.maxCount; 21 | break; 22 | case CV_TERMCRIT_EPS: 23 | _term.maxCount = _term.COUNT; 24 | break; 25 | case CV_TERMCRIT_ITER | CV_TERMCRIT_EPS: 26 | break; 27 | default: 28 | _term.maxCount = _term.COUNT; 29 | _term.epsilon = 0.1; 30 | _term.type = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS; 31 | break; 32 | } 33 | 34 | eps = std::max(_term.epsilon, 0.0); 35 | eps = eps * eps; 36 | 37 | _max_iters = std::max(_term.maxCount, 1); 38 | int max1 = TermCriteria::MAX_ITER; 39 | _max_iters = std::min(_max_iters, max1); 40 | } 41 | 42 | double SubPixelCorner::pointDist(cv::Point2f estimate_corner, cv::Point2f curr_corner) { 43 | double dist = ((curr_corner.x - estimate_corner.x) * (curr_corner.x - estimate_corner.x)) + 44 | ((curr_corner.y - estimate_corner.y) * (curr_corner.y - estimate_corner.y)); 45 | return dist; 46 | } 47 | 48 | 49 | void SubPixelCorner::generateMask() { 50 | 51 | double coeff = 1. / (_winSize * _winSize); 52 | float *maskX = (float *)calloc(1, (_winSize * sizeof(float))); 53 | float *maskY = (float *)calloc(1, (_winSize * sizeof(float))); 54 | mask.create(_winSize, _winSize, CV_32FC(1)); 55 | /* calculate mask */ 56 | int k = 0; 57 | for (int i = -_winSize / 2, k = 0; i <= _winSize / 2; i++, k++) { 58 | maskX[k] = (float)exp(-i * i * coeff); 59 | } 60 | 61 | maskY = maskX; 62 | 63 | for (int i = 0; i < _winSize; i++) { 64 | float *mask_ptr = mask.ptr< float >(i); 65 | for (int j = 0; j < _winSize; j++) { 66 | mask_ptr[j] = maskX[j] * maskY[i]; 67 | } 68 | } 69 | } 70 | 71 | void SubPixelCorner::RefineCorner(cv::Mat image, std::vector< cv::Point2f > &corners) { 72 | 73 | if (enable == false) 74 | return; 75 | checkTerm(); 76 | 77 | generateMask(); 78 | // loop over all the corner points 79 | for (int k = 0; k < corners.size(); k++) { 80 | cv::Point2f curr_corner; 81 | // initial estimate 82 | cv::Point2f estimate_corner = corners[k]; 83 | 84 | // cerr << 'SSS" << corners[k].x <<":" << corners[k].y << endl; 85 | 86 | if (estimate_corner.x < 0 || estimate_corner.y < 0 || estimate_corner.y > image.rows || estimate_corner.y > image.cols) 87 | continue; 88 | int iter = 0; 89 | double dist = TermCriteria::EPS; 90 | // loop till termination criteria is met 91 | do { 92 | iter = iter + 1; 93 | curr_corner = estimate_corner; 94 | 95 | /* 96 | Point cx; 97 | cx.x=floor(curr_corner.x); 98 | cx.y=floor(curr_corner.y); 99 | double dx=curr_corner.x-cx.x; 100 | double dy=curr_corner.y-cx.y; 101 | float vIx[2]; 102 | float vIy[2]; 103 | 104 | vIx[0] = dx; 105 | vIx[1] = 1 - dx; 106 | vIy[0] = dy; 107 | vIy[1] = 1 - dy; 108 | 109 | int x1=std::max((int)(cx.x-_winSize-_apertureSize/2),0); 110 | int y1=std::max((int)(cx.y-_winSize-_apertureSize/2),0); 111 | 112 | xmin = x1<0?0:x1; 113 | xmax = x1+_winSize(i); 138 | float *dy_ptr = Dy.ptr< float >(i); 139 | ly = i - _winSize / 2 - _apertureSize / 2; 140 | 141 | float *mask_ptr = mask.ptr< float >(ly + _winSize / 2); 142 | 143 | for (int j = _apertureSize / 2; j <= _winSize; j++) { 144 | 145 | lx = j - _winSize / 2 - _apertureSize / 2; 146 | // cerr << lx+_winSize/2 << ":" ; 147 | double val = mask_ptr[lx + _winSize / 2]; 148 | double dxx = dx_ptr[j] * dx_ptr[j] * val; 149 | double dyy = dy_ptr[j] * dy_ptr[j] * val; 150 | double dxy = dx_ptr[j] * dy_ptr[j] * val; 151 | 152 | A = A + dxx; 153 | B = B + dxy; 154 | E = E + dyy; 155 | C = C + dxx * lx + dxy * ly; 156 | F = F + dxy * lx + dyy * ly; 157 | } 158 | } 159 | 160 | // computing denominator 161 | double det = (A * E - B * B); 162 | if (fabs(det) > DBL_EPSILON * DBL_EPSILON) { 163 | det = 1.0 / det; 164 | // translating back to original corner and adding new estimates 165 | estimate_corner.x = curr_corner.x + ((C * E) - (B * F)) * det; 166 | estimate_corner.y = curr_corner.y + ((A * F) - (C * D)) * det; 167 | } else { 168 | estimate_corner.x = curr_corner.x; 169 | estimate_corner.y = curr_corner.y; 170 | } 171 | 172 | dist = pointDist(estimate_corner, curr_corner); 173 | 174 | 175 | } while (iter < _max_iters && dist > eps); 176 | 177 | // double dist=pointDist(corners[k],estimate_corner); 178 | if (fabs(corners[k].x - estimate_corner.x) > _winSize || fabs(corners[k].y - estimate_corner.y) > _winSize) { 179 | estimate_corner.x = corners[k].x; 180 | estimate_corner.y = corners[k].y; 181 | } 182 | corners[k].x = estimate_corner.x; 183 | corners[k].y = estimate_corner.y; 184 | // cerr << "EEE" << corners[k].x <<":" << corners[k].y << endl; 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/boarddetector.h: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | #ifndef _Aruco_BoardDetector_H 29 | #define _Aruco_BoardDetector_H 30 | #include 31 | #include "exports.h" 32 | #include "board.h" 33 | #include "cameraparameters.h" 34 | #include "markerdetector.h" 35 | using namespace std; 36 | 37 | namespace aruco { 38 | 39 | /**\brief This class detects AR boards 40 | * Version 1.2 41 | * There are two modes for board detection. 42 | * First, the old way. (You first detect markers with MarkerDetector and then call to detect in this class. 43 | * 44 | * Second: New mode, marker detection is included in the class 45 | * \code 46 | 47 | CameraParameters CP; 48 | CP.readFromFile(path_cp) 49 | BoardConfiguration BC; 50 | BC.readFromFile(path_bc); 51 | BoardDetector BD; 52 | BD.setParams(BC,CP); //or only BD.setParams(BC) 53 | //capture image 54 | cv::Mat im; 55 | capture_image(im); 56 | 57 | float prob=BD.detect(im); 58 | if (prob>0.3) 59 | CvDrawingUtils::draw3DAxis(im,BD.getDetectedBoard(),CP); 60 | 61 | \endcode 62 | * 63 | */ 64 | class ARUCO_EXPORTS BoardDetector { 65 | public: 66 | /** See discussion in @see enableRotateXAxis. 67 | * Do not change unless you know what you are doing 68 | */ 69 | BoardDetector(bool setYPerpendicular = false); 70 | 71 | 72 | /** 73 | * Use if you plan to let this class to perform marker detection too 74 | */ 75 | void setParams(const BoardConfiguration &bc, const CameraParameters &cp, float markerSizeMeters = -1); 76 | void setParams(const BoardConfiguration &bc); 77 | /** 78 | * Detect markers, and then, look for the board indicated in setParams() 79 | * @return value indicating the likelihood of having found the marker 80 | */ 81 | float detect(const cv::Mat &im) throw(cv::Exception); 82 | /**Returns a reference to the board detected 83 | */ 84 | Board &getDetectedBoard() { return _boardDetected; } 85 | /**Returns a reference to the internal marker detector 86 | */ 87 | MarkerDetector &getMarkerDetector() { return _mdetector; } 88 | /**Returns the vector of markers detected 89 | */ 90 | vector< Marker > &getDetectedMarkers() { return _vmarkers; } 91 | 92 | 93 | // ALTERNATIVE DETECTION METHOD, BASED ON MARKERS PREVIOUSLY DETECTED 94 | 95 | /** Given the markers detected, determines if there is the board passed 96 | * @param detectedMarkers result provided by aruco::ArMarkerDetector 97 | * @param BConf the board you want to see if is present 98 | * @param Bdetected output information of the detected board 99 | * @param camMatrix camera matrix with intrinsics 100 | * @param distCoeff camera distorsion coeff 101 | * @param camMatrix intrinsic camera information. 102 | * @param distCoeff camera distorsion coefficient. If set Mat() if is assumed no camera distorion 103 | * @param markerSizeMeters size of the marker sides expressed in meters 104 | * @return value indicating the likelihood of having found the marker 105 | */ 106 | float detect(const vector< Marker > &detectedMarkers, const BoardConfiguration &BConf, Board &Bdetected, cv::Mat camMatrix = cv::Mat(), 107 | cv::Mat distCoeff = cv::Mat(), float markerSizeMeters = -1) throw(cv::Exception); 108 | float detect(const vector< Marker > &detectedMarkers, const BoardConfiguration &BConf, Board &Bdetected, const CameraParameters &cp, 109 | float markerSizeMeters = -1) throw(cv::Exception); 110 | 111 | /**Static version (all in one). Detects the board indicated 112 | * @param Image input image 113 | * @param bc the board you want to see if is present 114 | * @param cp camera parameters 115 | * @param markerSizeMeters size of the marker sides expressed in meters (not needed in the board is expressed in meters) 116 | * @return Board detected 117 | */ 118 | static Board detect(const cv::Mat &Image, const BoardConfiguration &bc, const CameraParameters &cp, float markerSizeMeters = -1); 119 | 120 | /** 121 | * By default, the Y axis is set to point up. However this is not the default 122 | * operation mode of opencv, which produces the Z axis pointing up instead. 123 | * So, to achieve this change, we have to rotate the X axis. 124 | */ 125 | void setYPerpendicular(bool enable) { _setYPerpendicular = enable; } 126 | void setYPerperdicular(bool enable) { setYPerpendicular(enable); } // TODO mark as deprecated 127 | bool isYPerpendicular() { return _setYPerpendicular; } 128 | 129 | /**Sets the threshold for reprjection test. Pixels that after estimating the camera location 130 | * projects 'repj_err_thres' pixels farther from its original location are discarded as outliers. 131 | * By default it is set to -1, meaning that not reprojection test is performed 132 | */ 133 | void set_repj_err_thres(float Repj_err_thres) { repj_err_thres = Repj_err_thres; } 134 | float get_repj_err_thres() const { return repj_err_thres; } 135 | 136 | 137 | private: 138 | void rotateXAxis(cv::Mat &rotation); 139 | bool _setYPerpendicular; 140 | 141 | //-- Functionality to detect markers inside 142 | bool _areParamsSet; 143 | BoardConfiguration _bconf; 144 | Board _boardDetected; 145 | float _markerSize, repj_err_thres; 146 | CameraParameters _camParams; 147 | MarkerDetector _mdetector; // internal markerdetector 148 | vector< Marker > _vmarkers; // markers detected in the call to : float detect(const cv::Mat &im); 149 | }; 150 | }; 151 | #endif 152 | -------------------------------------------------------------------------------- /src/board.h: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | #ifndef _Aruco_board_h 29 | #define _Aruco_board_h 30 | #include 31 | #include 32 | #include 33 | #include "exports.h" 34 | #include "marker.h" 35 | using namespace std; 36 | namespace aruco { 37 | /** 38 | * 3d representation of a marker 39 | */ 40 | struct ARUCO_EXPORTS MarkerInfo : public vector< cv::Point3f > { 41 | MarkerInfo() {} 42 | MarkerInfo(int _id) { id = _id; } 43 | MarkerInfo(const MarkerInfo &MI) : vector< cv::Point3f >(MI) { id = MI.id; } 44 | MarkerInfo &operator=(const MarkerInfo &MI) { 45 | vector< cv::Point3f >::operator=(MI); 46 | id = MI.id; 47 | return *this; 48 | } 49 | int id; // maker id 50 | }; 51 | 52 | /**\brief This class defines a board with several markers. 53 | * A Board contains several markers so that they are more robustly detected. 54 | * 55 | * In general, a board is a set of markers. So BoardConfiguration is only a list 56 | * of the id of the markers along with the position of their corners. 57 | * 58 | * The position of the corners can be specified either in pixels (in a non-specific size) or in meters. 59 | * The first is the typical case in which you generate the image of board and the print it. Since you do not know in advance the real 60 | * size of the markers, their corners are specified in pixels, and then, the translation to meters can be made once you know the real size. 61 | * 62 | * On the other hand, you may want to have the information of your boards in meters. The BoardConfiguration allows you to do so. 63 | * 64 | * The point is in the mInfoType variable. It can be either PIX or METERS according to your needs. 65 | * 66 | */ 67 | 68 | 69 | class ARUCO_EXPORTS BoardConfiguration : public vector< MarkerInfo > { 70 | friend class Board; 71 | 72 | public: 73 | enum MarkerInfoType { 74 | NONE = -1, 75 | PIX = 0, 76 | METERS = 1 77 | }; // indicates if the data in MakersInfo is expressed in meters or in pixels so as to do conversion internally 78 | // variable indicates if the data in MakersInfo is expressed in meters or in pixels so as to do conversion internally 79 | int mInfoType; 80 | /** 81 | */ 82 | BoardConfiguration(); 83 | /**Loads from file 84 | * @param filePath to the config file 85 | */ 86 | BoardConfiguration(string filePath) throw(cv::Exception); 87 | 88 | /** 89 | */ 90 | BoardConfiguration(const BoardConfiguration &T); 91 | 92 | /** 93 | */ 94 | BoardConfiguration &operator=(const BoardConfiguration &T); 95 | /**Saves the board info to a file 96 | */ 97 | void saveToFile(string sfile) throw(cv::Exception); 98 | /**Reads board info from a file 99 | */ 100 | void readFromFile(string sfile) throw(cv::Exception); 101 | /**Indicates if the corners are expressed in meters 102 | */ 103 | bool isExpressedInMeters() const { return mInfoType == METERS; } 104 | /**Indicates if the corners are expressed in meters 105 | */ 106 | bool isExpressedInPixels() const { return mInfoType == PIX; } 107 | /**Returns the index of the marker with id indicated, if is in the list 108 | */ 109 | int getIndexOfMarkerId(int id) const; 110 | /**Returns the Info of the marker with id specified. If not in the set, throws exception 111 | */ 112 | const MarkerInfo &getMarkerInfo(int id) const throw(cv::Exception); 113 | /**Set in the list passed the set of the ids 114 | */ 115 | void getIdList(vector< int > &ids, bool append = true) const; 116 | 117 | private: 118 | /**Saves the board info to a file 119 | */ 120 | void saveToFile(cv::FileStorage &fs) throw(cv::Exception); 121 | /**Reads board info from a file 122 | */ 123 | void readFromFile(cv::FileStorage &fs) throw(cv::Exception); 124 | }; 125 | 126 | /** 127 | */ 128 | class ARUCO_EXPORTS Board : public vector< Marker > { 129 | 130 | public: 131 | BoardConfiguration conf; 132 | // matrices of rotation and translation respect to the camera 133 | cv::Mat Rvec, Tvec; 134 | /** 135 | */ 136 | Board() { 137 | Rvec.create(3, 1, CV_32FC1); 138 | Tvec.create(3, 1, CV_32FC1); 139 | for (int i = 0; i < 3; i++) 140 | Tvec.at< float >(i, 0) = Rvec.at< float >(i, 0) = -999999; 141 | } 142 | 143 | /**Given the extrinsic camera parameters returns the GL_MODELVIEW matrix for opengl. 144 | * Setting this matrix, the reference corrdinate system will be set in this board 145 | */ 146 | void glGetModelViewMatrix(double modelview_matrix[16]) throw(cv::Exception); 147 | 148 | /** 149 | * Returns position vector and orientation quaternion for an Ogre scene node or entity. 150 | * Use: 151 | * ... 152 | * Ogre::Vector3 ogrePos (position[0], position[1], position[2]); 153 | * Ogre::Quaternion ogreOrient (orientation[0], orientation[1], orientation[2], orientation[3]); 154 | * mySceneNode->setPosition( ogrePos ); 155 | * mySceneNode->setOrientation( ogreOrient ); 156 | * ... 157 | */ 158 | void OgreGetPoseParameters(double position[3], double orientation[4]) throw(cv::Exception); 159 | 160 | 161 | /**Save this from a file 162 | */ 163 | void saveToFile(string filePath) throw(cv::Exception); 164 | /**Read this from a file 165 | */ 166 | void readFromFile(string filePath) throw(cv::Exception); 167 | 168 | /**Draws the detected markers 169 | */ 170 | void draw(cv::Mat &im, cv::Scalar color, int lineWidth = 1, bool writeId = true); 171 | }; 172 | } 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /src/cuda_aruco.cu: -------------------------------------------------------------------------------- 1 | #include "cuda_aruco.h" 2 | 3 | #include "cudautils.h" 4 | 5 | 6 | 7 | #include 8 | 9 | std::vector streams; 10 | 11 | struct cbs { 12 | unsigned char* src; 13 | unsigned char* dst; 14 | int width; 15 | int height; 16 | int pitch; 17 | }; 18 | 19 | void CUDART_CB MyCallback(cudaStream_t stream, cudaError_t status, void *data){ 20 | 21 | cbs* s = (cbs*)data; 22 | 23 | for (int y=0; yheight; ++y) { 24 | memcpy(s->dst + y*s->width, s->src + y*s->pitch, s->width); 25 | } 26 | 27 | free(data); 28 | } 29 | 30 | 31 | void cuda_aruco::CudaProcessor::createBuffer(int _width, int _height, 32 | std::vector& _buffers, 33 | int _nimages) { 34 | width = _width; 35 | height = _height; 36 | cudaMallocPitch(&buffer, &pitch, width, height * _nimages); 37 | 38 | _buffers.resize(_nimages); 39 | 40 | for (int i = 0; i < _nimages; ++i) { 41 | _buffers[i].width = width; 42 | _buffers[i].height = height; 43 | _buffers[i].pitch = pitch; 44 | cudaMallocHost(&(_buffers[i].h_data), height*width); 45 | _buffers[i].d_data = &buffer[i * height * pitch]; 46 | _buffers[i].pitch_h = width; 47 | } 48 | 49 | streams.resize(5); 50 | for (int i=0; i<5; ++i) { 51 | cudaStreamCreate(&streams[i]); 52 | } 53 | 54 | } 55 | 56 | void cuda_aruco::CudaProcessor::mallocPitch(void** d, size_t* p, size_t w, size_t h) { 57 | cudaMallocPitch(d,p,w,h); 58 | } 59 | 60 | 61 | void cuda_aruco::CudaProcessor::readbackAndCopy(CudaImage& _src, unsigned char* _dst, int _stream) { 62 | 63 | cudaMemcpy2DAsync(_src.h_data, _src.pitch, _src.d_data, _src.pitch, _src.width, _src.height, cudaMemcpyDeviceToHost, streams[_stream]); 64 | 65 | cbs* s = (cbs*)malloc(sizeof(cbs)); 66 | s->src = _src.h_data; 67 | s->dst = _dst; 68 | s->height = _src.height; 69 | s->width = _src.width; 70 | s->pitch = _src.pitch; 71 | 72 | cudaStreamAddCallback(streams[_stream], MyCallback, (void*)s, 0); 73 | } 74 | 75 | 76 | void cuda_aruco::CudaProcessor::freeBuffer() { cudaFree(buffer); } 77 | 78 | 79 | 80 | void cuda_aruco::CudaProcessor::allocHost(void** _buff, size_t _bytes) { 81 | cudaMallocHost(_buff, _bytes); 82 | } 83 | 84 | 85 | 86 | __global__ void filter_kernel_row(const unsigned char* _src, 87 | float* _dst, int _width, int _height, 88 | int _pitch, size_t _pp) { 89 | 90 | int y = blockDim.y * blockIdx.y + threadIdx.y; 91 | int x = blockDim.x * blockIdx.x + threadIdx.x; 92 | 93 | float p0 = 0.f; 94 | float p1 = 0.f; 95 | float p2 = 0.f; 96 | float p3 = 0.f; 97 | float p4 = 0.f; 98 | 99 | for (int dy = -6; dy <= 6; ++dy) { 100 | int ty = y + dy; 101 | ty = (ty < 0 ? -ty : (ty >= _height ? _height - 1 : ty)); 102 | float val = _src[ty * _pitch + x]; 103 | p4 += val; 104 | if (abs(dy) < 6) p3 += val; 105 | if (abs(dy) < 5) p2 += val; 106 | if (abs(dy) < 4) p1 += val; 107 | if (abs(dy) < 3) p0 += val; 108 | } 109 | 110 | _dst[0 * _pp * _height + y * _pp + x] = p0; 111 | _dst[1 * _pp * _height + y * _pp + x] = p1; 112 | _dst[2 * _pp * _height + y * _pp + x] = p2; 113 | _dst[3 * _pp * _height + y * _pp + x] = p3; 114 | _dst[4 * _pp * _height + y * _pp + x] = p4; 115 | 116 | } 117 | 118 | 119 | 120 | __global__ void filter_kernel_col(const float* _src, 121 | unsigned char* _dst, int _width, int _height, 122 | int _pitch, size_t _pp) { 123 | int y = blockDim.y * blockIdx.y + threadIdx.y; 124 | int x = blockDim.x * blockIdx.x + threadIdx.x; 125 | 126 | float p0 = 0.f; 127 | float p1 = 0.f; 128 | float p2 = 0.f; 129 | float p3 = 0.f; 130 | float p4 = 0.f; 131 | 132 | for (int dx = -6; dx <= 6; ++dx) { 133 | int tx = x + dx; 134 | tx = (tx < 0 ? -tx : (tx >= _width ? _width - 1 : tx)); 135 | p4 += _src[4 * _pp * _height + y * _pp + tx]; 136 | if (abs(dx) < 6) p3 += _src[3 * _pp * _height + y * _pp + tx]; 137 | if (abs(dx) < 5) p2 += _src[2 * _pp * _height + y * _pp + tx]; 138 | if (abs(dx) < 4) p1 += _src[1 * _pp * _height + y * _pp + tx]; 139 | if (abs(dx) < 3) p0 += _src[0 * _pp * _height + y * _pp + tx]; 140 | } 141 | 142 | _dst[0*_pitch*_height + y*_pitch+x] = (unsigned char)(p0 * 1.f / (5.f * 5.f) + .5f); 143 | _dst[1*_pitch*_height + y*_pitch+x] = (unsigned char)(p1 * 1.f / (7.f * 7.f) + .5f); 144 | _dst[2*_pitch*_height + y*_pitch+x] = (unsigned char)(p2 * 1.f / (9.f * 9.f) + .5f); 145 | _dst[3*_pitch*_height + y*_pitch+x] = (unsigned char)(p3 * 1.f / (11.f * 11.f) + .5f); 146 | _dst[4*_pitch*_height + y*_pitch+x] = (unsigned char)(p4 * 1.f / (13.f * 13.f) + .5f); 147 | 148 | } 149 | 150 | 151 | 152 | __global__ void filter_kernel(const unsigned char* _src, unsigned char* _dst, 153 | int _width, int _height, int _pitch) { 154 | int y = blockDim.y * blockIdx.y + threadIdx.y; 155 | int x = blockDim.x * blockIdx.x + threadIdx.x; 156 | 157 | float p0 = 0.f; 158 | float p1 = 0.f; 159 | float p2 = 0.f; 160 | float p3 = 0.f; 161 | float p4 = 0.f; 162 | 163 | if (y < _height && x < _width) { 164 | 165 | for (int dy = -6; dy <= 6; ++dy) { 166 | int ty = y + dy; 167 | ty = (ty < 0 ? -ty : (ty >= _height ? _height - 1 : ty)); 168 | for (int dx = -6; dx <= 6; ++dx) { 169 | int tx = x + dx; 170 | tx = (tx < 0 ? -tx : (tx >= _width ? _width - 1 : tx)); 171 | p4 += _src[ty * _pitch + tx]; 172 | if (abs(dx) < 6 && abs(dy) < 6) p3 += _src[ty * _pitch + tx]; 173 | if (abs(dx) < 5 && abs(dy) < 5) p2 += _src[ty * _pitch + tx]; 174 | if (abs(dx) < 4 && abs(dy) < 4) p1 += _src[ty * _pitch + tx]; 175 | if (abs(dx) < 3 && abs(dy) < 3) p0 += _src[ty * _pitch + tx]; 176 | } 177 | } 178 | 179 | p0 *= 1.f / (5.f * 5.f); 180 | p1 *= 1.f / (7.f * 7.f); 181 | p2 *= 1.f / (9.f * 9.f); 182 | p3 *= 1.f / (11.f * 11.f); 183 | p4 *= 1.f / (13.f * 13.f); 184 | 185 | _dst[0 * _pitch * _height + y * _pitch + x] = (unsigned char)(p0 + .5f); 186 | _dst[1 * _pitch * _height + y * _pitch + x] = (unsigned char)(p1 + .5f); 187 | _dst[2 * _pitch * _height + y * _pitch + x] = (unsigned char)(p2 + .5f); 188 | _dst[3 * _pitch * _height + y * _pitch + x] = (unsigned char)(p3 + .5f); 189 | _dst[4 * _pitch * _height + y * _pitch + x] = (unsigned char)(p4 + .5f); 190 | } 191 | } 192 | 193 | __global__ void threshold_kernel(const unsigned char* _src, unsigned char* _dst, 194 | int _width, int _height, int _pitch, 195 | double _param) { 196 | int y = blockDim.y * blockIdx.y + threadIdx.y; 197 | int x = blockDim.x * blockIdx.x + threadIdx.x; 198 | 199 | if (y < _height && x < _width) { 200 | #pragma unroll 201 | for (int i = 0; i < 5; ++i) 202 | _dst[i * _pitch * _height + y * _pitch + x] = 203 | _src[y * _pitch + x] > _dst[i * _pitch * _height + y * _pitch + x] - _param 204 | ? 0 205 | : 255; 206 | } 207 | } 208 | 209 | void cuda_aruco::CudaProcessor::sync(int i) { 210 | if (i==-1) 211 | cudaDeviceSynchronize(); 212 | else 213 | cudaStreamSynchronize(streams[i]); 214 | } 215 | 216 | void cuda_aruco::CudaProcessor::cuda_threshold(CudaImage& _src, float* _tmp, size_t _pp, 217 | CudaImage& _dst, double* t1, 218 | double t2) { 219 | // Set device to prioritize cache 220 | // cudaFuncSetCacheConfig(filter_kernel, cudaFuncCachePreferL1); 221 | 222 | dim3 blocks(iDivUp(width, 16), iDivUp(height, 16)); 223 | dim3 threads(16, 16); 224 | filter_kernel_row<<>> 225 | (_src.d_data, _tmp, width, height, pitch, _pp); 226 | filter_kernel_col<<>> 227 | (_tmp, _dst.d_data, width, height, pitch, _pp); 228 | /* filter_kernel<< >> 229 | (_src.d_data, _dst.d_data, width, height, pitch);*/ 230 | 231 | threshold_kernel<<>> 232 | (_src.d_data, _dst.d_data, width, height, pitch, t2); 233 | } 234 | -------------------------------------------------------------------------------- /src/aruco.h: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are 6 | permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | of conditions and the following disclaimer in the documentation and/or other materials 13 | provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 16 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 17 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 18 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 22 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | The views and conclusions contained in the software and documentation are those of the 26 | authors and should not be interpreted as representing official policies, either expressed 27 | or implied, of Rafael Muñoz Salinas. 28 | 29 | 30 | 31 | \mainpage ArUco: Augmented Reality library from the University of Cordoba 32 | 33 | 34 | ArUco is a minimal C++ library for detection of Augmented Reality markers based on OpenCv exclusively. 35 | 36 | It is an educational project to show student how to detect augmented reality markers and it is provided under BSD license. 37 | 38 | 39 | \section INTRODUCTION INTRODUCTION 40 | 41 | The library relies on the use of coded markers. Each marker has an unique code indicated by the black and white colors in it. The libary detect borders, and 42 | analyzes into the rectangular regions which of them are likely to be markers. Then, a decoding is performed and if the code is valid, it is considered that the 43 | rectangle is a marker. 44 | 45 | The codification included into the marker is a slighly modified version of the Hamming Code. It has a total a 25 bits didived in 5 rows of 5 bits each. So, we 46 | have 5 words of 5 bits. Each word, contains only 2 bits of real information, the rest is for and error detection/correction (error correction is yet to be 47 | done). As a conclusion, a marker contains 10 bits of real information wich allows 1024 different markers. 48 | 49 | 50 | \section BOARDS BOARDS 51 | 52 | Aruco allows the possibility to employ board. Boards are markers composed by an array of markers arranged in a known order. The advantages of using boards 53 | instead of simple markers are: 54 | - More robusteness. The misdetection of several markers of the board is not a problem as long as a minimum set of them are detected. 55 | - More precision. Since there are a larger number of corners, camera pose estimation becomes more precise. 56 | 57 | 58 | \section APPLICATIONS APPLICATIONS 59 | 60 | The library comes with five applications that will help you to learn how to use the library: 61 | - aruco_create_marker: which creates marker and saves it in a jpg file you can print. 62 | - aruco_simple : simple test aplication that detects the markers in a image 63 | - aruco_test: this is the main application for detection. It reads images either from the camera of from a video and detect markers. Additionally, if you 64 | provide the intrinsics of the camera(obtained by OpenCv calibration) and the size of the marker in meters, the library calculates the marker intrinsics so that 65 | you can easily create your AR applications. 66 | - aruco_test_gl: shows how to use the library AR applications using OpenGL for rendering 67 | - aruco_create_board: application that helps you to create a board 68 | - aruco_simple_board: simple test aplication that detects a board of markers in a image 69 | - aruco_test_board: application that detects boards 70 | - aruco_test_board_gl: application that detects boards and uses OpenGL to draw 71 | 72 | \section LIBRARY LIBRARY DESCRIPTION: 73 | 74 | The ArUco library contents are divided in two main directories. The src directory, which contains the library itself. And the utils directory which contains the 75 | applications. 76 | 77 | The library main classes are: 78 | - aruco::CameraParameters: represent the information of the camera that captures the images. Here you must set the calibration info. 79 | - aruco::Marker: which represent a marker detected in the image 80 | - aruco::MarkerDetector: that is in charge of deteting the markers in a image Detection is done by simple calling the member funcion 81 | ArMarkerDetector::detect(). Additionally, the classes contain members to create the required matrices for rendering using OpenGL. See aruco_test_gl for details 82 | - aruco::BoardConfiguration: A board is an array of markers in a known order. BoardConfiguracion is the class that defines a board by indicating the id of 83 | its markers. In addition, it has informacion about the distance between the markers so that extrinsica camera computations can be done. 84 | - aruco::Board: This class defines a board detected in a image. The board has the extrinsic camera parameters as public atributes. In addition, it has a 85 | method that allows obtain the matrix for getting its position in OpenGL (see aruco_test_board_gl for details). 86 | - aruco::BoardDetector : This is the class in charge of detecting a board in a image. You must pass to it the set of markers detected by ArMarkerDetector and 87 | the BoardConfiguracion of the board you want to detect. This class will do the rest for you, even calculating the camera extrinsics. 88 | 89 | 90 | \section COMPILING COMPILING THE LIBRARY: 91 | \subsection Linux 92 | Go to the aruco library and do 93 | \verbatim 94 | >mkdir build 95 | >cd build 96 | >cmake .. 97 | >make 98 | >make install (optional) 99 | \endverbatim 100 | 101 | NOTE ON OPENGL: The library supports eaily the integration with OpenGL. In order to compile with support for OpenGL, you just have installed in your system the 102 | develop packages for GL and glut (or freeglut). 103 | 104 | \subsection WINDOWS 105 | 106 | The library has been compiled using MinGW and codeblocks. Below I describe the best way to compile it that I know. If you know better, please let me know. 107 | - step 1) codeblocks 108 | -# Download codeblocks. I recommend to download the version 10.5 with mingw included (codeblocks-10.05mingw-setup.exe) 109 | -# Install and set the PATH variable so that the codeblock/mingw/bin directory is included. In my case c:/codeblocks/mingw/bin. This will allow cmake to 110 | find the compiler. 111 | -# The codeblock program will not find the mingw path by deafult. So, run codeblocks and go to setting->Compuiler debugger and set the correct path to the 112 | MinGW dir. 113 | - step 2) cmake 114 | -# Download and install the last version of cmake. 115 | - step 3) OpenCv 116 | -# Download the source code and compile it using cmake and codeblocks. Note: install the library in C:\ if you want it to be easily detected by cmake 117 | afterwards 118 | - step 4) aruco 119 | -# Download and decompress. 120 | -# Open cmake gui application and set the path to the main library directory and also set a path where the project is going to be built. 121 | -# Generate the codeblock project. 122 | -# Open the project with codeblock and compile then, install. The programs will be probably generated into the bin directory 123 | 124 | OpenGL: by default, the mingw version installed has not the glut library. So, the opengl programs are not compiled. If you want to compile with OpenGL support, 125 | you must install glut, or prefereably freeglut. 126 | Thus, 127 | - Download the library (http://www.martinpayne.me.uk/software/development/GLUT/freeglut-MinGW.zip) for mingw. 128 | - Decompress in a directory X. 129 | - Then, rerun cmake setting the variable GLU_PATH to that directory (>cmake .. -DGLUT_PATH="C:\X") 130 | - Finally, recompile and test. Indeed, you should move the freeglut.dll to the directory with the binaries or to any other place in the PATH. 131 | 132 | 133 | CONCLUSION: Move to Linux, things are simpler :P 134 | 135 | 136 | \section Testing 137 | 138 | For testing the applications, the library provides videos and the corresponding camera parameters of these videos. Into the directories you will find 139 | information on how to run the examples. 140 | 141 | \section Final Notes 142 | 143 | - REQUIREMENTS: OpenCv >= 2.1.0. and OpenGL for (aruco_test_gl and aruco_test_board_gl) 144 | - CONTACT: Rafael Munoz-Salinas: rmsalinas@uco.es 145 | - This libary is free software and come with no guaratee! 146 | 147 | */ 148 | 149 | #include "markerdetector.h" 150 | #include "boarddetector.h" 151 | #include "cvdrawingutils.h" 152 | -------------------------------------------------------------------------------- /utils/aruco_selectoptimalmarkers.cpp: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | /**** 29 | * Select the n best markers according to their distance. In other words, selects the n farthert markers in terms of hamming distance 30 | * 31 | * 32 | * 33 | *****/ 34 | 35 | #include 36 | #include "aruco.h" 37 | #include 38 | #include 39 | #include "arucofidmarkers.h" 40 | using namespace cv; 41 | using namespace std; 42 | 43 | int HammDist_(const cv::Mat &m1, const cv::Mat &m2) { 44 | 45 | int dist = 0; 46 | for (int y = 0; y < 5; y++) 47 | for (int x = 0; x < 5; x++) 48 | if (m1.at< uchar >(y, x) != m2.at< uchar >(y, x)) 49 | dist++; 50 | return dist; 51 | } 52 | Mat rotate(Mat in) { 53 | Mat out; 54 | in.copyTo(out); 55 | for (int i = 0; i < in.rows; i++) { 56 | for (int j = 0; j < in.cols; j++) { 57 | out.at< uchar >(i, j) = in.at< uchar >(in.cols - j - 1, i); 58 | } 59 | } 60 | return out; 61 | } 62 | 63 | 64 | int HammDist(const cv::Mat &m1, const cv::Mat &m2) { 65 | cv::Mat mc = m1.clone(); 66 | int minD = std::numeric_limits< int >::max(); 67 | for (int i = 0; i < 4; i++) { 68 | int dist = HammDist_(mc, m2); 69 | if (dist < minD) 70 | minD = dist; 71 | mc = rotate(mc); 72 | } 73 | return minD; 74 | } 75 | 76 | int entropy(const cv::Mat &marker) { 77 | 78 | // the entropy is calcualte for each bin as the number of elements different from it in its sourroundings 79 | int totalEntropy = 0; 80 | for (int y = 0; y < 5; y++) 81 | for (int x = 0; x < 5; x++) { 82 | int minX = max(x - 1, 0); 83 | int maxX = min(x + 1, 5); 84 | int minY = max(y - 1, 0); 85 | int maxY = min(y + 1, 5); 86 | 87 | for (int yy = minY; yy < maxY; yy++) 88 | for (int xx = minX; xx < maxX; xx++) 89 | if (marker.at< uchar >(y, x) != marker.at< uchar >(yy, xx)) 90 | totalEntropy++; 91 | } 92 | 93 | return totalEntropy; 94 | } 95 | // return the index of the param or -1 if not found 96 | int findParam(std::string param, int argc, char *argv[]) { 97 | for (int i = 0; i < argc; i++) 98 | if (string(argv[i]) == param) 99 | return i; 100 | 101 | return -1; 102 | } 103 | 104 | int main(int argc, char **argv) { 105 | try { 106 | if (argc < 4) { 107 | 108 | // You can also use ids 2000-2007 but it is not safe since there are a lot of false positives. 109 | cerr << "Usage: nofMarkers outbasename size [minimum_entropy(9,25)] [-locked ] " << endl; 110 | return -1; 111 | } 112 | 113 | bool locked = findParam("-locked", argc, argv) != -1; // if found, true 114 | 115 | // create a vector with all markers 116 | int minimimEntropy = 0; 117 | if (argc >= 5) 118 | minimimEntropy = atoi(argv[4]); 119 | vector< cv::Mat > markers; 120 | vector< int > ventropy; 121 | for (int i = 0; i < 1024; i++) { 122 | markers.push_back(aruco::FiducidalMarkers::getMarkerMat(i)); 123 | ventropy.push_back(entropy(aruco::FiducidalMarkers::getMarkerMat(i))); 124 | } 125 | cout << "Calculating distance matrix" << endl; 126 | // create a matrix with all distances 127 | cv::Mat distances = cv::Mat::zeros(1024, 1024, CV_32SC1); 128 | for (int i = 0; i < 1024; i++) 129 | for (int j = i + 1; j < 1024; j++) 130 | distances.at< int >(i, j) = distances.at< int >(j, i) = HammDist(markers[i], markers[j]); 131 | cout << "done" << endl; 132 | // 133 | int nMarkers = atoi(argv[1]); 134 | // select the first marker 135 | vector< bool > usedMarkers(1024, false); 136 | 137 | 138 | 139 | vector< int > selectedMarkers; 140 | // select the masker with higher entropy first 141 | int bestEntr = 0; 142 | for (size_t i = 0; i < ventropy.size(); i++) 143 | if (ventropy[i] > ventropy[bestEntr]) 144 | bestEntr = i; 145 | selectedMarkers.push_back(bestEntr); 146 | usedMarkers[bestEntr] = true; 147 | 148 | // remove these with low entropy. Not very elegnat. Other day I will improve the algorithm 149 | // to make it multiobjective 150 | for (size_t i = 0; i < ventropy.size(); i++) 151 | if (ventropy[i] < minimimEntropy) 152 | usedMarkers[i] = true; 153 | 154 | cout << "Max Entroy in =" << bestEntr << " " << ventropy[bestEntr] << endl; 155 | // add new markers according to the distance added to the global 156 | for (int i = 1; i < nMarkers; i++) { 157 | int bestMarker = -1; 158 | int shorterDist = 0; 159 | // select as new marker the one that maximizes mean distance to 160 | for (int j = 0; j < distances.cols; j++) { 161 | if (!usedMarkers[j]) { 162 | int minDist = std::numeric_limits< int >::max(); 163 | for (size_t k = 0; k < selectedMarkers.size(); k++) 164 | if (distances.at< int >(selectedMarkers[k], j) < minDist) 165 | minDist = distances.at< int >(selectedMarkers[k], j); 166 | // cout<<"j="< shorterDist) { 168 | shorterDist = minDist; 169 | bestMarker = j; 170 | } 171 | } 172 | } 173 | if (bestMarker != -1 && shorterDist > 1) { 174 | selectedMarkers.push_back(bestMarker); 175 | usedMarkers[bestMarker] = true; 176 | // cout<<"Best id="<>c; 182 | } 183 | 184 | sort(selectedMarkers.begin(), selectedMarkers.end()); 185 | for (size_t i = 0; i < selectedMarkers.size(); i++) { 186 | char name[1024]; 187 | sprintf(name, "%s%d.png", argv[2], selectedMarkers[i]); 188 | // cout<<"name="<::max(); 196 | for (size_t i = 0; i < selectedMarkers.size() - 1; i++) 197 | for (size_t j = i + 1; j < selectedMarkers.size(); j++) { 198 | // cout<<" d=" << selectedMarkers[i]<<" "<"< ( selectedMarkers[i], selectedMarkers[j])<(selectedMarkers[i], selectedMarkers[j]) < minDist) 200 | minDist = distances.at< int >(selectedMarkers[i], selectedMarkers[j]); 201 | } 202 | 203 | 204 | cout << "Min Dist=" << minDist << endl; 205 | 206 | } catch (std::exception &ex) { 207 | cout << ex.what() << endl; 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /utils/aruco_test_gl.cpp: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | #include 29 | 30 | #include 31 | #include 32 | #ifdef __APPLE__ 33 | #include 34 | #else 35 | #include 36 | #include 37 | #endif 38 | #include 39 | #include 40 | #include "aruco.h" 41 | using namespace cv; 42 | using namespace aruco; 43 | 44 | string TheInputVideo; 45 | string TheIntrinsicFile; 46 | bool The3DInfoAvailable=false; 47 | float TheMarkerSize=-1; 48 | MarkerDetector PPDetector; 49 | VideoCapture TheVideoCapturer; 50 | vector TheMarkers; 51 | Mat TheInputImage,TheUndInputImage,TheResizedImage; 52 | CameraParameters TheCameraParams; 53 | Size TheGlWindowSize; 54 | bool TheCaptureFlag=true; 55 | bool readIntrinsicFile(string TheIntrinsicFile,Mat & TheIntriscCameraMatrix,Mat &TheDistorsionCameraParams,Size size); 56 | 57 | void vDrawScene(); 58 | void vIdle(); 59 | void vResize( GLsizei iWidth, GLsizei iHeight ); 60 | void vMouse(int b,int s,int x,int y); 61 | 62 | 63 | /************************************ 64 | * 65 | * 66 | * 67 | * 68 | ************************************/ 69 | 70 | bool readArguments ( int argc,char **argv ) 71 | { 72 | if (argc!=4) { 73 | cerr<<"Invalid number of arguments"<>TheInputImage; 108 | //read camera paramters if passed 109 | TheCameraParams.readFromXMLFile(TheIntrinsicFile); 110 | TheCameraParams.resize(TheInputImage.size()); 111 | 112 | glutInit(&argc, argv); 113 | glutInitWindowPosition( 0, 0); 114 | glutInitWindowSize(TheInputImage.size().width,TheInputImage.size().height); 115 | glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE ); 116 | glutCreateWindow( "AruCo" ); 117 | glutDisplayFunc( vDrawScene ); 118 | glutIdleFunc( vIdle ); 119 | glutReshapeFunc( vResize ); 120 | glutMouseFunc(vMouse); 121 | glClearColor( 0.0, 0.0, 0.0, 1.0 ); 122 | glClearDepth( 1.0 ); 123 | TheGlWindowSize=TheInputImage.size(); 124 | vResize(TheGlWindowSize.width,TheGlWindowSize.height); 125 | glutMainLoop(); 126 | 127 | } catch (std::exception &ex) 128 | 129 | { 130 | cout<<"Exception :"<= 2.4.9, cmake >= 2.8 84 | OPTIONAL: OpenGL for aruco_test_gl and aruco_test_board_gl 85 | 86 | \subsection LINUX: 87 | 88 | Go to the aruco library and do 89 | >mkdir build 90 | >cd build 91 | >cmake .. 92 | >make 93 | >make install (optional) 94 | 95 | NOTE ON OPENGL: The library supports eaily the integration with OpenGL. In order to compile with support for OpenGL, you just have installed in your system the develop packages for GL and glut (or freeglut). 96 | 97 | \subsection WINDOWS 98 | 99 | We have successfully compiled in in two compilers: MSVC2010 and MinGW. 100 | In both cases cmake and OpenCv are required first. So install them 101 | 102 | 103 | \subsubsection Microsoft Visual C++ (Express Edition 2010) 104 | 105 | a) Downdload MSVC 2010 (http://www.microsoft.com/visualstudio/en-us/products/2010-editions/express). 106 | b) Use cmake to create the project. Compile and run! 107 | 108 | \subsubsection MinGW and codeblocks 109 | 110 | The library has been compiled using MinGW and codeblocks. Below I describe the best way to compile it that I know. If you know better, please let me know. 111 | 112 | step 1) codeblocks 113 | -# Download codeblocks. I recommend to download the version 10.5 with mingw included (codeblocks-10.05mingw-setup.exe) 114 | -# Install and set the PATH variable so that the codeblock/mingw/bin directory is included. In my case "c:\codeblocks\mingw\bin". This will allow cmake to find the compiler. 115 | -# The codeblock program will not find the mingw path by deafult. So, run codeblocks and go to setting->Compuiler debugger and set the correct path to the MinGW dir. 116 | 117 | step 2) aruco 118 | -# download and decompress. 119 | -# Open cmake gui application and set the path to the main library directory and also set a path where the project is going to be built. Generate the codeblock project. 120 | -# Open the project with codeblock and compile then, install. The programs will be probably generated into the bin directory 121 | 122 | 123 | OpenGL: by default, the mingw version installed has not the glut library. SO, the opengl programs are not compiled. If you want to compile with OpenGL support, you must install glut, or prefereably freeglut. 124 | So, download the library (http://www.martinpayne.me.uk/software/development/GLUT/freeglut-MinGW.zip) for mingw. Decompress in a directory X. Then, rerun cmake setting the variable GLU_PATH to that directory 125 | >cmake .. -DGLUT_PATH="C:\x" 126 | Finally, recompile and test. Indeed, you should move the freeglut.dll to the directory with the binaries or to any other place in the PATH. 127 | 128 | \section Testing 129 | 130 | For testing the applications, the library provides videos and the corresponding camera parameters of these videos. Into the directories you will find information on how to run the examples. 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /utils/aruco_calibration.cpp: -------------------------------------------------------------------------------- 1 | // Automatic camera calibration using an aruco board only 2 | // The board must be expressed in meters (use aruco_board_pix2meters) 3 | 4 | // You must move the camera around the board and the program automatically detects it and recalibrate camera 5 | // Not all he detections are employed for calibration, we create store viewpoints at a given distance between thems 6 | 7 | #include "boarddetector.h" 8 | #include "board.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | cv::VideoCapture TheVideoCapturer; 15 | 16 | aruco::BoardConfiguration TheBoardConfig; 17 | aruco::BoardDetector TheBoardDetector; 18 | cv::Mat TheInputImage; 19 | aruco::CameraParameters TheCamParams; 20 | std::vector< cv::Mat > The_rvecs, The_tvecs; // locations at which calibration is done 21 | std::vector< vector< cv::Point2f > > TheimagePointsV; 22 | std::vector< vector< cv::Point3f > > TheobjPointsV; // image and obj points at which calibration is done 23 | float ViewPointDistance = 0.025; 24 | using namespace std; 25 | 26 | 27 | // returns an initial dummy camera parameters 28 | aruco::CameraParameters getDummyInitialCameraParams(cv::Size imageSize) { 29 | aruco::CameraParameters Cp; 30 | cv::Mat CamMatrix = cv::Mat::eye(3, 3, CV_32F); 31 | CamMatrix.at< float >(0, 0) = 500; 32 | CamMatrix.at< float >(1, 1) = 500; 33 | CamMatrix.at< float >(0, 2) = imageSize.width / 2; 34 | CamMatrix.at< float >(1, 2) = imageSize.height / 2; 35 | Cp.setParams(CamMatrix, cv::Mat::zeros(1, 5, CV_32F), imageSize); 36 | return Cp; 37 | } 38 | 39 | 40 | // computes minimum distance of T to elements in The_tvecs 41 | float minDistanceToStoredLocations(cv::Mat T) { 42 | // normalize R 43 | float minDist = std::numeric_limits< float >::max(); 44 | for (size_t i = 0; i < The_tvecs.size(); i++) { 45 | // first, normalize the vector of R 46 | 47 | float norm = cv::norm(T - The_tvecs[i]); 48 | if (norm < minDist) 49 | minDist = norm; 50 | // now, check norm 51 | } 52 | 53 | return minDist; 54 | } 55 | // inclusion of new points to compute 56 | void setCurrentViewPoint(vector< cv::Point3f > &objPoints, vector< cv::Point2f > &imagePoints) { 57 | cv::Mat Rvec, Tvec; 58 | // get the current location given the points 59 | cv::solvePnP(objPoints, imagePoints, TheCamParams.CameraMatrix, TheCamParams.Distorsion, Rvec, Tvec); 60 | // check the minimum distance to the rest of valid locations 61 | // cerr<<"Tvec="< ViewPointDistance) { 63 | cerr << "Adding new view point" << endl; 64 | // addToPool(imagePoints,objPoints); 65 | // add the points to calculate the camera params 66 | TheimagePointsV.push_back(imagePoints); 67 | TheobjPointsV.push_back(objPoints); 68 | The_tvecs.push_back(Tvec); 69 | The_rvecs.push_back(Rvec); 70 | // char c;cin>>c; 71 | if (TheobjPointsV.size() >= 3 && TheobjPointsV.size() < 8) { 72 | // now, calibrate camera 73 | float repro = cv::calibrateCamera(TheobjPointsV, TheimagePointsV, TheCamParams.CamSize, TheCamParams.CameraMatrix, TheCamParams.Distorsion, 74 | The_rvecs, The_tvecs); 75 | cerr << "Recalibared: " << repro << endl; 76 | cerr << TheCamParams.CameraMatrix << " " << endl << TheCamParams.Distorsion << endl; 77 | } 78 | } 79 | } 80 | // void getObjectAndImagePoints(aruco::Board &B, cv::Mat &objPoints,cv::Mat &imagePoints) { 81 | // //composes the matrices 82 | // int nPoints=B.size()*4; 83 | // 84 | // imagePoints.create(nPoints,1,CV_32FC2); 85 | // objPoints.create(nPoints,1,CV_32FC3); 86 | // int cIdx=0; 87 | // for (size_t i=0;i(0)[cIdx]= B[i][j]; 91 | // objPoints.ptr(0)[cIdx]= mInfo[j]; 92 | // } 93 | // } 94 | // 95 | // } 96 | void getObjectAndImagePoints(aruco::Board &B, vector< cv::Point3f > &objPoints, vector< cv::Point2f > &imagePoints) { 97 | // composes the matrices 98 | int nPoints = B.size() * 4; 99 | 100 | int cIdx = 0; 101 | for (size_t i = 0; i < B.size(); i++) { 102 | const aruco::MarkerInfo &mInfo = B.conf.getMarkerInfo(B[i].id); 103 | for (int j = 0; j < 4; j++, cIdx++) { 104 | imagePoints.push_back(B[i][j]); 105 | objPoints.push_back(mInfo[j]); 106 | } 107 | } 108 | } 109 | int main(int argc, char **argv) { 110 | 111 | 112 | try { 113 | if (argc < 4) { 114 | cerr << "Usage : (in.avi|live) board_in_meters.yml out_camera_params.yml [viewPointDist (default 0.025)]\n"; 115 | return -1; 116 | } 117 | 118 | // extra param? 119 | if (argc >= 5) { 120 | ViewPointDistance = atof(argv[4]); 121 | cerr << "Using view point distance=" << ViewPointDistance << endl; 122 | } 123 | 124 | // Open video stream 125 | if (string(argv[1]) == "live") 126 | TheVideoCapturer.open(0); 127 | else 128 | TheVideoCapturer.open(argv[1]); 129 | if (!TheVideoCapturer.isOpened()) { 130 | cerr << "Could not open video" << endl; 131 | return -1; 132 | } 133 | // assume an initial camera params 134 | // capture first image to do so and get the image size 135 | TheVideoCapturer.grab(); 136 | TheVideoCapturer.retrieve(TheInputImage); 137 | TheCamParams = getDummyInitialCameraParams(TheInputImage.size()); 138 | // TheCalibrator.setParams(TheInputImage.size()); 139 | // load config file 140 | TheBoardConfig.readFromFile(argv[2]); 141 | TheBoardDetector.setParams(TheBoardConfig); 142 | TheBoardDetector.getMarkerDetector().setCornerRefinementMethod(aruco::MarkerDetector::SUBPIX); 143 | // let's go! until wnd of file or ESC pressed 144 | char key = 0; 145 | 146 | while (TheVideoCapturer.grab() && key != 27) { // 147 | TheVideoCapturer.retrieve(TheInputImage); 148 | // detect 149 | float prob = TheBoardDetector.detect(TheInputImage); 150 | for (size_t i = 0; i < TheBoardDetector.getDetectedBoard().size(); i++) 151 | TheBoardDetector.getDetectedBoard()[i].draw(TheInputImage, cv::Scalar(0, 0, 255)); 152 | cv::imshow("image", TheInputImage); 153 | key = cv::waitKey(10); 154 | if (prob > 0.2) { 155 | // lets add the detection 156 | vector< cv::Point3f > objPoints; 157 | vector< cv::Point2f > imgPoints; 158 | getObjectAndImagePoints(TheBoardDetector.getDetectedBoard(), objPoints, imgPoints); 159 | setCurrentViewPoint(objPoints, imgPoints); 160 | } 161 | } 162 | 163 | // do the final calibration with all images 164 | if (TheobjPointsV.size() >= 3) { 165 | cerr << "Performing final calibration with the " << TheobjPointsV.size() << " images selected. It migth take a little while" << endl; 166 | float repro = cv::calibrateCamera(TheobjPointsV, TheimagePointsV, TheCamParams.CamSize, TheCamParams.CameraMatrix, TheCamParams.Distorsion, 167 | The_rvecs, The_tvecs); 168 | cerr << "Recalibared: " << repro << endl; 169 | cerr << TheCamParams.CameraMatrix << " " << endl << TheCamParams.Distorsion << endl; 170 | // do a refinement using these with low reprjection error 171 | vector< cv::Point2f > reprj; 172 | int nToRemove = 0, nTotal = 0; 173 | vector< vector< bool > > toRemove(TheobjPointsV.size()); 174 | for (size_t i = 0; i < TheobjPointsV.size(); i++) { 175 | cv::projectPoints(TheobjPointsV[i], The_rvecs[i], The_tvecs[i], TheCamParams.CameraMatrix, TheCamParams.Distorsion, reprj); 176 | toRemove[i].resize(TheobjPointsV[i].size(), false); 177 | for (size_t j = 0; j < TheimagePointsV.size(); j++, nTotal++) { 178 | if (cv::norm(reprj[j] - TheimagePointsV[i][j]) > 0.99) { 179 | toRemove[i][j] = true; 180 | nToRemove++; 181 | } 182 | } 183 | } 184 | cout << "Total o " << nToRemove << " outliers of " << nTotal << " total points" << endl; 185 | // now, copy only the good ones 186 | vector< vector< cv::Point3f > > ob3d(TheobjPointsV.size()); 187 | vector< vector< cv::Point2f > > ob2d(TheobjPointsV.size()); 188 | for (size_t i = 0; i < TheobjPointsV.size(); i++) { 189 | for (size_t j = 0; j < TheimagePointsV[i].size(); j++) { 190 | if (!toRemove[i][j]) { 191 | ob3d[i].push_back(TheobjPointsV[i][j]); 192 | ob2d[i].push_back(TheimagePointsV[i][j]); 193 | } 194 | } 195 | } 196 | 197 | // repeating calibration without outliers 198 | cerr << "Performing final calibration with the " << TheobjPointsV.size() << " images selected. It migth take a little while" << endl; 199 | repro = cv::calibrateCamera(ob3d, ob2d, TheCamParams.CamSize, TheCamParams.CameraMatrix, TheCamParams.Distorsion, The_rvecs, The_tvecs); 200 | cerr << "Recalibared: " << repro << endl; 201 | cerr << TheCamParams.CameraMatrix << " " << endl << TheCamParams.Distorsion << endl; 202 | 203 | 204 | TheCamParams.saveToFile(argv[3]); 205 | } 206 | 207 | 208 | 209 | } catch (std::exception &ex) { 210 | cout << ex.what() << endl; 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /utils/aruco_test_board.cpp: -------------------------------------------------------------------------------- 1 | /***************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************/ 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "aruco.h" 34 | using namespace cv; 35 | using namespace aruco; 36 | 37 | string TheInputVideo; 38 | string TheIntrinsicFile; 39 | string TheBoardConfigFile; 40 | bool The3DInfoAvailable = false; 41 | float TheMarkerSize = -1; 42 | VideoCapture TheVideoCapturer; 43 | Mat TheInputImage, TheInputImageCopy; 44 | CameraParameters TheCameraParameters; 45 | BoardConfiguration TheBoardConfig; 46 | BoardDetector TheBoardDetector; 47 | 48 | string TheOutVideoFilePath; 49 | cv::VideoWriter VWriter; 50 | 51 | void cvTackBarEvents(int pos, void *); 52 | pair< double, double > AvrgTime(0, 0); // determines the average time required for detection 53 | double ThresParam1, ThresParam2; 54 | int iThresParam1, iThresParam2; 55 | int waitTime = 0; 56 | 57 | 58 | 59 | 60 | /************************************ 61 | * 62 | * 63 | * 64 | * 65 | ************************************/ 66 | 67 | bool readArguments(int argc, char **argv) { 68 | 69 | if (argc < 3) { 70 | cerr << "Invalid number of arguments" << endl; 71 | cerr << "Usage: (in.avi|live) boardConfig.yml [intrinsics.yml] [size] [out]" << endl; 72 | return false; 73 | } 74 | TheInputVideo = argv[1]; 75 | TheBoardConfigFile = argv[2]; 76 | if (argc >= 4) 77 | TheIntrinsicFile = argv[3]; 78 | if (argc >= 5) 79 | TheMarkerSize = atof(argv[4]); 80 | if (argc >= 6) 81 | TheOutVideoFilePath = argv[5]; 82 | 83 | 84 | if (argc == 4) 85 | cerr << "NOTE: You need makersize to see 3d info!!!!" << endl; 86 | 87 | return true; 88 | } 89 | 90 | void processKey(char k) { 91 | switch (k) { 92 | case 's': 93 | if (waitTime == 0) 94 | waitTime = 10; 95 | else 96 | waitTime = 0; 97 | break; 98 | 99 | /* case 'p': 100 | if (MDetector.getCornerRefinementMethod()==MarkerDetector::SUBPIX) 101 | MDetector.setCornerRefinementMethod(MarkerDetector::NONE); 102 | else 103 | MDetector.setCornerRefinementMethod(MarkerDetector::SUBPIX); 104 | break;*/ 105 | } 106 | } 107 | 108 | /************************************ 109 | * 110 | * 111 | * 112 | * 113 | ************************************/ 114 | int main(int argc, char **argv) { 115 | try { 116 | if (readArguments(argc, argv) == false) 117 | return 0; 118 | // parse arguments 119 | TheBoardConfig.readFromFile(TheBoardConfigFile); 120 | // read from camera or from file 121 | if (TheInputVideo == "live") { 122 | TheVideoCapturer.open(0); 123 | waitTime = 10; 124 | } else 125 | TheVideoCapturer.open(TheInputVideo); 126 | // check video is open 127 | if (!TheVideoCapturer.isOpened()) { 128 | cerr << "Could not open video" << endl; 129 | return -1; 130 | } 131 | 132 | // read first image to get the dimensions 133 | TheVideoCapturer >> TheInputImage; 134 | 135 | // Open outputvideo 136 | if (TheOutVideoFilePath != "") 137 | VWriter.open(TheOutVideoFilePath, CV_FOURCC('M', 'J', 'P', 'G'), 15, TheInputImage.size()); 138 | 139 | // read camera parameters if passed 140 | if (TheIntrinsicFile != "") { 141 | TheCameraParameters.readFromXMLFile(TheIntrinsicFile); 142 | TheCameraParameters.resize(TheInputImage.size()); 143 | } 144 | 145 | // Create gui 146 | 147 | cv::namedWindow("thres", 1); 148 | cv::namedWindow("in", 1); 149 | TheBoardDetector.setParams(TheBoardConfig, TheCameraParameters, TheMarkerSize); 150 | TheBoardDetector.getMarkerDetector().getThresholdParams(ThresParam1, ThresParam2); 151 | TheBoardDetector.getMarkerDetector().setCornerRefinementMethod(MarkerDetector::HARRIS); 152 | TheBoardDetector.set_repj_err_thres(1.5); 153 | // TheBoardDetector.getMarkerDetector().enableErosion(true);//for chessboards 154 | iThresParam1 = ThresParam1; 155 | iThresParam2 = ThresParam2; 156 | cv::createTrackbar("ThresParam1", "in", &iThresParam1, 13, cvTackBarEvents); 157 | cv::createTrackbar("ThresParam2", "in", &iThresParam2, 13, cvTackBarEvents); 158 | char key = 0; 159 | int index = 0; 160 | // capture until press ESC or until the end of the video 161 | do { 162 | TheVideoCapturer.retrieve(TheInputImage); 163 | TheInputImage.copyTo(TheInputImageCopy); 164 | index++; // number of images captured 165 | double tick = (double)getTickCount(); // for checking the speed 166 | // Detection of the board 167 | float probDetect = TheBoardDetector.detect(TheInputImage); 168 | // chekc the speed by calculating the mean speed of all iterations 169 | AvrgTime.first += ((double)getTickCount() - tick) / getTickFrequency(); 170 | AvrgTime.second++; 171 | cout << "Time detection=" << 1000 * AvrgTime.first / AvrgTime.second << " milliseconds" << endl; 172 | // print marker borders 173 | for (unsigned int i = 0; i < TheBoardDetector.getDetectedMarkers().size(); i++) 174 | TheBoardDetector.getDetectedMarkers()[i].draw(TheInputImageCopy, Scalar(0, 0, 255), 1); 175 | 176 | // print board 177 | if (TheCameraParameters.isValid()) { 178 | if (probDetect > 0.2) { 179 | CvDrawingUtils::draw3dAxis(TheInputImageCopy, TheBoardDetector.getDetectedBoard(), TheCameraParameters); 180 | // CvDrawingUtils::draw3dCube(TheInputImageCopy, TheBoardDetector.getDetectedBoard(),TheCameraParameters); 181 | // draw3dBoardCube( TheInputImageCopy,TheBoardDetected,TheIntriscCameraMatrix,TheDistorsionCameraParams); 182 | } 183 | } 184 | // DONE! Easy, right? 185 | 186 | // show input with augmented information and the thresholded image 187 | cv::imshow("in", TheInputImageCopy); 188 | cv::imshow("thres", TheBoardDetector.getMarkerDetector().getThresholdedImage()); 189 | // write to video if required 190 | if (TheOutVideoFilePath != "") { 191 | // create a beautiful compiosed image showing the thresholded 192 | // first create a small version of the thresholded image 193 | cv::Mat smallThres; 194 | cv::resize(TheBoardDetector.getMarkerDetector().getThresholdedImage(), smallThres, 195 | cvSize(TheInputImageCopy.cols / 3, TheInputImageCopy.rows / 3)); 196 | cv::Mat small3C; 197 | cv::cvtColor(smallThres, small3C, CV_GRAY2BGR); 198 | cv::Mat roi = TheInputImageCopy(cv::Rect(0, 0, TheInputImageCopy.cols / 3, TheInputImageCopy.rows / 3)); 199 | small3C.copyTo(roi); 200 | VWriter << TheInputImageCopy; 201 | // cv::imshow("TheInputImageCopy",TheInputImageCopy); 202 | } 203 | 204 | key = cv::waitKey(waitTime); // wait for key to be pressed 205 | processKey(key); 206 | } while (key != 27 && TheVideoCapturer.grab()); 207 | 208 | 209 | } catch (std::exception &ex) 210 | 211 | { 212 | cout << "Exception :" << ex.what() << endl; 213 | } 214 | } 215 | /************************************ 216 | * 217 | * 218 | * 219 | * 220 | ************************************/ 221 | 222 | void cvTackBarEvents(int pos, void *) { 223 | if (iThresParam1 < 3) 224 | iThresParam1 = 3; 225 | if (iThresParam1 % 2 != 1) 226 | iThresParam1++; 227 | if (ThresParam2 < 1) 228 | ThresParam2 = 1; 229 | ThresParam1 = iThresParam1; 230 | ThresParam2 = iThresParam2; 231 | TheBoardDetector.getMarkerDetector().setThresholdParams(ThresParam1, ThresParam2); 232 | // recompute 233 | // Detection of the board 234 | float probDetect = TheBoardDetector.detect(TheInputImage); 235 | TheInputImage.copyTo(TheInputImageCopy); 236 | if (TheCameraParameters.isValid() && probDetect > 0.2) 237 | aruco::CvDrawingUtils::draw3dAxis(TheInputImageCopy, TheBoardDetector.getDetectedBoard(), TheCameraParameters); 238 | 239 | 240 | cv::imshow("in", TheInputImageCopy); 241 | cv::imshow("thres", TheBoardDetector.getMarkerDetector().getThresholdedImage()); 242 | } 243 | -------------------------------------------------------------------------------- /dox.in: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.3.7 2 | 3 | #--------------------------------------------------------------------------- 4 | # Project related configuration options 5 | #--------------------------------------------------------------------------- 6 | PROJECT_NAME = @PACKAGE_NAME@ 7 | PROJECT_NUMBER = @VERSION@ 8 | OUTPUT_DIRECTORY = . 9 | CREATE_SUBDIRS = NO 10 | OUTPUT_LANGUAGE = English 11 | USE_WINDOWS_ENCODING = NO 12 | BRIEF_MEMBER_DESC = YES 13 | REPEAT_BRIEF = YES 14 | ABBREVIATE_BRIEF = "The $name class" \ 15 | "The $name widget" \ 16 | "The $name file" \ 17 | is \ 18 | provides \ 19 | specifies \ 20 | contains \ 21 | represents \ 22 | a \ 23 | an \ 24 | the 25 | ALWAYS_DETAILED_SEC = YES 26 | INLINE_INHERITED_MEMB = YES 27 | FULL_PATH_NAMES = NO 28 | STRIP_FROM_PATH = 29 | STRIP_FROM_INC_PATH = 30 | SHORT_NAMES = NO 31 | JAVADOC_AUTOBRIEF = YES 32 | MULTILINE_CPP_IS_BRIEF = NO 33 | DETAILS_AT_TOP = NO 34 | INHERIT_DOCS = YES 35 | DISTRIBUTE_GROUP_DOC = NO 36 | TAB_SIZE = 8 37 | ALIASES = 38 | OPTIMIZE_OUTPUT_FOR_C = NO 39 | OPTIMIZE_OUTPUT_JAVA = NO 40 | SUBGROUPING = YES 41 | #--------------------------------------------------------------------------- 42 | # Build related configuration options 43 | #--------------------------------------------------------------------------- 44 | EXTRACT_ALL = YES 45 | EXTRACT_PRIVATE = NO 46 | EXTRACT_STATIC = YES 47 | EXTRACT_LOCAL_CLASSES = YES 48 | EXTRACT_LOCAL_METHODS = NO 49 | HIDE_UNDOC_MEMBERS = YES 50 | HIDE_UNDOC_CLASSES = YES 51 | HIDE_FRIEND_COMPOUNDS = NO 52 | HIDE_IN_BODY_DOCS = NO 53 | INTERNAL_DOCS = NO 54 | CASE_SENSE_NAMES = YES 55 | HIDE_SCOPE_NAMES = NO 56 | SHOW_INCLUDE_FILES = YES 57 | INLINE_INFO = YES 58 | SORT_MEMBER_DOCS = YES 59 | SORT_BRIEF_DOCS = NO 60 | SORT_BY_SCOPE_NAME = NO 61 | GENERATE_TODOLIST = YES 62 | GENERATE_TESTLIST = YES 63 | GENERATE_BUGLIST = YES 64 | GENERATE_DEPRECATEDLIST= YES 65 | ENABLED_SECTIONS = 66 | MAX_INITIALIZER_LINES = 30 67 | SHOW_USED_FILES = YES 68 | #--------------------------------------------------------------------------- 69 | # configuration options related to warning and progress messages 70 | #--------------------------------------------------------------------------- 71 | QUIET = NO 72 | WARNINGS = YES 73 | WARN_IF_UNDOCUMENTED = YES 74 | WARN_IF_DOC_ERROR = YES 75 | WARN_FORMAT = "$file:$line: $text" 76 | WARN_LOGFILE = 77 | #--------------------------------------------------------------------------- 78 | # configuration options related to the input files 79 | #--------------------------------------------------------------------------- 80 | INPUT = src @SRCDIR@ 81 | FILE_PATTERNS = *.c \ 82 | *.cc \ 83 | *.cxx \ 84 | *.cpp \ 85 | *.c++ \ 86 | *.java \ 87 | *.ii \ 88 | *.ixx \ 89 | *.ipp \ 90 | *.i++ \ 91 | *.inl \ 92 | *.h \ 93 | *.hh \ 94 | *.hxx \ 95 | *.hpp \ 96 | *.h++ \ 97 | *.idl \ 98 | *.odl \ 99 | *.cs \ 100 | *.php \ 101 | *.php3 \ 102 | *.inc \ 103 | *.C \ 104 | *.H \ 105 | *.tlh \ 106 | *.diff \ 107 | *.patch \ 108 | *.moc \ 109 | *.xpm \ 110 | *.dox 111 | RECURSIVE = YES 112 | EXCLUDE = ./src/gu 113 | EXCLUDE_SYMLINKS = NO 114 | EXCLUDE_PATTERNS = 115 | EXAMPLE_PATH = 116 | EXAMPLE_PATTERNS = * 117 | EXAMPLE_RECURSIVE = NO 118 | IMAGE_PATH = 119 | INPUT_FILTER = 120 | FILTER_SOURCE_FILES = NO 121 | #--------------------------------------------------------------------------- 122 | # configuration options related to source browsing 123 | #--------------------------------------------------------------------------- 124 | SOURCE_BROWSER = NO 125 | INLINE_SOURCES = NO 126 | STRIP_CODE_COMMENTS = YES 127 | REFERENCED_BY_RELATION = YES 128 | REFERENCES_RELATION = YES 129 | VERBATIM_HEADERS = YES 130 | #--------------------------------------------------------------------------- 131 | # configuration options related to the alphabetical class index 132 | #--------------------------------------------------------------------------- 133 | ALPHABETICAL_INDEX = YES 134 | COLS_IN_ALPHA_INDEX = 5 135 | IGNORE_PREFIX = 136 | #--------------------------------------------------------------------------- 137 | # configuration options related to the HTML output 138 | #--------------------------------------------------------------------------- 139 | GENERATE_HTML = YES 140 | HTML_OUTPUT = html 141 | HTML_FILE_EXTENSION = .html 142 | HTML_HEADER = 143 | HTML_FOOTER = 144 | HTML_STYLESHEET = 145 | HTML_ALIGN_MEMBERS = YES 146 | GENERATE_HTMLHELP = NO 147 | CHM_FILE = 148 | HHC_LOCATION = 149 | GENERATE_CHI = NO 150 | BINARY_TOC = NO 151 | TOC_EXPAND = NO 152 | DISABLE_INDEX = NO 153 | ENUM_VALUES_PER_LINE = 4 154 | GENERATE_TREEVIEW = NO 155 | TREEVIEW_WIDTH = 250 156 | #--------------------------------------------------------------------------- 157 | # configuration options related to the LaTeX output 158 | #--------------------------------------------------------------------------- 159 | GENERATE_LATEX = NO 160 | LATEX_OUTPUT = latex 161 | LATEX_CMD_NAME = latex 162 | MAKEINDEX_CMD_NAME = makeindex 163 | COMPACT_LATEX = NO 164 | PAPER_TYPE = a4wide 165 | EXTRA_PACKAGES = 166 | LATEX_HEADER = 167 | PDF_HYPERLINKS = NO 168 | USE_PDFLATEX = NO 169 | LATEX_BATCHMODE = NO 170 | LATEX_HIDE_INDICES = NO 171 | #--------------------------------------------------------------------------- 172 | # configuration options related to the RTF output 173 | #--------------------------------------------------------------------------- 174 | GENERATE_RTF = NO 175 | RTF_OUTPUT = rtf 176 | COMPACT_RTF = NO 177 | RTF_HYPERLINKS = NO 178 | RTF_STYLESHEET_FILE = 179 | RTF_EXTENSIONS_FILE = 180 | #--------------------------------------------------------------------------- 181 | # configuration options related to the man page output 182 | #--------------------------------------------------------------------------- 183 | GENERATE_MAN = NO 184 | MAN_OUTPUT = man 185 | MAN_EXTENSION = .3 186 | MAN_LINKS = NO 187 | #--------------------------------------------------------------------------- 188 | # configuration options related to the XML output 189 | #--------------------------------------------------------------------------- 190 | GENERATE_XML = NO 191 | XML_OUTPUT = xml 192 | XML_SCHEMA = 193 | XML_DTD = 194 | XML_PROGRAMLISTING = YES 195 | #--------------------------------------------------------------------------- 196 | # configuration options for the AutoGen Definitions output 197 | #--------------------------------------------------------------------------- 198 | GENERATE_AUTOGEN_DEF = NO 199 | #--------------------------------------------------------------------------- 200 | # configuration options related to the Perl module output 201 | #--------------------------------------------------------------------------- 202 | GENERATE_PERLMOD = NO 203 | PERLMOD_LATEX = NO 204 | PERLMOD_PRETTY = YES 205 | PERLMOD_MAKEVAR_PREFIX = 206 | #--------------------------------------------------------------------------- 207 | # Configuration options related to the preprocessor 208 | #--------------------------------------------------------------------------- 209 | ENABLE_PREPROCESSING = YES 210 | MACRO_EXPANSION = NO 211 | EXPAND_ONLY_PREDEF = NO 212 | SEARCH_INCLUDES = YES 213 | INCLUDE_PATH = 214 | INCLUDE_FILE_PATTERNS = 215 | PREDEFINED = 216 | EXPAND_AS_DEFINED = 217 | SKIP_FUNCTION_MACROS = YES 218 | #--------------------------------------------------------------------------- 219 | # Configuration::additions related to external references 220 | #--------------------------------------------------------------------------- 221 | TAGFILES = 222 | GENERATE_TAGFILE = gu.tgf 223 | ALLEXTERNALS = NO 224 | EXTERNAL_GROUPS = YES 225 | PERL_PATH = /usr/bin/perl 226 | #--------------------------------------------------------------------------- 227 | # Configuration options related to the dot tool 228 | #--------------------------------------------------------------------------- 229 | CLASS_DIAGRAMS = YES 230 | HIDE_UNDOC_RELATIONS = YES 231 | HAVE_DOT = NO 232 | CLASS_GRAPH = YES 233 | COLLABORATION_GRAPH = YES 234 | UML_LOOK = NO 235 | TEMPLATE_RELATIONS = NO 236 | INCLUDE_GRAPH = YES 237 | INCLUDED_BY_GRAPH = YES 238 | CALL_GRAPH = NO 239 | GRAPHICAL_HIERARCHY = YES 240 | DOT_IMAGE_FORMAT = png 241 | DOT_PATH = 242 | DOTFILE_DIRS = 243 | MAX_DOT_GRAPH_WIDTH = 1024 244 | MAX_DOT_GRAPH_HEIGHT = 1024 245 | MAX_DOT_GRAPH_DEPTH = 1000 246 | GENERATE_LEGEND = YES 247 | DOT_CLEANUP = YES 248 | #--------------------------------------------------------------------------- 249 | # Configuration::additions related to the search engine 250 | #--------------------------------------------------------------------------- 251 | SEARCHENGINE = NO 252 | -------------------------------------------------------------------------------- /utils/aruco_test.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************************** 2 | Copyright 2011 Rafael Muñoz Salinas. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 | of conditions and the following disclaimer in the documentation and/or other materials 12 | provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Rafael Muñoz Salinas ''AS IS'' AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Rafael Muñoz Salinas OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those of the 25 | authors and should not be interpreted as representing official policies, either expressed 26 | or implied, of Rafael Muñoz Salinas. 27 | ********************************************************************************************/ 28 | #include 29 | #include 30 | #include 31 | #include "aruco.h" 32 | #include "cvdrawingutils.h" 33 | #include 34 | using namespace cv; 35 | using namespace aruco; 36 | 37 | string TheInputVideo; 38 | string TheIntrinsicFile; 39 | float TheMarkerSize = -1; 40 | int ThePyrDownLevel; 41 | MarkerDetector MDetector; 42 | VideoCapture TheVideoCapturer; 43 | vector< Marker > TheMarkers; 44 | Mat TheInputImage, TheInputImageCopy; 45 | CameraParameters TheCameraParameters; 46 | void cvTackBarEvents(int pos, void *); 47 | bool readCameraParameters(string TheIntrinsicFile, CameraParameters &CP, Size size); 48 | 49 | pair< double, double > AvrgTime(0, 0); // determines the average time required for detection 50 | double ThresParam1, ThresParam2; 51 | int iThresParam1, iThresParam2; 52 | int waitTime = 0; 53 | 54 | /************************************ 55 | * 56 | * 57 | * 58 | * 59 | ************************************/ 60 | bool readArguments(int argc, char **argv) { 61 | if (argc < 2) { 62 | cerr << "Invalid number of arguments" << endl; 63 | cerr << "Usage: (in.avi|live[:idx_cam=0]) [intrinsics.yml] [size]" << endl; 64 | return false; 65 | } 66 | TheInputVideo = argv[1]; 67 | if (argc >= 3) 68 | TheIntrinsicFile = argv[2]; 69 | if (argc >= 4) 70 | TheMarkerSize = atof(argv[3]); 71 | 72 | if (argc == 3) 73 | cerr << "NOTE: You need makersize to see 3d info!!!!" << endl; 74 | return true; 75 | } 76 | 77 | int findParam(std::string param, int argc, char *argv[]) { 78 | for (int i = 0; i < argc; i++) 79 | if (string(argv[i]) == param) 80 | return i; 81 | 82 | return -1; 83 | } 84 | /************************************ 85 | * 86 | * 87 | * 88 | * 89 | ************************************/ 90 | int main(int argc, char **argv) { 91 | try { 92 | if (readArguments(argc, argv) == false) { 93 | return 0; 94 | } 95 | // parse arguments 96 | 97 | // read from camera or from file 98 | if (TheInputVideo.find("live") != string::npos) { 99 | int vIdx = 0; 100 | // check if the :idx is here 101 | char cad[100]; 102 | if (TheInputVideo.find(":") != string::npos) { 103 | std::replace(TheInputVideo.begin(), TheInputVideo.end(), ':', ' '); 104 | sscanf(TheInputVideo.c_str(), "%s %d", cad, &vIdx); 105 | } 106 | cout << "Opening camera index " << vIdx << endl; 107 | TheVideoCapturer.open(vIdx); 108 | waitTime = 10; 109 | } else 110 | TheVideoCapturer.open(TheInputVideo); 111 | // check video is open 112 | if (!TheVideoCapturer.isOpened()) { 113 | cerr << "Could not open video" << endl; 114 | return -1; 115 | } 116 | bool isVideoFile = false; 117 | if (TheInputVideo.find(".avi") != std::string::npos || TheInputVideo.find("live") != string::npos) 118 | isVideoFile = true; 119 | // read first image to get the dimensions 120 | TheVideoCapturer >> TheInputImage; 121 | 122 | // read camera parameters if passed 123 | if (TheIntrinsicFile != "") { 124 | TheCameraParameters.readFromXMLFile(TheIntrinsicFile); 125 | TheCameraParameters.resize(TheInputImage.size()); 126 | } 127 | // Configure other parameters 128 | if (ThePyrDownLevel > 0) 129 | MDetector.pyrDown(ThePyrDownLevel); 130 | 131 | 132 | // Create gui 133 | 134 | cv::namedWindow("thres", 1); 135 | cv::namedWindow("in", 1); 136 | 137 | MDetector.setThresholdParams(7, 7); 138 | MDetector.setThresholdParamRange(2, 0); 139 | // MDetector.enableLockedCornersMethod(true); 140 | // MDetector.setCornerRefinementMethod ( MarkerDetector::SUBPIX ); 141 | MDetector.getThresholdParams(ThresParam1, ThresParam2); 142 | iThresParam1 = ThresParam1; 143 | iThresParam2 = ThresParam2; 144 | //cv::createTrackbar("ThresParam1", "in", &iThresParam1, 25, cvTackBarEvents); 145 | //cv::createTrackbar("ThresParam2", "in", &iThresParam2, 13, cvTackBarEvents); 146 | 147 | char key = 0; 148 | int index = 0; 149 | // capture until press ESC or until the end of the video 150 | TheVideoCapturer.retrieve(TheInputImage); 151 | 152 | cv::Size sz = TheInputImage.size(); 153 | MDetector.createCudaBuffers(sz.width, sz.height); 154 | 155 | do { 156 | 157 | // copy image 158 | 159 | index++; // number of images captured 160 | double tick = (double)getTickCount(); // for checking the speed 161 | // Detection of markers in the image passed 162 | MDetector.detect(TheInputImage, TheMarkers, TheCameraParameters, TheMarkerSize); 163 | // chekc the speed by calculating the mean speed of all iterations 164 | AvrgTime.first += ((double)getTickCount() - tick) / getTickFrequency(); 165 | AvrgTime.second++; 166 | cout << "\rTime detection=" << 1000 * AvrgTime.first / AvrgTime.second << " milliseconds nmarkers=" << TheMarkers.size() << std::flush; 167 | 168 | // print marker info and draw the markers in image 169 | TheInputImage.copyTo(TheInputImageCopy); 170 | 171 | for (unsigned int i = 0; i < TheMarkers.size(); i++) { 172 | cout << endl << TheMarkers[i]; 173 | TheMarkers[i].draw(TheInputImageCopy, Scalar(0, 0, 255), 1); 174 | } 175 | if (TheMarkers.size() != 0) 176 | cout << endl; 177 | // print other rectangles that contains no valid markers 178 | /** for (unsigned int i=0;i 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include "exports.h" 39 | 40 | #include 41 | 42 | namespace aruco { 43 | 44 | /** 45 | * This class represent the internal code of a marker 46 | * It does not include marker borders 47 | * 48 | */ 49 | class ARUCO_EXPORTS MarkerCode { 50 | public: 51 | /** 52 | * Constructor, receive dimension of marker 53 | */ 54 | MarkerCode(unsigned int n = 0); 55 | 56 | /** 57 | * Copy Constructor 58 | */ 59 | MarkerCode(const MarkerCode &MC); 60 | 61 | /** 62 | * Get id of a specific rotation as the number obtaiend from the concatenation of all the bits 63 | */ 64 | unsigned int getId(unsigned int rot = 0) const { return _ids[rot]; }; 65 | 66 | /** 67 | * Get a bit value in a specific rotation. 68 | * The marker is refered as a unidimensional string of bits, i.e. pos=y*n+x 69 | */ 70 | bool get(unsigned int pos, unsigned int rot = 0) const { return _bits[rot][pos]; } 71 | 72 | /** 73 | * Get the string of bits for a specific rotation 74 | */ 75 | const std::vector< bool > &getRotation(unsigned int rot) const { return _bits[rot]; }; 76 | 77 | /** 78 | * Set the value of a bit in a specific rotation 79 | * The marker is refered as a unidimensional string of bits, i.e. pos=y*n+x 80 | * This method assure consistency of the marker code: 81 | * - The rest of rotations are updated automatically when performing a modification 82 | * - The id values in all rotations are automatically updated too 83 | * This is the only method to modify a bit value 84 | */ 85 | void set(unsigned int pos, bool val, bool updateIds=true); 86 | 87 | /** 88 | * Return the full size of the marker (n*n) 89 | */ 90 | unsigned int size() const { return n() * n(); }; 91 | 92 | /** 93 | * Return the value of marker dimension (n) 94 | */ 95 | unsigned int n() const { return _n; }; 96 | 97 | /** 98 | * Return the self distance S(m) of the marker (Equation 8) 99 | * Assign to minRot the rotation of minimun hamming distance 100 | */ 101 | unsigned int selfDistance(unsigned int &minRot) const; 102 | 103 | /** 104 | * Return the self distance S(m) of the marker (Equation 8) 105 | * Same method as selfDistance(uint &minRot), except this doesnt return minRot value. 106 | */ 107 | unsigned int selfDistance() const { 108 | unsigned int minRot; 109 | return selfDistance(minRot); 110 | }; 111 | 112 | /** 113 | * Return the rotation invariant distance to another marker, D(m1, m2) (Equation 6) 114 | * Assign to minRot the rotation of minimun hamming distance. The rotation refers to the marker passed as parameter, m 115 | */ 116 | unsigned int distance(const MarkerCode &m, unsigned int &minRot) const; 117 | 118 | /** 119 | * Return the rotation invariant distance to another marker, D(m1, m2) (Equation 6) 120 | * Same method as distance(MarkerCode m, uint &minRot), except this doesnt return minRot value. 121 | */ 122 | unsigned int distance(const MarkerCode &m) const { 123 | unsigned int minRot; 124 | return distance(m, minRot); 125 | }; 126 | 127 | /** 128 | * Read marker bits from a string of "0"s and "1"s 129 | */ 130 | void fromString(std::string s); 131 | 132 | /** 133 | * Convert marker to a string of "0"s and "1"s 134 | */ 135 | std::string toString() const; 136 | 137 | 138 | /** 139 | * Convert marker to a cv::Mat image of (pixSize x pixSize) pixels 140 | * It adds a black border of one cell size 141 | */ 142 | cv::Mat getImg(unsigned int pixSize) const; 143 | 144 | private: 145 | unsigned int _ids[4]; // ids in the four rotations 146 | std::vector< bool > _bits[4]; // bit strings in the four rotations 147 | unsigned int _n; // marker dimension 148 | 149 | /** 150 | * Return hamming distance between two bit vectors 151 | */ 152 | unsigned int hammingDistance(const std::vector< bool > &m1, const std::vector< bool > &m2) const; 153 | }; 154 | 155 | 156 | /** 157 | * This class represent a marker dictionary as a vector of MarkerCodes 158 | * 159 | * 160 | */ 161 | class ARUCO_EXPORTS Dictionary : public std::vector< MarkerCode > { 162 | public: 163 | /** 164 | * Read dictionary from a .yml opencv file 165 | */ 166 | bool fromFile(std::string filename); 167 | 168 | /** 169 | * Write dictionary to a .yml opencv file 170 | */ 171 | bool toFile(std::string filename); 172 | 173 | /** 174 | * Return the distance of a marker to the dictionary, D(m,D) (Equation 7) 175 | * Assign to minMarker the marker index in the dictionary with minimun distance to m 176 | * Assign to minRot the rotation of minimun hamming distance. The rotation refers to the marker passed as parameter, m 177 | */ 178 | unsigned int distance(const MarkerCode &m, unsigned int &minMarker, unsigned int &minRot); 179 | 180 | /** 181 | * Return the distance of a marker to the dictionary, D(m,D) (Equation 7) 182 | * Same method as distance(MarkerCode m, uint &minMarker, uint &minRot), except this doesnt return minMarker and minRot values. 183 | */ 184 | unsigned int distance(const MarkerCode &m) { 185 | unsigned int minMarker, minRot; 186 | return distance(m, minMarker, minRot); 187 | } 188 | 189 | /** 190 | * Calculate the minimun distance between the markers in the dictionary (Equation 9) 191 | */ 192 | unsigned int minimunDistance(); 193 | 194 | int tau0; 195 | 196 | private: 197 | // convert to string 198 | template < class T > static std::string toStr(T num) { 199 | std::stringstream ss; 200 | ss << num; 201 | return ss.str(); 202 | } 203 | }; 204 | 205 | 206 | /** 207 | * Highly Reliable Marker Detector Class 208 | * 209 | * 210 | */ 211 | class ARUCO_EXPORTS HighlyReliableMarkers { 212 | public: 213 | /** 214 | * Balanced Binary Tree for a marker dictionary 215 | * 216 | */ 217 | class BalancedBinaryTree { 218 | 219 | public: 220 | /** 221 | * Create the tree for dictionary D 222 | */ 223 | void loadDictionary(Dictionary *D); 224 | 225 | /** 226 | * Search a id in the dictionary. Return true if found, false otherwise. 227 | */ 228 | bool findId(unsigned int id, unsigned int &orgPos); 229 | 230 | private: 231 | std::vector< std::pair< unsigned int, unsigned int > > _orderD; // dictionary sorted by id, 232 | // first element is the id, 233 | // second element is the position in original D 234 | std::vector< std::pair< int, int > > _binaryTree; // binary tree itself (as a vector), each element is a node of the tree 235 | // first element indicate the position in _binaryTree of the lower child 236 | // second element is the position in _binaryTree of the higher child 237 | // -1 value indicates no lower or higher child 238 | unsigned int _root; // position in _binaryTree of the root node of the tree 239 | }; 240 | 241 | /** 242 | * Load the dictionary that will be detected or read it directly from file 243 | */ 244 | // correctionDistance [0,1] 0: totalmente restrictivo, 1 mas flexible 245 | static bool loadDictionary(Dictionary D, float correctionDistance = 1); 246 | static bool loadDictionary(std::string filename, float correctionDistance = 1); 247 | static Dictionary &getDictionary() { return _D; } 248 | 249 | 250 | /** 251 | * Detect marker in a canonical image. Perform detection and error correction 252 | * Return marker id in 0 rotation, or -1 if not found 253 | * Assign the detected rotation of the marker to nRotation 254 | */ 255 | static int detect(const cv::Mat &in, int &nRotations); 256 | 257 | 258 | private: 259 | static Dictionary _D; // loaded dictionary 260 | static BalancedBinaryTree _binaryTree; 261 | // marker dimension, marker dimension with borders, maximunCorrectionDistance 262 | static unsigned int _n; 263 | static unsigned int _ncellsBorder; 264 | static unsigned int _correctionDistance; 265 | static int _swidth; // cell size in the canonical image 266 | 267 | 268 | /** 269 | * Check marker borders cell in the canonical image are black 270 | */ 271 | static bool checkBorders(cv::Mat grey); 272 | 273 | /** 274 | * Return binary MarkerCode from a canonical image, it ignores borders 275 | */ 276 | static MarkerCode getMarkerCode(const cv::Mat &grey); 277 | }; 278 | 279 | } 280 | 281 | 282 | #endif // HIGHLYRELIABLEMARKERS_H 283 | --------------------------------------------------------------------------------