├── doc └── tagdesign.png ├── platforms ├── javascript │ ├── todo.txt │ ├── Makefile │ ├── src │ │ └── chilitags-javascript.js │ └── samples │ │ └── detection-2d │ │ └── index.html └── jni │ ├── samples │ ├── android-estimate3d │ │ ├── res │ │ │ ├── drawable-mdpi │ │ │ │ └── ic_launcher.png │ │ │ └── layout │ │ │ │ └── activity_chilitags_sample_estimate3d.xml │ │ ├── .classpath │ │ ├── project.properties │ │ ├── .project │ │ ├── AndroidManifest.xml │ │ └── src │ │ │ └── ch │ │ │ └── epfl │ │ │ └── chili │ │ │ └── chilitags │ │ │ └── samples │ │ │ └── estimate3d │ │ │ └── Estimate3DActivity.java │ ├── android-estimate3d-gui │ │ ├── res │ │ │ └── drawable-mdpi │ │ │ │ └── ic_launcher.png │ │ ├── .classpath │ │ ├── project.properties │ │ ├── proguard-project.txt │ │ ├── .project │ │ ├── src │ │ │ └── ch │ │ │ │ └── epfl │ │ │ │ └── chili │ │ │ │ └── chilitags │ │ │ │ └── samples │ │ │ │ └── estimate3d_gui │ │ │ │ ├── shader │ │ │ │ ├── LineShader.java │ │ │ │ ├── YUV2RGBShader.java │ │ │ │ └── Shader.java │ │ │ │ ├── CameraPreviewGLSurfaceView.java │ │ │ │ ├── Estimate3DGUIActivity.java │ │ │ │ ├── GLESLine.java │ │ │ │ └── CameraController.java │ │ └── AndroidManifest.xml │ └── README.md │ └── src │ ├── CMakeLists.txt │ └── ch │ └── epfl │ └── chili │ └── chilitags │ ├── CVSize.java │ └── ObjectTransform.java ├── .gitmodules ├── .gitignore ├── chilitags.pc.in ├── test ├── README.md ├── CMakeLists.txt ├── find-crash.cpp ├── integration.cpp ├── codec.cpp ├── Filter.cpp ├── float-precision.cpp ├── drawer.cpp └── test-metadata.hpp ├── .travis.yml ├── samples ├── detection │ ├── README.md │ └── detect-from-file.cpp ├── CMakeLists.txt ├── 3destimation │ └── estimate3d.cpp └── multithreaded │ └── async-detection.cpp ├── src ├── GrowRoi.hpp ├── Refine.hpp ├── EnsureGreyscale.hpp ├── ScreenOut.hpp ├── FindQuads.hpp ├── ReadBits.hpp ├── EnsureGreyscale.cpp ├── Track.hpp ├── ScreenOut.cpp ├── Decode.hpp ├── GrowRoi.cpp ├── Filter.hpp ├── Detect.hpp ├── Decode.cpp ├── CMakeLists.txt ├── Refine.cpp ├── Track.cpp ├── Filter.cpp ├── Codec.hpp ├── EstimatePose3D.cpp ├── Detect.cpp ├── EstimatePose3D.hpp └── FindQuads.cpp ├── share └── tag_configuration_sample.yml ├── tools ├── CMakeLists.txt └── creator │ ├── creator.cpp │ └── README.md ├── .ycm_extra_conf.py ├── cmake ├── UseJavaExtensions.cmake └── TargetDoc.cmake └── CMakeLists.txt /doc/tagdesign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/chilitags/master/doc/tagdesign.png -------------------------------------------------------------------------------- /platforms/javascript/todo.txt: -------------------------------------------------------------------------------- 1 | * Allow JSON files as camera calibration and marker configuration 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/data"] 2 | path = test/data 3 | url = https://github.com/chili-epfl/chilitags-testdata.git 4 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/chilitags/master/platforms/jni/samples/android-estimate3d/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royshil/chilitags/master/platforms/jni/samples/android-estimate3d-gui/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Build caches 2 | build*/ 3 | bin/ 4 | gen/ 5 | libs/ 6 | 7 | #Eclipse files 8 | /.cproject 9 | /.project 10 | .settings 11 | .directory 12 | 13 | #Markdown cache 14 | *.md.html 15 | 16 | #??? 17 | /Default 18 | 19 | #Python cache 20 | *.pyc 21 | 22 | -------------------------------------------------------------------------------- /chilitags.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/lib 4 | includedir=${prefix}/include 5 | 6 | Name: chilitags 7 | Description: Robust Fiducial Markers for Augmented Reality 8 | Version: @CPACK_PACKAGE_VERSION_MAJOR@.@CPACK_PACKAGE_VERSION_MINOR@.@CPACK_PACKAGE_VERSION_PATCH@ 9 | Libs: -L${libdir} -lchilitags 10 | Cflags: @COMPILE_FLAGS@ -I${includedir}/chilitags 11 | -------------------------------------------------------------------------------- /platforms/javascript/Makefile: -------------------------------------------------------------------------------- 1 | chilitags.js: src/jschilitags.cpp src/chilitags-javascript.js 2 | em++ -std=c++11 -O2 -s OUTLINING_LIMIT=40000 src/jschilitags.cpp -lchilitags -lopencv_core -lopencv_imgproc -lopencv_calib3d -lhighgui -o $@ --post-js src/chilitags-javascript.js -s EXPORTED_FUNCTIONS="['_setFilter', '_find', '_set3DFilter', '_set2DFilter', '_estimate', '_readTagConfiguration', '_setDefaultTagSize', '_readCalibration', '_getCameraMatrix', '_getDistortionCoeffs']" 3 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | Chilitags have been extensively used in the past years, providing "real word" 2 | tests. Automated tests are a more recent addition. 3 | 4 | To run automated tests, you need to activate them in the CMake configuration 5 | (option `WITH_TESTS`). The test data is a submodule, you need to get it before 6 | being able to run tests. 7 | 8 | Example on Unix : 9 | ``` 10 | git clone --recursive git@github.com:chili-epfl/chilitags 11 | cd chilitags 12 | mkdir build 13 | cd build 14 | ccmake .. # set the option `WITH_TESTS` to `ON` 15 | make 16 | cd test && ctest 17 | ``` 18 | 19 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | compiler: 4 | - clang 5 | - gcc 6 | 7 | before_install: 8 | - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test 9 | - sudo add-apt-repository -y ppa:kubuntu-ppa/backports 10 | - sudo apt-get update -qq 11 | - sudo apt-get install -qq g++-4.8 libopencv-dev 12 | - if [ "$CXX" = "g++" ]; then sudo apt-get install -qq g++-4.8; fi 13 | - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi 14 | - sudo apt-get install -qq openjdk-7-jdk 15 | - export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 16 | 17 | before_script: 18 | - mkdir build 19 | - cd build 20 | 21 | script: 22 | - cmake -DWITH_TESTS=ON -DWITH_TOOLS=ON -DWITH_SAMPLES=ON -DWITH_JNI_BINDINGS=ON .. 23 | - make 24 | - cd test && ctest -V 25 | 26 | branches: 27 | only: 28 | - master 29 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d/res/layout/activity_chilitags_sample_estimate3d.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | chilitags-sample-estimate3d 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | chilitags-sample-estimate3d-gui 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/src/ch/epfl/chili/chilitags/samples/estimate3d_gui/shader/LineShader.java: -------------------------------------------------------------------------------- 1 | package ch.epfl.chili.chilitags.samples.estimate3d_gui.shader; 2 | 3 | /** 4 | * Simple line shader, paints all of the interpolated pixels the same color 5 | * @author Ayberk Özgür 6 | */ 7 | public class LineShader extends Shader { 8 | 9 | @Override 10 | protected String getVertexShader() { 11 | return "attribute vec4 a_position; \n" + 12 | "void main() { \n" + 13 | " gl_Position = a_position; \n" + 14 | "} \n"; 15 | } 16 | 17 | @Override 18 | protected String getFragmentShader() { 19 | return "#ifdef GL_ES \n" + 20 | "precision highp float; \n" + 21 | "#endif \n" + 22 | "uniform vec4 v_color; \n" + 23 | "void main() { \n" + 24 | " gl_FragColor = v_color; \n" + 25 | "} \n"; 26 | } 27 | 28 | @Override 29 | protected void loadUniforms() { /*No auto uniforms*/ } 30 | 31 | @Override 32 | protected void getUniformHandles() { /*No auto uniforms*/ } 33 | } 34 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/detection/README.md: -------------------------------------------------------------------------------- 1 | Chilitags Detector Sample 2 | ========================= 3 | 4 | `detect-live` has two purposes: allowing to quickly test the detection of chilitags, and illustrate the use of the library. 5 | 6 | 7 | 8 | Usage of `detect-live` 9 | ---------------------- 10 | 11 | `detect-live` displays the identifier and the size of the tags detected on the live feed of a camera. 12 | 13 | ### Synopsis 14 | 15 | detect-live [x-res y-res [camera-index]] 16 | 17 | ### Description 18 | 19 | *x-res y-res* are the resolution parameter to give to the camera. 20 | By default, `detect-live` grabs 640x480 images. 21 | 22 | *camera-index* is the index of the camera to use to grab images. 23 | By default, it is 0. 24 | If multiple cameras are attached to the computer, you can select them by increasing the index. 25 | For example, 1 is the second camera attached to the computer. 26 | 27 | 28 | 29 | Using chilitags in your code. 30 | ----------------------------- 31 | 32 | The source code provided here shows how to use the chilitags library. 33 | The comments in `detect-live.cpp` are meant to be a tutorial on how to integrate the detection in your application. 34 | They also explain how to use the information produced by the detection of tags, i.e. the position and identifier of the detected tags. 35 | More detailed documentation can be found in the headers of the library. 36 | If you are more curious, you will have to dive into the source code of the library. 37 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/src/ch/epfl/chili/chilitags/samples/estimate3d_gui/CameraPreviewGLSurfaceView.java: -------------------------------------------------------------------------------- 1 | package ch.epfl.chili.chilitags.samples.estimate3d_gui; 2 | 3 | import ch.epfl.chili.chilitags.Chilitags3D; 4 | import android.content.Context; 5 | import android.opengl.GLSurfaceView; 6 | 7 | public class CameraPreviewGLSurfaceView extends GLSurfaceView { 8 | 9 | /** 10 | * Our GL surface. It will hold the rendered the camera image on the background and the frames of all detected tags. 11 | * 12 | * @param context Current context 13 | * @param camController The camera controller that holds the camera image buffer 14 | * @param chilitags The Chilitags3D object that detects tags and calculates their transforms w.r.t the camera 15 | * @param camCalib Camera calibration matrix that was fed to Chilitags3D 16 | * @param xScale The inverse of the downscale value that was induced to the Chilitags processing image width vs. the camera image width 17 | * @param yScale The inverse of the downscale value that was induced to the Chilitags processing image height vs. the camera image height 18 | */ 19 | public CameraPreviewGLSurfaceView(Context context, CameraController camController, Chilitags3D chilitags, double[] camCalib, double xScale, double yScale) { 20 | super(context); 21 | setEGLContextClientVersion(2); //We're declaring that we're using GLES 2.0 22 | setRenderer(new CameraPreviewRenderer(camController,chilitags,camCalib,xScale,yScale)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /platforms/jni/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_FIND_ROOT_PATH_OLD ${CMAKE_FIND_ROOT_PATH}) #A small hack to search for Java in our host system 2 | set(CMAKE_FIND_ROOT_PATH /) 3 | find_package(Java REQUIRED) 4 | include(UseJava) 5 | include(UseJavaExtensions) #Our custom Java extensions 6 | set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH_OLD}) 7 | 8 | #For finding jni.h while we're not on an Android toolchain 9 | if(NOT ANDROID) 10 | find_package(JNI REQUIRED) 11 | include_directories(${JNI_INCLUDE_DIRS}) 12 | endif() 13 | 14 | file(GLOB_RECURSE chilitags_jni_bindings_source *.cpp) 15 | file(GLOB_RECURSE chilitags_jni_wrapper_source *.java) 16 | 17 | add_library( 18 | chilitags_jni_bindings 19 | SHARED 20 | ${chilitags_jni_bindings_source} 21 | ) 22 | 23 | target_link_libraries(chilitags_jni_bindings chilitags) 24 | 25 | install (TARGETS chilitags_jni_bindings 26 | LIBRARY DESTINATION lib 27 | ARCHIVE DESTINATION lib 28 | ) 29 | 30 | set(CMAKE_JAVA_COMPILE_FLAGS ${CMAKE_JAVA_COMPILE_FLAGS} -encoding UTF-8) 31 | add_jar(chilitags-jni-wrapper ${chilitags_jni_wrapper_source}) 32 | add_jar_no_compile(chilitags-jni-wrapper-sources ${chilitags_jni_wrapper_source}) 33 | 34 | if(ANDROID_INSTALL_LIBRARIES) 35 | 36 | install(TARGETS chilitags_jni_bindings 37 | LIBRARY DESTINATION ${ANDROID_PROJECT_ROOT}/libs/$ENV{ANDROID_ABI}/ 38 | ARCHIVE DESTINATION ${ANDROID_PROJECT_ROOT}/libs/$ENV{ANDROID_ABI}/ 39 | ) 40 | 41 | install_jar(chilitags-jni-wrapper ${ANDROID_PROJECT_ROOT}/libs/) 42 | install_jar(chilitags-jni-wrapper-sources ${ANDROID_PROJECT_ROOT}/libs/) 43 | endif() 44 | -------------------------------------------------------------------------------- /platforms/jni/src/ch/epfl/chili/chilitags/CVSize.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 EPFL * 3 | * * 4 | * This file is part of chilitags. * 5 | * * 6 | * Chilitags is free software: you can redistribute it and/or modify * 7 | * it under the terms of the Lesser GNU General Public License as * 8 | * published by the Free Software Foundation, either version 3 of the * 9 | * License, or (at your option) any later version. * 10 | * * 11 | * Chilitags is distributed in the hope that it will be useful, * 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 14 | * GNU Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public License * 17 | * along with Chilitags. If not, see . * 18 | *******************************************************************************/ 19 | 20 | package ch.epfl.chili.chilitags; 21 | 22 | /** 23 | * Simple wrapper for CV::Size. 24 | * 25 | * @author Ayberk Özgür 26 | * 27 | */ 28 | public class CVSize{ 29 | public int height; 30 | public int width; 31 | 32 | public CVSize(){ 33 | height = -1; 34 | width = -1; 35 | } 36 | } -------------------------------------------------------------------------------- /src/GrowRoi.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef GrowRoi_HPP 22 | #define GrowRoi_HPP 23 | 24 | #include 25 | 26 | namespace chilitags { 27 | 28 | cv::Rect growRoi( 29 | const cv::Mat &inputImage, 30 | cv::InputArray points, 31 | float growthRatio); 32 | 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /share/tag_configuration_sample.yml: -------------------------------------------------------------------------------- 1 | %YAML:1.0 2 | # This file describes how tags are placed on objects. 3 | # 4 | # This can also be used to provide tag aliases, or transform the computed 5 | # origin of a tag. 6 | # 7 | # This sample file define 3 objects, and covers the different options 8 | # available. 9 | 10 | # This first object has only one tag (ID 0). 'myobject1' is the name returned 11 | # by the object detector. The size of the tag is 20x20 (the unit does not 12 | # matter, but must be consistent with the calibration unit. We recommend to use 13 | # millimeters). 14 | # This simple declaration allows to define name aliases for tags. 'tag' 15 | # and 'size' are the only two mandatory fields. 16 | myobject1: 17 | - tag: 0 18 | size: 20 19 | 20 | # The second object also has a single tag, but translated and rotated. The 21 | # origin of 'myobject2' is will be 10 units *below* the tag, on the object's X 22 | # axis, and the tag is rotated by 90 degrees along the object's Z axis. 23 | # Rotations must be specified in degrees as XYZ Euler rotations, ie a rotation 24 | # on the X axis followed by a rotation on the Y axis, followed by a rotation on 25 | # the Z axis. 26 | myobject2: 27 | - tag: 1 28 | size: 30 29 | translation: [10., 0., 0.] 30 | rotation: [0., 0., 90.] 31 | 32 | # The third object features 3 tags, of various size, and at various positions. 33 | # Here, the rotation is omitted (defaults to [0.,0.,0.]). 34 | # If a tag sets the option 'keep' to '1', the tag 3D position is 35 | # returned besides the object. By default, object components are not kept, but 36 | # you can explicitely set keep to '0'. 37 | myobject3: 38 | - tag: 2 39 | size: 20 40 | translation: [-50., -100., 0.0] 41 | keep: 1 42 | - tag: 3 43 | size: 30 44 | translation: [50., -100., 0.0] 45 | keep: 0 46 | - tag: 4 47 | size: 30 48 | translation: [50., 100., 0.0] 49 | 50 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright 2013-2014 EPFL # 3 | # Copyright 2013-2014 Quentin Bonnard # 4 | # # 5 | # This file is part of chilitags. # 6 | # # 7 | # Chilitags is free software: you can redistribute it and/or modify # 8 | # it under the terms of the Lesser GNU General Public License as # 9 | # published by the Free Software Foundation, either version 3 of the # 10 | # License, or (at your option) any later version. # 11 | # # 12 | # Chilitags is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 15 | # GNU Lesser General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU Lesser General Public License # 18 | # along with Chilitags. If not, see . # 19 | ################################################################################ 20 | 21 | if(NOT OPENCV_HIGHGUI_FOUND) 22 | message(FATAL_ERROR "OpenCV compiled without support for highgui! Can not compile detector.") 23 | endif() 24 | 25 | add_executable(chilitags-creator creator/creator.cpp) 26 | target_link_libraries( chilitags-creator ${OpenCV_LIBS} ) 27 | target_link_libraries( chilitags-creator chilitags ) 28 | install(TARGETS chilitags-creator RUNTIME DESTINATION bin) 29 | -------------------------------------------------------------------------------- /src/Refine.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef Refine_HPP 22 | #define Refine_HPP 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | 30 | namespace chilitags { 31 | 32 | class Refine 33 | { 34 | public: 35 | 36 | Refine(); 37 | 38 | Quad operator()( 39 | const cv::Mat &inputImage, 40 | const Quad &quad, 41 | const float proximityRatio); 42 | 43 | }; 44 | 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/EnsureGreyscale.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef EnsureGreyscale_HPP 22 | #define EnsureGreyscale_HPP 23 | 24 | #include 25 | 26 | #include 27 | 28 | namespace chilitags { 29 | 30 | class EnsureGreyscale 31 | { 32 | public: 33 | 34 | EnsureGreyscale(); 35 | 36 | const cv::Mat & operator()(const cv::Mat & inputImage); 37 | 38 | protected: 39 | 40 | cv::Mat mOutputImage; 41 | 42 | }; 43 | 44 | 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/ScreenOut.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef SCREENOUT_HPP 22 | #define SCREENOUT_HPP 23 | 24 | /** 25 | * @file ScreenOut.hpp 26 | * @brief Contains fast and simple methods to screen out things that are obviously not tags 27 | * @author Ayberk Özgür 28 | */ 29 | 30 | #include 31 | 32 | namespace chilitags { 33 | 34 | class ScreenOut 35 | { 36 | public: 37 | 38 | static bool isConvex(Quad const& quad); 39 | }; 40 | 41 | } /* namespace chilitags */ 42 | 43 | #endif /* SCREENOUT_HPP */ 44 | -------------------------------------------------------------------------------- /src/FindQuads.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef FindQuads_H 22 | #define FindQuads_H 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | namespace chilitags { 30 | 31 | class FindQuads 32 | { 33 | public: 34 | FindQuads(); 35 | 36 | std::vector operator()(const cv::Mat &greyscaleImage); 37 | 38 | void setMinInputWidth(int minWidth) {mMinInputWidth = minWidth;} 39 | 40 | protected: 41 | 42 | std::vector mGrayPyramid; 43 | std::vector mBinaryPyramid; 44 | int mMinInputWidth; 45 | 46 | }; 47 | 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/src/ch/epfl/chili/chilitags/samples/estimate3d_gui/Estimate3DGUIActivity.java: -------------------------------------------------------------------------------- 1 | package ch.epfl.chili.chilitags.samples.estimate3d_gui; 2 | 3 | import ch.epfl.chili.chilitags.Chilitags3D; 4 | import android.os.Bundle; 5 | import android.app.Activity; 6 | 7 | public class Estimate3DGUIActivity extends Activity { 8 | 9 | private CameraController camController; //The camera controller object that holds the device camera object and 10 | private Chilitags3D chilitags; //The chilitags object 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | 16 | //Create and initialize the camera controller 17 | camController = new CameraController(); 18 | camController.onStart(); 19 | 20 | //Create the Chilitags object (which also creates its native counterpart) 21 | //The default Android camera color space is YUV_NV21 22 | chilitags = new Chilitags3D(camController.cameraWidth,camController.cameraHeight, 23 | camController.processingWidth,camController.processingHeight,Chilitags3D.InputType.YUV_NV21); 24 | 25 | //A simple camera calibration based on a lot of assumptions 26 | double[] cc = { 27 | 270, 0, camController.processingWidth/2, 28 | 0, 270, camController.processingHeight/2, 29 | 0, 0, 1}; 30 | double[] dc = {}; 31 | chilitags.setCalibration(cc,dc); 32 | 33 | //Create the surface that we will draw on using GLES 2.0 34 | setContentView(new CameraPreviewGLSurfaceView(this,camController,chilitags,cc, 35 | (double)camController.cameraWidth/camController.processingWidth, 36 | (double)camController.cameraHeight/camController.processingHeight)); 37 | } 38 | 39 | @Override 40 | protected void onStart(){ 41 | super.onStart(); 42 | camController.onStart(); 43 | } 44 | 45 | @Override 46 | protected void onResume(){ 47 | super.onResume(); 48 | camController.onResume(); 49 | } 50 | 51 | @Override 52 | protected void onPause(){ 53 | super.onPause(); 54 | camController.onPause(); 55 | } 56 | 57 | @Override 58 | protected void onStop(){ 59 | super.onStop(); 60 | camController.onStop(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/ReadBits.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef ReadBits_HPP 22 | #define ReadBits_HPP 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | namespace chilitags { 30 | 31 | class ReadBits 32 | { 33 | public: 34 | ReadBits(); 35 | 36 | const std::vector &operator()(const cv::Mat &inputImage, const Quad &corners); 37 | 38 | protected: 39 | 40 | std::vector mSamplePoints; 41 | std::vector mTransformedSamplePoints; 42 | cv::Mat mSamples; 43 | 44 | std::vector mBits; 45 | 46 | }; 47 | 48 | 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/EnsureGreyscale.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include "EnsureGreyscale.hpp" 22 | #include 23 | 24 | namespace chilitags{ 25 | 26 | EnsureGreyscale::EnsureGreyscale() : mOutputImage(){ 27 | } 28 | 29 | const cv::Mat &EnsureGreyscale::operator()(const cv::Mat &inputImage) 30 | { 31 | if (inputImage.channels() != 1) { 32 | // assuming BGR 33 | cv::cvtColor(inputImage, mOutputImage, cv::COLOR_BGR2GRAY); 34 | } else { 35 | // Shallow copy 36 | mOutputImage = inputImage; 37 | } 38 | return mOutputImage; 39 | } 40 | 41 | } /* namespace chilitags */ 42 | -------------------------------------------------------------------------------- /platforms/jni/src/ch/epfl/chili/chilitags/ObjectTransform.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 EPFL * 3 | * * 4 | * This file is part of chilitags. * 5 | * * 6 | * Chilitags is free software: you can redistribute it and/or modify * 7 | * it under the terms of the Lesser GNU General Public License as * 8 | * published by the Free Software Foundation, either version 3 of the * 9 | * License, or (at your option) any later version. * 10 | * * 11 | * Chilitags is distributed in the hope that it will be useful, * 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 14 | * GNU Lesser General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU Lesser General Public License * 17 | * along with Chilitags. If not, see . * 18 | *******************************************************************************/ 19 | 20 | package ch.epfl.chili.chilitags; 21 | 22 | /** 23 | * Simple wrapper for the Chilitags3D object transform. 24 | * 25 | * @author Ayberk Özgür 26 | * 27 | */ 28 | public class ObjectTransform{ 29 | /** 30 | * The name of this object. 31 | */ 32 | public String name; 33 | 34 | /** 35 | * The transform 4x4 matrix, relative to the camera frame. 36 | */ 37 | public double[][] transform; 38 | 39 | /** 40 | * Creates a new ObjectTransform with empty name and identity transform. 41 | */ 42 | public ObjectTransform(){ 43 | name = ""; 44 | transform = new double[4][4]; 45 | for(int i=0;i<4;i++) 46 | for(int j=0;j<4;j++) 47 | transform[i][j] = i == j ? 1 : 0; 48 | } 49 | } -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/src/ch/epfl/chili/chilitags/samples/estimate3d_gui/shader/YUV2RGBShader.java: -------------------------------------------------------------------------------- 1 | package ch.epfl.chili.chilitags.samples.estimate3d_gui.shader; 2 | 3 | /** 4 | * YUV to RGB conversion shader. 5 | * @author Ayberk Özgür 6 | */ 7 | public class YUV2RGBShader extends Shader { 8 | 9 | @Override 10 | protected String getVertexShader() { 11 | return "attribute vec4 a_position; \n" + 12 | "attribute vec2 a_texCoord; \n" + 13 | "varying vec2 v_texCoord; \n" + 14 | 15 | "void main(){ \n" + 16 | " gl_Position = a_position; \n" + 17 | " v_texCoord = a_texCoord; \n" + 18 | "} \n"; 19 | } 20 | 21 | @Override 22 | protected String getFragmentShader() { 23 | return "#ifdef GL_ES \n" + 24 | "precision highp float; \n" + 25 | "#endif \n" + 26 | 27 | "varying vec2 v_texCoord; \n" + 28 | "uniform sampler2D y_texture; \n" + 29 | "uniform sampler2D uv_texture; \n" + 30 | 31 | "void main (void){ \n" + 32 | " float r, g, b, y, u, v; \n" + 33 | 34 | //We had put the Y values of each pixel to the R,G,B components by GL_LUMINANCE, 35 | //that's why we're pulling it from the R component, we could also use G or B 36 | " y = texture2D(y_texture, v_texCoord).r; \n" + 37 | 38 | //We had put the U and V values of each pixel to the A and R,G,B components of the 39 | //texture respectively using GL_LUMINANCE_ALPHA. Since U,V bytes are interspread 40 | //in the texture, this is probably the fastest way to use them in the shader 41 | " u = texture2D(uv_texture, v_texCoord).a - 0.5; \n" + 42 | " v = texture2D(uv_texture, v_texCoord).r - 0.5; \n" + 43 | 44 | //The numbers are just YUV to RGB conversion constants 45 | " r = y + 1.13983*v; \n" + 46 | " g = y - 0.39465*u - 0.58060*v; \n" + 47 | " b = y + 2.03211*u; \n" + 48 | 49 | //We finally set the RGB color of our pixel 50 | " gl_FragColor = vec4(r, g, b, 1.0); \n" + 51 | "} \n"; 52 | } 53 | 54 | @Override 55 | protected void loadUniforms() { /*No auto uniforms*/ } 56 | 57 | @Override 58 | protected void getUniformHandles() { /*No auto uniforms*/ } 59 | } 60 | -------------------------------------------------------------------------------- /samples/detection/detect-from-file.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include 22 | 23 | #include // imread 24 | 25 | #include 26 | using std::cout; 27 | 28 | 29 | int main(int argc, char* argv[]) 30 | { 31 | if (argc != 2) { 32 | cout 33 | << "Usage: chilitags-detect \n\n" 34 | << "Returns the list of detected tag id's in the image, one per line.\n"; 35 | return 1; 36 | } 37 | 38 | cv::Mat image = cv::imread(argv[1]); 39 | if(image.data) { 40 | for (const auto &tag : chilitags::Chilitags().find(image)) 41 | cout << tag.first << "\n"; 42 | 43 | return 0; 44 | } 45 | return 1; 46 | } 47 | -------------------------------------------------------------------------------- /src/Track.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef Track_HPP 22 | #define Track_HPP 23 | 24 | #include 25 | #ifdef HAS_MULTITHREADING 26 | #include 27 | #endif 28 | 29 | #include 30 | 31 | #include 32 | #include "Refine.hpp" 33 | 34 | namespace chilitags { 35 | 36 | class Track 37 | { 38 | public: 39 | 40 | Track(); 41 | 42 | //Both these methods are thread-safe 43 | void update(TagCornerMap const& tags); 44 | TagCornerMap operator()(cv::Mat const& inputImage); 45 | 46 | protected: 47 | 48 | Refine mRefine; 49 | 50 | cv::Mat mPrevFrame; 51 | TagCornerMap mFromTags; 52 | 53 | #ifdef HAS_MULTITHREADING 54 | pthread_mutex_t mInputLock; 55 | #endif 56 | 57 | }; 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/ScreenOut.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | /** 22 | * @file ScreenOut.cpp 23 | * @brief Contains fast and simple methods to screen out things that are obviously not tags 24 | * @author Ayberk Özgür 25 | */ 26 | 27 | #include "ScreenOut.hpp" 28 | 29 | namespace chilitags{ 30 | 31 | bool ScreenOut::isConvex(Quad const& quad) 32 | { 33 | int vPrevX, vPrevY, vNextX, vNextY; 34 | 35 | for(int c = 0, p = 3, n = 1; c < 4; c++, p = (p + 1)%4, n = (n + 1)%4){ 36 | vPrevX = quad(p,0) - quad(c,0); vPrevY = quad(p,1) - quad(c,1); 37 | vNextX = quad(n,0) - quad(c,0); vNextY = quad(n,1) - quad(c,1); 38 | if(vPrevX*vNextY > vPrevY*vNextX) 39 | return false; 40 | } 41 | 42 | return true; 43 | } 44 | 45 | } /* namespace chilitags */ 46 | -------------------------------------------------------------------------------- /src/Decode.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef Decode_HPP 22 | #define Decode_HPP 23 | 24 | #include 25 | #include "Codec.hpp" 26 | 27 | #include 28 | #include 29 | 30 | namespace chilitags { 31 | 32 | class Decode 33 | { 34 | public: 35 | static const int INVALID_TAG; 36 | 37 | Decode(); 38 | 39 | std::pair operator()( 40 | const std::vector &bits, 41 | const Quad &corners); 42 | 43 | const Codec &getCodec() const { 44 | return mCodec; 45 | } 46 | 47 | virtual ~Decode(); 48 | 49 | protected: 50 | 51 | unsigned char *mMatrix; 52 | unsigned char *mMatrix90; 53 | unsigned char *mMatrix180; 54 | unsigned char *mMatrix270; 55 | 56 | Codec mCodec; 57 | 58 | private: 59 | Decode(const Decode&); 60 | Decode& operator=(const Decode&); 61 | 62 | }; 63 | 64 | } 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/GrowRoi.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include "GrowRoi.hpp" 22 | #include 23 | 24 | cv::Rect chilitags::growRoi(const cv::Mat &inputImage, cv::InputArray points, float growthRatio) 25 | { 26 | // Taking a ROI around the raw corners with some margin 27 | cv::Rect roi = cv::boundingRect(points); 28 | int xGrowth = (int)(growthRatio*roi.width); 29 | int yGrowth = (int)(growthRatio*roi.height); 30 | roi.x -= xGrowth; 31 | roi.y -= yGrowth; 32 | roi.width += 2*xGrowth; 33 | roi.height += 2*yGrowth; 34 | 35 | // Making sure the ROI is still in the image 36 | int previousRoiX = roi.x; 37 | int previousRoiY = roi.y; 38 | roi.x = std::max(roi.x, 0); 39 | roi.y = std::max(roi.y, 0); 40 | roi.width -= roi.x - previousRoiX; 41 | roi.height -= roi.y - previousRoiY; 42 | roi.width = cv::min(roi.x+roi.width, inputImage.cols)-roi.x; 43 | roi.height = cv::min(roi.y+roi.height, inputImage.rows)-roi.y; 44 | 45 | return roi; 46 | } 47 | -------------------------------------------------------------------------------- /src/Filter.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | /** This header contains various utilities to paliate with imperfect detection. 22 | */ 23 | 24 | #ifndef Filter_HPP 25 | #define Filter_HPP 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | namespace chilitags { 33 | 34 | class FindOutdated { 35 | 36 | public: 37 | 38 | FindOutdated(int persistence); 39 | 40 | void setPersistence(int persistence) { 41 | mPersistence = persistence; 42 | } 43 | 44 | std::vector operator()(const std::map &tags); 45 | 46 | protected: 47 | 48 | int mPersistence; 49 | std::map mDisappearanceTime; 50 | 51 | }; 52 | 53 | 54 | 55 | class Filter { 56 | public: 57 | Filter(int persistence, float gain); 58 | 59 | void setPersistence(int persistence) { 60 | mFindOutdated.setPersistence(persistence); 61 | } 62 | 63 | void setGain(float gain) { 64 | mGain = gain; 65 | } 66 | 67 | const std::map & operator()( 68 | const std::map &tags) ; 69 | 70 | protected: 71 | FindOutdated mFindOutdated; 72 | float mGain; 73 | std::map mFilteredCoordinates; 74 | }; 75 | 76 | 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /samples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright 2013-2014 EPFL # 3 | # Copyright 2013-2014 Quentin Bonnard # 4 | # # 5 | # This file is part of chilitags. # 6 | # # 7 | # Chilitags is free software: you can redistribute it and/or modify # 8 | # it under the terms of the Lesser GNU General Public License as # 9 | # published by the Free Software Foundation, either version 3 of the # 10 | # License, or (at your option) any later version. # 11 | # # 12 | # Chilitags is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 15 | # GNU Lesser General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU Lesser General Public License # 18 | # along with Chilitags. If not, see . # 19 | ################################################################################ 20 | 21 | if(NOT OPENCV_HIGHGUI_FOUND) 22 | message(FATAL_ERROR "OpenCV compiled without support for highgui, cannot compile samples!") 23 | endif() 24 | 25 | add_executable( estimate3d 3destimation/estimate3d.cpp) 26 | target_link_libraries( estimate3d chilitags_static ) 27 | target_link_libraries( estimate3d ${OpenCV_LIBS} ) 28 | 29 | add_executable( estimate3d-gui 3destimation/estimate3d-gui.cpp) 30 | target_link_libraries( estimate3d-gui chilitags_static ) 31 | target_link_libraries( estimate3d-gui ${OpenCV_LIBS} ) 32 | 33 | add_executable( detect-live detection/detect-live.cpp) 34 | target_link_libraries( detect-live chilitags_static ) 35 | target_link_libraries( detect-live ${OpenCV_LIBS} ) 36 | 37 | add_executable( detect-from-file detection/detect-from-file.cpp) 38 | target_link_libraries( detect-from-file chilitags_static ) 39 | target_link_libraries( detect-from-file ${OpenCV_LIBS} ) 40 | 41 | add_executable( tracking tracking/tracking.cpp) 42 | target_link_libraries( tracking chilitags ) 43 | target_link_libraries( tracking ${OpenCV_LIBS} ) 44 | 45 | if(WITH_PTHREADS) 46 | add_executable( async-detection multithreaded/async-detection.cpp) 47 | target_link_libraries( async-detection chilitags ) 48 | target_link_libraries( async-detection ${OpenCV_LIBS} ) 49 | endif() 50 | 51 | add_executable( filter3d-gui 3dfiltering/filter3d-gui.cpp) 52 | target_link_libraries( filter3d-gui chilitags ) 53 | target_link_libraries( filter3d-gui ${OpenCV_LIBS} ) 54 | 55 | -------------------------------------------------------------------------------- /src/Detect.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef DETECT_HPP 22 | #define DETECT_HPP 23 | 24 | #include 25 | 26 | #ifdef HAS_MULTITHREADING 27 | #include 28 | #endif 29 | 30 | #include 31 | 32 | #include "FindQuads.hpp" 33 | #include "Decode.hpp" 34 | #include "Refine.hpp" 35 | #include "ReadBits.hpp" 36 | #include "Track.hpp" 37 | 38 | namespace chilitags { 39 | 40 | class Detect { 41 | 42 | public: 43 | 44 | Detect(); 45 | 46 | void setMinInputWidth(int minWidth); 47 | 48 | void setCornerRefinement(bool refineCorners); 49 | 50 | void operator()(cv::Mat const& inputImage, TagCornerMap& tags); 51 | 52 | #ifdef HAS_MULTITHREADING 53 | void launchBackgroundThread(Track& track); 54 | 55 | void shutdownBackgroundThread(); 56 | #endif 57 | 58 | protected: 59 | 60 | bool mRefineCorners; 61 | 62 | FindQuads mFindQuads; 63 | Refine mRefine; 64 | ReadBits mReadBits; 65 | Decode mDecode; 66 | 67 | cv::Mat mFrame; 68 | TagCornerMap mTags; 69 | 70 | void doDetection(TagCornerMap& tags); 71 | 72 | #ifdef HAS_MULTITHREADING 73 | Track* mTrack; 74 | 75 | pthread_t mBackgroundThread; 76 | 77 | bool mBackgroundRunning; 78 | bool mBackgroundShouldRun; 79 | bool mNeedFrame; 80 | 81 | pthread_cond_t mInputCond; 82 | pthread_mutex_t mInputLock; 83 | 84 | static void* dispatchRun(void* args); 85 | void run(); 86 | #endif 87 | 88 | }; 89 | 90 | } /* namespace chilitags */ 91 | 92 | #endif /* DETECT_HPP */ 93 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright 2013-2014 EPFL # 3 | # Copyright 2013-2014 Quentin Bonnard # 4 | # # 5 | # This file is part of chilitags. # 6 | # # 7 | # Chilitags is free software: you can redistribute it and/or modify # 8 | # it under the terms of the Lesser GNU General Public License as # 9 | # published by the Free Software Foundation, either version 3 of the # 10 | # License, or (at your option) any later version. # 11 | # # 12 | # Chilitags is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 15 | # GNU Lesser General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU Lesser General Public License # 18 | # along with Chilitags. If not, see . # 19 | ################################################################################ 20 | 21 | if(NOT OPENCV_TS_FOUND) 22 | message(FATAL_ERROR "OpenCV compiled without support for ts! Can not compile tests.") 23 | endif() 24 | 25 | set(TEST_DATA 26 | "${CMAKE_SOURCE_DIR}/test/data/" 27 | CACHE 28 | PATH 29 | "specify the root directory of the test data (absolute, or relative to the execution directory of the tests)") 30 | enable_testing() 31 | 32 | MACRO(declare_test) 33 | cmake_parse_arguments(declare_test "NEEDS_DATA" "TESTNAME" "CV_MODULES" ${ARGN} ) 34 | 35 | file(GLOB ${declare_test_TESTNAME}_source_files ${declare_test_TESTNAME}*.cpp) 36 | add_executable(${declare_test_TESTNAME} ${${declare_test_TESTNAME}_source_files}) 37 | 38 | target_link_libraries(${declare_test_TESTNAME} chilitags_static) 39 | target_link_libraries(${declare_test_TESTNAME} ${OpenCV_LIBS} ) 40 | 41 | add_test(${declare_test_TESTNAME} ${declare_test_TESTNAME}) 42 | 43 | if (${declare_test_NEEDS_DATA}) 44 | set_property(TEST ${declare_test_TESTNAME} PROPERTY ENVIRONMENT OPENCV_TEST_DATA_PATH=${TEST_DATA}) 45 | endif() 46 | endMACRO() 47 | 48 | include_directories(../src) 49 | 50 | declare_test(TESTNAME drawer) 51 | declare_test(TESTNAME codec) 52 | declare_test(TESTNAME Filter) 53 | declare_test(TESTNAME integration) 54 | declare_test(TESTNAME pose-estimation NEEDS_DATA) 55 | declare_test(TESTNAME detection-performance NEEDS_DATA) 56 | declare_test(TESTNAME float-precision NEEDS_DATA) 57 | 58 | add_executable(find-crash find-crash.cpp) 59 | target_link_libraries(find-crash chilitags) 60 | target_link_libraries(find-crash ${OpenCV_LIBS} ) 61 | -------------------------------------------------------------------------------- /tools/creator/creator.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | int main(int argc, char **argv) 30 | { 31 | if (argc <= 1) { 32 | std::cout << "Usage: " << argv[0] << " tagID [zoom [margin [red green blue]]]\n"; 33 | std::cout << " - tagId is the id of the tag to draw, between 0 and 1023,\n"; 34 | std::cout << " - zoom is a non null integer indicating the length in pixel\n"; 35 | std::cout << " of each bit of the tag matrix (default: 1).\n"; 36 | std::cout << " - margin is n if no white rectangle should be drawn around the tag,\n"; 37 | std::cout << " (make sure the black borders of the tag\n"; 38 | std::cout << " still contrast with where it is placed),\n"; 39 | std::cout << " - red, green and blue define the color with which to draw the tag.\n"; 40 | std::cout << " The darker, the better. Black is default and optimal.\n"; 41 | return 1; 42 | } 43 | 44 | std::string outputFilename = std::string(argv[1])+".png"; 45 | int tagId = std::atoi(argv[1]); 46 | int zoom = (argc > 2) ? std::atoi(argv[2]) : 1; 47 | bool noMargin = (argc > 3 && argv[3][0] == 'n'); 48 | cv::Scalar color = (argc > 6 ? cv::Scalar(std::atoi(argv[4]), std::atoi(argv[5]), std::atoi(argv[6])) : cv::Scalar(0,0,0)); 49 | 50 | cv::imwrite(outputFilename, chilitags::Chilitags().draw(tagId, zoom, !noMargin, color)); 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import ycm_core 3 | from clang_helpers import PrepareClangFlags 4 | 5 | # Set this to the absolute path to the folder (NOT the file!) containing the 6 | # compile_commands.json file to use that instead of 'flags'. See here for 7 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 8 | # Most projects will NOT need to set this to anything; you can just change the 9 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach. 10 | compilation_database_folder = '' 11 | 12 | # These are the compilation flags that will be used in case there's no 13 | # compilation database set. 14 | flags = [ 15 | '-Wall', 16 | '-std=c++11', 17 | '-stdlib=libc++', 18 | '-x', 19 | 'c++', 20 | '-I', 21 | '.', 22 | '-I', 23 | './include', 24 | '-isystem', 25 | '/usr/lib/c++/v1', 26 | '-isystem', 27 | '/usr/include/c++/4.8', 28 | '-isystem', 29 | '/usr/include/x86_64-linux-gnu/c++/4.8', 30 | '-isystem', 31 | '/usr/include/c++/4.8/backward', 32 | '-isystem', 33 | '/usr/lib/gcc/x86_64-linux-gnu/4.8/include', 34 | '-isystem', 35 | '/usr/local/include', 36 | '-isystem', 37 | '/usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed', 38 | '-isystem', 39 | '/usr/include/x86_64-linux-gnu', 40 | '-isystem', 41 | '/usr/include' 42 | ] 43 | 44 | if compilation_database_folder: 45 | database = ycm_core.CompilationDatabase(compilation_database_folder) 46 | else: 47 | database = None 48 | 49 | 50 | def DirectoryOfThisScript(): 51 | return os.path.dirname(os.path.abspath(__file__)) 52 | 53 | 54 | def MakeRelativePathsInFlagsAbsolute(flags, working_directory): 55 | if not working_directory: 56 | return flags 57 | new_flags = [] 58 | make_next_absolute = False 59 | path_flags = ['-isystem', '-I', '-iquote', '--sysroot='] 60 | for flag in flags: 61 | new_flag = flag 62 | 63 | if make_next_absolute: 64 | make_next_absolute = False 65 | if not flag.startswith('/'): 66 | new_flag = os.path.join(working_directory, flag) 67 | 68 | for path_flag in path_flags: 69 | if flag == path_flag: 70 | make_next_absolute = True 71 | break 72 | 73 | if flag.startswith(path_flag): 74 | path = flag[len(path_flag):] 75 | new_flag = path_flag + os.path.join(working_directory, path) 76 | break 77 | 78 | if new_flag: 79 | new_flags.append(new_flag) 80 | return new_flags 81 | 82 | 83 | def FlagsForFile(filename): 84 | if database: 85 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a 86 | # python list, but a "list-like" StringVec object 87 | compilation_info = database.GetCompilationInfoForFile(filename) 88 | final_flags = PrepareClangFlags( 89 | MakeRelativePathsInFlagsAbsolute( 90 | compilation_info.compiler_flags_, 91 | compilation_info.compiler_working_dir_), 92 | filename) 93 | else: 94 | relative_to = DirectoryOfThisScript() 95 | final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to) 96 | 97 | return { 98 | 'flags': final_flags, 99 | 'do_cache': True} 100 | -------------------------------------------------------------------------------- /src/Decode.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include "Decode.hpp" 22 | 23 | namespace chilitags{ 24 | 25 | const int Decode::INVALID_TAG = -1; 26 | const int DATA_SIZE = 6; 27 | 28 | Decode::Decode() : 29 | mMatrix (new unsigned char[DATA_SIZE*DATA_SIZE]), 30 | mMatrix90 (new unsigned char[DATA_SIZE*DATA_SIZE]), 31 | mMatrix180(new unsigned char[DATA_SIZE*DATA_SIZE]), 32 | mMatrix270(new unsigned char[DATA_SIZE*DATA_SIZE]), 33 | mCodec() 34 | { 35 | } 36 | 37 | Decode::~Decode() 38 | { 39 | delete[] mMatrix; 40 | delete[] mMatrix270; 41 | delete[] mMatrix180; 42 | delete[] mMatrix90; 43 | } 44 | 45 | std::pair Decode::operator()(const std::vector &bits, const Quad &corners) 46 | { 47 | for (int i = 0; i < DATA_SIZE; ++i) 48 | { 49 | for (int j = 0; j < DATA_SIZE; ++j) 50 | { 51 | unsigned char bit = bits[i*DATA_SIZE + j]; 52 | mMatrix [ i *DATA_SIZE + j ] = bit; 53 | mMatrix90 [(DATA_SIZE-1-j)*DATA_SIZE + i ] = bit; 54 | mMatrix180[(DATA_SIZE-1-i)*DATA_SIZE + (DATA_SIZE-1-j)] = bit; 55 | mMatrix270[ j *DATA_SIZE + (DATA_SIZE-1-i)] = bit; 56 | } 57 | } 58 | 59 | int orientation = -1; 60 | int id = INVALID_TAG; 61 | if (mCodec.decode(mMatrix , id)) orientation = 0; 62 | else if (mCodec.decode(mMatrix90 , id)) orientation = 1; 63 | else if (mCodec.decode(mMatrix180, id)) orientation = 2; 64 | else if (mCodec.decode(mMatrix270, id)) orientation = 3; 65 | 66 | //The dreadful Black Tag! 67 | if (id == 682) id = INVALID_TAG; 68 | 69 | cv::Mat_ originalCorners(corners, false); 70 | Quad orderedQuad; 71 | cv::Mat_ orderedCorners(orderedQuad, false); 72 | if (id != INVALID_TAG) 73 | { 74 | for (size_t i = 0; i < 4; ++i) { 75 | orderedCorners(i) = originalCorners((i+orientation) % 4); 76 | } 77 | } 78 | 79 | return std::make_pair(id, orderedQuad); 80 | } 81 | 82 | } /* namespace chilitags */ 83 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright 2013-2014 EPFL # 3 | # Copyright 2013-2014 Quentin Bonnard # 4 | # # 5 | # This file is part of chilitags. # 6 | # # 7 | # Chilitags is free software: you can redistribute it and/or modify # 8 | # it under the terms of the Lesser GNU General Public License as # 9 | # published by the Free Software Foundation, either version 3 of the # 10 | # License, or (at your option) any later version. # 11 | # # 12 | # Chilitags is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 15 | # GNU Lesser General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU Lesser General Public License # 18 | # along with Chilitags. If not, see . # 19 | ################################################################################ 20 | 21 | file(GLOB_RECURSE chilitags_source *.cpp) 22 | 23 | add_library( 24 | chilitags_static 25 | STATIC 26 | ${chilitags_source} 27 | ) 28 | add_library( 29 | chilitags 30 | SHARED 31 | ${chilitags_source} 32 | ) 33 | 34 | target_link_libraries(chilitags ${OpenCV_LIBS}) 35 | target_link_libraries(chilitags_static ${OpenCV_LIBS}) 36 | 37 | if(WITH_PTHREADS AND NOT DEFINED ANDROID) #Android pthreads don't require -lpthread 38 | target_link_libraries(chilitags pthread) 39 | target_link_libraries(chilitags_static pthread) 40 | endif() 41 | 42 | install (TARGETS chilitags chilitags_static 43 | LIBRARY DESTINATION lib 44 | ARCHIVE DESTINATION lib 45 | ) 46 | 47 | if(ANDROID_INSTALL_LIBRARIES) 48 | install(TARGETS chilitags 49 | LIBRARY DESTINATION ${ANDROID_PROJECT_ROOT}/libs/$ENV{ANDROID_ABI}/ 50 | ARCHIVE DESTINATION ${ANDROID_PROJECT_ROOT}/libs/$ENV{ANDROID_ABI}/ 51 | ) 52 | endif() 53 | 54 | file(GLOB_RECURSE chilitags_headers ../include/*) 55 | 56 | install(FILES 57 | ${chilitags_headers} 58 | DESTINATION include/chilitags 59 | ) 60 | 61 | ########################################## 62 | ## PKGCONFIG file ### 63 | ########################################## 64 | 65 | if(EXISTS "${CMAKE_SOURCE_DIR}/chilitags.pc.in") 66 | message(STATUS "configuring ${CMAKE_SOURCE_DIR}/chilitags.pc.in --> ${CMAKE_CURRENT_BINARY_DIR}/chilitags.pc") 67 | 68 | # build a list of -D<...> macros to store in pkgconfig CFlags 69 | get_directory_property(INTERNAL_COMPILE_FLAGS COMPILE_DEFINITIONS) 70 | foreach(DEF ${INTERNAL_COMPILE_FLAGS}) 71 | set(COMPILE_FLAGS "${COMPILE_FLAGS} -D${DEF}") 72 | endforeach() 73 | 74 | configure_file(${CMAKE_SOURCE_DIR}/chilitags.pc.in 75 | ${CMAKE_CURRENT_BINARY_DIR}/chilitags.pc 76 | @ONLY ) 77 | 78 | install(FILES 79 | ${CMAKE_CURRENT_BINARY_DIR}/chilitags.pc 80 | DESTINATION lib/pkgconfig 81 | ) 82 | else() 83 | message(STATUS "${CMAKE_SOURCE_DIR}/chilitags.pc.in not found!") 84 | 85 | endif() 86 | 87 | 88 | -------------------------------------------------------------------------------- /test/find-crash.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | // This file serves as an illustration of how to use Chilitags 22 | 23 | 24 | // This header contains the detection part 25 | #include 26 | 27 | // OpenCV goodness for I/O 28 | #include 29 | 30 | #include 31 | 32 | int main(int argc, char* argv[]) 33 | { 34 | int xRes = 640; 35 | int yRes = 480; 36 | int cameraIndex = 0; 37 | bool fromFile = argc == 2; 38 | if (argc > 2) { 39 | xRes = std::atoi(argv[1]); 40 | yRes = std::atoi(argv[2]); 41 | } 42 | if (argc > 3) { 43 | cameraIndex = std::atoi(argv[3]); 44 | } 45 | 46 | // The source of input images 47 | cv::VideoCapture capture; 48 | if (fromFile) { 49 | capture.open(argv[1]); 50 | } 51 | else { 52 | capture.open(cameraIndex); 53 | } 54 | 55 | if (!capture.isOpened()) 56 | { 57 | std::cerr << "Unable to initialise video capture." << std::endl; 58 | return 1; 59 | } 60 | 61 | if (!fromFile) { 62 | #ifdef OPENCV3 63 | capture.set(cv::CAP_PROP_FRAME_WIDTH, xRes); 64 | capture.set(cv::CAP_PROP_FRAME_HEIGHT, yRes); 65 | #else 66 | capture.set(CV_CAP_PROP_FRAME_WIDTH, xRes); 67 | capture.set(CV_CAP_PROP_FRAME_HEIGHT, yRes); 68 | #endif 69 | } 70 | 71 | cv::Mat inputImage; 72 | chilitags::Chilitags chilitags; 73 | 74 | std::cout 75 | << "The input of Chilitags::find() is saved as ./lastimage.png\n" 76 | << "If the program crashes, this file can be used to reproduce the crash.\n" 77 | << "\n" 78 | << "Usage: " << argv[0] << " videofile\n" 79 | << " to use a video file as input.\n" 80 | << " " << argv[0] << " [x-res y-res [camera-index]]\n" 81 | << " to use the live feed of a camera as input.\n" 82 | << "\n" 83 | << "Hit Ctrl-C to stop the program.\n" 84 | ; 85 | while(capture.read(inputImage)) { 86 | cv::imwrite("lastimage.png", inputImage); 87 | chilitags.find(inputImage); 88 | } 89 | capture.release(); 90 | std::cout << "Done.\n"; 91 | 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /tools/creator/README.md: -------------------------------------------------------------------------------- 1 | Chilitags Creator 2 | ================= 3 | 4 | `creator` program is used to generate images of Chilitags, to use with your favourite software to print the tags. 5 | We first give some guidelines relative to the use of such images to maximize the detection performance. 6 | We then decribe the few options that can be given to `creator`. 7 | 8 | 9 | Guidelines on designing and printing chilitags 10 | ---------------------------------------------- 11 | 12 | The detection of chilitags consists of two steps: 13 | First, high contrasts having a quadrilateral shape are detected. 14 | Second, the area inside the high contrast quadrilaterals are examined to determine the coded identifier, if any. 15 | 16 | The high contrast quadrilaterals come from the black border around chilitags. 17 | They are critical for the rest of the detection and decoding process. 18 | It is thus important to avoid to degrade them. 19 | The following guidelines should help in this purpuse: 20 | 21 | * The tag should be placed on a light background (white is best, light colors should work too) to make sure the border still contrasts with its surronding. 22 | 23 | * If there is another high contrast next to the borders, they can confuse the detection of the quadrilateral shape. 24 | Avoid placing chilitags too close from other borders. 25 | At minimum, surround the tag with a light border that is as wide as the black border of the tag. 26 | 27 | * The corners of the detected quadrilateral are refined to get a more precise position of the tag. 28 | Avoid placing the corners of chilitags next to other corners, to avoid noise in the detection. 29 | 30 | ![This figure illustrates the guidelines](./tagdesign.svg) 31 | 32 | Additional notes: 33 | 34 | * Some tags are known to be problematic. #22 is not recognized for an undetermined reason. #682 is completely black. 35 | 36 | * Each tags is assumed to be unique on the image. 37 | If more than one tag with the same identifier is present, the behavior is undetermined. 38 | 39 | Usage of `creator` 40 | ------------------ 41 | 42 | `creator` generates the image of the chilitags of the specified identifier 43 | 44 | ### Synopsis 45 | 46 | creator tagId [zoom [margin [red green blue]]] 47 | 48 | ### Description 49 | 50 | *tagId* is the id of the tag to draw, between 0 and 1023. 51 | The generated image will be called [tagId].png and placed in the folder of execution. 52 | 53 | *zoom* is a non null integer indicating the length in pixel of each bit of the tag matrix. 54 | By default, the black border has a size of 10x10 pixels, i.e. 1 pixel ber bit of the matrix. 55 | Some graphical editors (e.g. Inkscape) interpolate images when resized. 56 | As a result, the inside of the tag becomes blurry. 57 | It does not disturb the detection, as long as the outside, black border remains sharp, but for aesthetic reasons, it may be useful to provide a bigger size to `creator`. 58 | 59 | *margin* is n if and only if no white rectangle should be drawn around the tag. 60 | Make sure to follow the design and printing guidelines then. 61 | 62 | *red green blue* are integers within [0,255] which define the color with which 63 | to draw the tag. The darker, the better. Black is default and optimal. 64 | 65 | ### Examples 66 | 67 | * `./creator 42` will produce 42.png, a 14x14 pixels image of tag #42. The white padding is 2*1 pixels thick, the black border is 2*1 pixels thick, and the matrix is 6*1 pixels large. 68 | 69 | * `./creator 123 40` will produce 123.png, a 280x280 pixels image of tag #123. The white padding is 2*20 pixels thick, the black border is 2*20 pixels thick, and the matrix is 6*20 pixels large. 70 | 71 | * `./creator 321 1 n` will produce 321.png, a 10x10 pixels image of tag #321. There is no white padding, the black border is 2*1 pixels thick, and the matrix is 6*1 pixels large. 72 | 73 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/src/ch/epfl/chili/chilitags/samples/estimate3d_gui/GLESLine.java: -------------------------------------------------------------------------------- 1 | package ch.epfl.chili.chilitags.samples.estimate3d_gui; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.ByteOrder; 5 | import java.nio.FloatBuffer; 6 | 7 | import ch.epfl.chili.chilitags.samples.estimate3d_gui.shader.LineShader; 8 | import ch.epfl.chili.chilitags.samples.estimate3d_gui.shader.Shader; 9 | import android.opengl.GLES20; 10 | 11 | public class GLESLine { 12 | 13 | private FloatBuffer vertexBuffer; //The vertex buffer 14 | 15 | private Shader shader; //Our line shader that paints the pixels on the line 16 | 17 | protected int positionHandle; //The handle to the a_position attribute 18 | protected int colorHandle; //The handle to the v_color uniform 19 | 20 | //The line coordinate array 21 | static float lineCoords[] = { 22 | 0.0f, 0.0f, //Line end 1 23 | 1.0f, 0.0f //Line end 2 24 | }; 25 | 26 | //The line color 27 | float color[] = { 0.0f, 0.0f, 0.0f, 1.0f }; 28 | 29 | /** 30 | * Creates a new GLES line object. 31 | */ 32 | public GLESLine(){ 33 | 34 | //Create out line shader 35 | shader = new LineShader(); 36 | 37 | //Allocate space for our line coordinates in native space instead of JVM heap 38 | ByteBuffer buf = ByteBuffer.allocateDirect(4*4); 39 | buf.order(ByteOrder.nativeOrder()); 40 | 41 | //Get the float buffer that will contain the line coordinates 42 | vertexBuffer = buf.asFloatBuffer(); 43 | vertexBuffer.put(lineCoords); 44 | vertexBuffer.position(0); 45 | } 46 | 47 | /** 48 | * Sets the vertices that describe the ends of this line. 49 | * 50 | * @param x0 The X coordinate of one end 51 | * @param y0 The Y coordinate of one end 52 | * @param x1 The X coordinate of the other end 53 | * @param y1 The Y coordinate of the other end 54 | */ 55 | public void setVerts(float x0, float y0, float x1, float y1){ 56 | lineCoords[0] = x0; 57 | lineCoords[1] = y0; 58 | lineCoords[2] = x1; 59 | lineCoords[3] = y1; 60 | 61 | vertexBuffer.put(lineCoords); 62 | vertexBuffer.position(0); 63 | } 64 | 65 | /** 66 | * Sets the color of this line. 67 | * 68 | * @param red The red component 69 | * @param green The green component 70 | * @param blue The blue component 71 | * @param alpha The alpha component 72 | */ 73 | public void setColor(float red, float green, float blue, float alpha){ 74 | color[0] = red; 75 | color[1] = green; 76 | color[2] = blue; 77 | color[3] = alpha; 78 | } 79 | 80 | /** 81 | * Begins the usage of this line in the GL context. 82 | */ 83 | public void load(){ 84 | 85 | shader.load(); 86 | } 87 | 88 | /** 89 | * Draws this line. 90 | */ 91 | public void draw() { 92 | 93 | //Use our shader 94 | shader.begin(); 95 | 96 | //Get the handle to the a_position attribute of our shader code 97 | positionHandle = GLES20.glGetAttribLocation(shader.getHandle(), "a_position"); 98 | 99 | //Load our attribute array to the shader 100 | GLES20.glEnableVertexAttribArray(positionHandle); 101 | GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 2*4, vertexBuffer); 102 | 103 | //Get the handle to the v_color uniform of our shader code 104 | colorHandle = GLES20.glGetUniformLocation(shader.getHandle(), "v_color"); 105 | 106 | //Set color to the v_color uniform 107 | GLES20.glUniform4fv(colorHandle, 1, color, 0); 108 | 109 | //Draw the actual line 110 | GLES20.glDrawArrays(GLES20.GL_LINES, 0, 2); 111 | 112 | //Unload our vertex array 113 | GLES20.glDisableVertexAttribArray(positionHandle); 114 | } 115 | 116 | /** 117 | * Multiplies a 4x4 matrix by a 4-vector (from left). 118 | * 119 | * @param mat The 4x4 matrix 120 | * @param vec The 4-vector 121 | * @return The result, i.e mat*vec 122 | */ 123 | public static double[] multiply(double[][] mat, double[] vec){ 124 | double[] res = new double[4]; 125 | 126 | for(int i=0;i<4;i++) 127 | for(int j=0;j<4;j++) 128 | res[i] += mat[i][j]*vec[j]; 129 | 130 | return res; 131 | } 132 | } -------------------------------------------------------------------------------- /src/Refine.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include "Refine.hpp" 22 | 23 | #include "GrowRoi.hpp" 24 | #include 25 | 26 | //#define DEBUG_Refine 27 | #ifdef DEBUG_Refine 28 | #include 29 | #include 30 | #include 31 | #endif 32 | 33 | namespace chilitags{ 34 | 35 | Refine::Refine() 36 | { 37 | #ifdef DEBUG_Refine 38 | cv::namedWindow("Refine"); 39 | #endif 40 | } 41 | 42 | Quad Refine::operator()( 43 | const cv::Mat &inputImage, 44 | const Quad &quad, 45 | const float proximityRatio) 46 | { 47 | cv::Mat_ refinedQuad(quad); 48 | 49 | // Taking a ROI around the raw corners with some margin 50 | static const float GROWTH_RATIO = 1.2f/10.0f; 51 | cv::Rect roi = chilitags::growRoi(inputImage, refinedQuad, GROWTH_RATIO); 52 | 53 | static const int MIN_ROI_SIZE = 10; 54 | if (roi.width < MIN_ROI_SIZE || roi.height < MIN_ROI_SIZE) return quad; 55 | 56 | cv::Point2f roiOffset = roi.tl(); 57 | for (int i : {0,1,2,3}) refinedQuad(i) -= roiOffset; 58 | 59 | float averageSideLength = cv::arcLength(refinedQuad, true) / 4.0f; 60 | float cornerNeighbourhood = proximityRatio*averageSideLength; 61 | 62 | // ensure the cornerSubPixel search window is smaller that the ROI 63 | cornerNeighbourhood = cv::min(cornerNeighbourhood, (roi.width - 5.0f)/2.0f); 64 | cornerNeighbourhood = cv::min(cornerNeighbourhood, (roi.height - 5.0f)/2.0f); 65 | cornerNeighbourhood = cv::max(cornerNeighbourhood, 1.0f); 66 | 67 | cv::cornerSubPix(inputImage(roi), refinedQuad, 68 | cv::Size(cornerNeighbourhood, cornerNeighbourhood), 69 | cv::Size(-1, -1), cv::TermCriteria( 70 | cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS, 71 | 5, 0.01f)); 72 | 73 | #ifdef DEBUG_Refine 74 | cv::Mat debugImage = inputImage(roi).clone(); 75 | for(int i=0; i<4; ++i) 76 | { 77 | cv::circle(debugImage, refinedQuad(i), 3, cv::Scalar::all(128), 2); 78 | cv::line(debugImage, 79 | refinedQuad(i), refinedQuad(i), 80 | cv::Scalar::all(255), 5); 81 | cv::rectangle(debugImage, 82 | refinedQuad(i)-cv::Point2f(cornerNeighbourhood, cornerNeighbourhood), refinedQuad(i)+cv::Point2f(cornerNeighbourhood, cornerNeighbourhood), 83 | cv::Scalar::all(255)); 84 | printf("%1.1f %1.1f ", refinedQuad(i).x, refinedQuad(i).y); 85 | } 86 | printf("\n"); 87 | cv::imshow("Refine", debugImage); 88 | cv::waitKey(0); 89 | #endif 90 | 91 | for (int i : {0,1,2,3}) refinedQuad(i) += roiOffset; 92 | 93 | return refinedQuad.reshape(1); 94 | } 95 | 96 | } /* namespace chilitags */ 97 | -------------------------------------------------------------------------------- /samples/3destimation/estimate3d.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include // for cv::Mat 26 | #include // for camera capture 27 | 28 | using namespace std; 29 | using namespace cv; 30 | 31 | int main(int argc, char* argv[]) 32 | { 33 | cout 34 | << "Usage: "<< argv[0] 35 | << " [-c ] [-i ]\n"; 36 | 37 | const char* intrinsicsFilename = 0; 38 | const char* configFilename = 0; 39 | 40 | for( int i = 1; i < argc; i++ ) 41 | { 42 | if( strcmp(argv[i], "-c") == 0 ) 43 | configFilename = argv[++i]; 44 | else if( strcmp(argv[i], "-i") == 0 ) 45 | intrinsicsFilename = argv[++i]; 46 | } 47 | 48 | /*****************************/ 49 | /* Init camera capture */ 50 | /*****************************/ 51 | int cameraIndex = 0; 52 | cv::VideoCapture capture(cameraIndex); 53 | if (!capture.isOpened()) 54 | { 55 | cerr << "Unable to initialise video capture.\n"; 56 | return 1; 57 | } 58 | 59 | /******************************/ 60 | /* Setting up pose estimation */ 61 | /******************************/ 62 | #ifdef OPENCV3 63 | float inputWidth = capture.get(cv::CAP_PROP_FRAME_WIDTH); 64 | float inputHeight = capture.get(cv::CAP_PROP_FRAME_HEIGHT); 65 | #else 66 | float inputWidth = capture.get(CV_CAP_PROP_FRAME_WIDTH); 67 | float inputHeight = capture.get(CV_CAP_PROP_FRAME_HEIGHT); 68 | #endif 69 | 70 | chilitags::Chilitags3D chilitags3D(Size(inputWidth, inputHeight)); 71 | 72 | if (configFilename) chilitags3D.readTagConfiguration(configFilename); 73 | 74 | if (intrinsicsFilename) { 75 | Size calibratedImageSize = chilitags3D.readCalibration(intrinsicsFilename); 76 | #ifdef OPENCV3 77 | capture.set(cv::CAP_PROP_FRAME_WIDTH, calibratedImageSize.width); 78 | capture.set(cv::CAP_PROP_FRAME_HEIGHT, calibratedImageSize.height); 79 | #else 80 | capture.set(CV_CAP_PROP_FRAME_WIDTH, calibratedImageSize.width); 81 | capture.set(CV_CAP_PROP_FRAME_HEIGHT, calibratedImageSize.height); 82 | #endif 83 | } 84 | 85 | /*****************************/ 86 | /* Go! */ 87 | /*****************************/ 88 | cout << "I'm now looking for objects...\n"; 89 | cv::Mat inputImage; 90 | 91 | for (; 'q' != (char) cv::waitKey(10); ) { 92 | capture.read(inputImage); 93 | 94 | for (auto& kv : chilitags3D.estimate(inputImage)) { 95 | cout << kv.first << " at " << Mat(kv.second) << "\n"; 96 | } 97 | } 98 | 99 | capture.release(); 100 | 101 | return 0; 102 | } 103 | 104 | -------------------------------------------------------------------------------- /test/integration.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifdef OPENCV3 22 | #include 23 | #else 24 | #include 25 | #endif 26 | 27 | #include 28 | 29 | TEST(Integration, Minimal) { 30 | int expectedId = 42; 31 | chilitags::Chilitags chilitags; 32 | // Tag needs to be > 12 px wide; 33 | int zoom = 3; 34 | cv::Mat image = chilitags.draw(expectedId, zoom, true); 35 | 36 | auto tags = chilitags.find(image); 37 | 38 | ASSERT_EQ(1, tags.size()); 39 | 40 | auto actualId = tags.cbegin()->first; 41 | EXPECT_EQ(expectedId, actualId); 42 | 43 | float close = zoom*2.0f; 44 | float far = zoom*12.0f; 45 | chilitags::Quad expectedCorners = { 46 | close, close, 47 | far , close, 48 | far , far , 49 | close, far 50 | }; 51 | 52 | // A pixel is a 1x1 square around its center 53 | cv::add(expectedCorners, cv::Scalar::all(-0.5f), expectedCorners); 54 | 55 | auto actualCorners = tags.cbegin()->second; 56 | for (int i : {0,1,2,3}) { 57 | EXPECT_GT(0.1f, cv::norm(actualCorners.row(i) - expectedCorners.row(i))) 58 | << "with i=" << i; 59 | } 60 | } 61 | 62 | TEST(Integration, MaxWidth) { 63 | int expectedId = 42; 64 | chilitags::Chilitags chilitags; 65 | int zoom = 300; 66 | cv::Mat image = chilitags.draw(expectedId, zoom, true); 67 | int tagSize = 2+10+2; 68 | ASSERT_EQ(image.cols, tagSize*zoom); 69 | 70 | //"burn" the input (initialiaze buffers, read from disk...) 71 | chilitags.find(image); 72 | 73 | //without setMaxInputWidth 74 | auto startCount = cv::getTickCount(); 75 | auto tagsWithout = chilitags.find(image); 76 | auto endCount = cv::getTickCount(); 77 | auto timeWithout = endCount - startCount; 78 | 79 | //with setMaxInputWidth 80 | int smallerImageSize = image.cols/10; 81 | chilitags.setMaxInputWidth(smallerImageSize); 82 | startCount = cv::getTickCount(); 83 | auto tagsWith = chilitags.find(image); 84 | endCount = cv::getTickCount(); 85 | auto timeWith = endCount - startCount; 86 | 87 | EXPECT_GT(timeWithout, timeWith); 88 | 89 | ASSERT_EQ(tagsWith.size(), tagsWithout.size()); 90 | 91 | for (auto withIt = tagsWith.cbegin(), withoutIt = tagsWithout.cbegin(); 92 | withIt != tagsWith.cend(); 93 | ++withIt, ++withoutIt) { 94 | 95 | EXPECT_EQ(withIt->first, withoutIt->first); 96 | 97 | for (int i : {0,1,2,3}) { 98 | EXPECT_GT(3.0f, cv::norm( 99 | withIt->second.row(i) - 100 | withoutIt->second.row(i))) 101 | << "with i=" << i 102 | << ",\n withIt[i]=" << withIt->second.row(i) 103 | << ",\n withoutIt[i]=" << withoutIt->second.row(i); 104 | } 105 | } 106 | } 107 | 108 | CV_TEST_MAIN(".") 109 | -------------------------------------------------------------------------------- /test/codec.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifdef OPENCV3 22 | #include 23 | #else 24 | #include 25 | #endif 26 | 27 | #include 28 | #include 29 | 30 | #include "HardcodedIds.hpp" 31 | 32 | using namespace cv; 33 | using namespace cvtest; 34 | using namespace std; 35 | 36 | TEST(Codec, Code) { 37 | chilitags::Codec codec; 38 | 39 | HardcodedIds hardcodedIds; 40 | 41 | for (int i = 0; i<1024; ++i) { 42 | unsigned char bits[36]; 43 | codec.getTagEncodedId(i, bits); 44 | for (int j = 0; j<36; ++j) { 45 | ASSERT_EQ(hardcodedIds.id[i][j], bits[j]); 46 | } 47 | } 48 | } 49 | 50 | TEST(Codec, DecodeNoError) { 51 | chilitags::Codec codec; 52 | 53 | HardcodedIds hardcodedIds; 54 | 55 | for (int i = 0; i<1024; ++i) { 56 | unsigned char bits[36]; 57 | for (int j = 0; j<36; ++j) { 58 | bits[j] = hardcodedIds.id[i][j]; 59 | } 60 | 61 | int decodedId; 62 | 63 | ASSERT_TRUE(codec.decode(bits, decodedId)); 64 | ASSERT_EQ(i, decodedId); 65 | } 66 | } 67 | 68 | TEST(Codec, Decode1Error) { 69 | chilitags::Codec codec; 70 | 71 | HardcodedIds hardcodedIds; 72 | 73 | for (int i = 0; i<1024; ++i) { 74 | unsigned char bits[36]; 75 | for (int j = 0; j<36; ++j) { 76 | bits[j] = hardcodedIds.id[i][j]; 77 | } 78 | 79 | for (int error1 = 0; error1<36; ++error1) { 80 | bits[error1] = 1-bits[error1]; 81 | 82 | int decodedId; 83 | ASSERT_TRUE(codec.decode(bits, decodedId)); 84 | ASSERT_EQ(i, decodedId); 85 | 86 | bits[error1] = 1-bits[error1]; 87 | } 88 | } 89 | } 90 | 91 | TEST(Codec, Decode2Errors) { 92 | chilitags::Codec codec; 93 | 94 | HardcodedIds hardcodedIds; 95 | 96 | for (int i = 0; i<1024; ++i) { 97 | unsigned char bits[36]; 98 | for (int j = 0; j<36; ++j) { 99 | bits[j] = hardcodedIds.id[i][j]; 100 | } 101 | 102 | for (int error1 = 0; error1<36; ++error1) { 103 | bits[error1] = 1-bits[error1]; 104 | 105 | for (int error2 = error1+1; error2<36; ++error2) { 106 | bits[error2] = 1-bits[error2]; 107 | 108 | int decodedId; 109 | ASSERT_TRUE(codec.decode(bits, decodedId)); 110 | ASSERT_EQ(i, decodedId); 111 | 112 | bits[error2] = 1-bits[error2]; 113 | } 114 | 115 | bits[error1] = 1-bits[error1]; 116 | } 117 | } 118 | } 119 | 120 | TEST(Codec, InterfaceWrapper) { 121 | chilitags::Chilitags chilitags; 122 | cv::Matx matrix = chilitags.encode(42); 123 | EXPECT_EQ(42, chilitags.decode(matrix)); 124 | } 125 | 126 | CV_TEST_MAIN(".") 127 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/src/ch/epfl/chili/chilitags/samples/estimate3d_gui/shader/Shader.java: -------------------------------------------------------------------------------- 1 | package ch.epfl.chili.chilitags.samples.estimate3d_gui.shader; 2 | 3 | import android.opengl.GLES20; 4 | import android.util.Log; 5 | 6 | /** 7 | * Base class for a GLSL shader. 8 | * @author Ayberk Özgür 9 | */ 10 | public abstract class Shader { 11 | 12 | /** 13 | * The GL program handle (i.e name) 14 | */ 15 | private int programHandle; 16 | 17 | /** 18 | * Compiles and loads the shader 19 | */ 20 | public void load(){ 21 | programHandle = loadProgram(getVertexShader(), getFragmentShader()); 22 | getUniformHandles(); 23 | } 24 | 25 | /** 26 | * Gets the GL program handle (i.e name) 27 | * @return The GL program handle 28 | */ 29 | public int getHandle(){ 30 | return programHandle; 31 | } 32 | 33 | /** 34 | * Loads the shader and uniforms for rendering 35 | */ 36 | public void begin(){ 37 | 38 | //Load the shader program object 39 | GLES20.glUseProgram(getHandle()); 40 | 41 | //Load the auto uniforms 42 | loadUniforms(); 43 | } 44 | 45 | /** 46 | * Loads the uniforms that can be loaded automatically without manual implementation 47 | */ 48 | protected abstract void loadUniforms(); 49 | 50 | /** 51 | * Gets the handles of the uniforms that can be loaded automatically without manual implementation 52 | */ 53 | protected abstract void getUniformHandles(); 54 | 55 | /** 56 | * Gets the vertex shader code 57 | * @return The vertex shader code 58 | */ 59 | protected abstract String getVertexShader(); 60 | 61 | /** 62 | * Gets the fragment shader code 63 | * @return The fragment shader code 64 | */ 65 | protected abstract String getFragmentShader(); 66 | 67 | /** 68 | * Compiles the given shader code and returns its program handle. 69 | * 70 | * @param type The type of the shader 71 | * @param source The GLSL source code of the shader 72 | * @return The program handle of the compiled shader 73 | */ 74 | private static int loadShader(int type, String source) { 75 | int shader; 76 | int[] compiled = new int[1]; 77 | 78 | //Create the shader object 79 | shader = GLES20.glCreateShader(type); 80 | if(shader == 0) 81 | return 0; 82 | 83 | //Load the shader source 84 | GLES20.glShaderSource(shader, source); 85 | 86 | //Compile the shader 87 | GLES20.glCompileShader(shader); 88 | 89 | //Check the compile status 90 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); 91 | 92 | if(compiled[0] == 0){ 93 | Log.e("ESShader", GLES20.glGetShaderInfoLog(shader)); 94 | GLES20.glDeleteShader(shader); 95 | return 0; 96 | } 97 | return shader; 98 | } 99 | 100 | /** 101 | * Compiles and links the individual shaders into a complete program and returns the program handle. 102 | * 103 | * @param vertexShaderSource The vertex shader GLSL source code 104 | * @param fragmentShaderSource The fragment shader GLSL source code 105 | * @return The handle of the shader program 106 | */ 107 | private static int loadProgram(String vertexShaderSource, String fragmentShaderSource) { 108 | int vertexShader; 109 | int fragmentShader; 110 | int programObject; 111 | int[] linked = new int[1]; 112 | 113 | //Load the vertex/fragment shaders 114 | vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderSource); 115 | if(vertexShader == 0) 116 | return 0; 117 | 118 | fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderSource); 119 | if(fragmentShader == 0){ 120 | GLES20.glDeleteShader(vertexShader); 121 | return 0; 122 | } 123 | 124 | //Create the program object 125 | programObject = GLES20.glCreateProgram(); 126 | 127 | if(programObject == 0) 128 | return 0; 129 | 130 | GLES20.glAttachShader(programObject, vertexShader); 131 | GLES20.glAttachShader(programObject, fragmentShader); 132 | 133 | //Link the program 134 | GLES20.glLinkProgram(programObject); 135 | 136 | //Check the link status 137 | GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0); 138 | 139 | if(linked[0] == 0){ 140 | Log.e("ESShader", "Error linking program:"); 141 | Log.e("ESShader", GLES20.glGetProgramInfoLog(programObject)); 142 | GLES20.glDeleteProgram(programObject); 143 | return 0; 144 | } 145 | 146 | //Free up no longer needed shader resources 147 | GLES20.glDeleteShader(vertexShader); 148 | GLES20.glDeleteShader(fragmentShader); 149 | 150 | return programObject; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /cmake/UseJavaExtensions.cmake: -------------------------------------------------------------------------------- 1 | 2 | #Hack of the add_jar function to make source jar without compiling for documentation purposes 3 | #Combines all the input files into a jar 4 | function(add_jar_no_compile _TARGET_NAME) 5 | set(_JAVA_SOURCE_FILES ${ARGN}) 6 | 7 | if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR) 8 | set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) 9 | endif(NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR) 10 | 11 | if (LIBRARY_OUTPUT_PATH) 12 | set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}) 13 | else (LIBRARY_OUTPUT_PATH) 14 | set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR}) 15 | endif (LIBRARY_OUTPUT_PATH) 16 | 17 | set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar") 18 | if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION) 19 | set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") 20 | set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") 21 | elseif (CMAKE_JAVA_TARGET_VERSION) 22 | set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") 23 | set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar") 24 | elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME) 25 | set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") 26 | endif (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION) 27 | # reset 28 | set(CMAKE_JAVA_TARGET_OUTPUT_NAME) 29 | 30 | #Prepare source files 31 | add_custom_target("${_TARGET_NAME}_COPY") 32 | set(_JAVA_RESOURCE_FILES) 33 | foreach(_JAVA_SOURCE_FILE ${_JAVA_SOURCE_FILES}) 34 | 35 | #Remove the absolute path prefix from source files to leave e.g ./ch/epfl/chili/chilitags/Chilitags3D.java 36 | #Remove only from the beginning of path 37 | STRING(REGEX REPLACE "^${CMAKE_CURRENT_SOURCE_DIR}" "." _JAVA_SOURCE_FILE_RELATIVE ${_JAVA_SOURCE_FILE}) 38 | SET(_JAVA_RESOURCE_FILES ${_JAVA_RESOURCE_FILES} ${_JAVA_SOURCE_FILE_RELATIVE}) 39 | 40 | #Copy source files to build directory so that they can be found during creation of jar 41 | #They need to be in the local directory to be put inside the correct directories in the jar 42 | add_custom_command(TARGET "${_TARGET_NAME}_COPY" PRE_BUILD 43 | COMMAND ${CMAKE_COMMAND} -E copy 44 | ${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE_RELATIVE} 45 | ${CMAKE_CURRENT_BINARY_DIR}/${_JAVA_SOURCE_FILE_RELATIVE} 46 | ) 47 | endforeach(_JAVA_SOURCE_FILE) 48 | 49 | # create the jar file 50 | set(_JAVA_JAR_OUTPUT_PATH 51 | ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME}) 52 | add_custom_command( 53 | OUTPUT ${_JAVA_JAR_OUTPUT_PATH} 54 | COMMAND ${Java_JAR_EXECUTABLE} 55 | -cf ${_JAVA_JAR_OUTPUT_PATH} ${_JAVA_RESOURCE_FILES} 56 | COMMAND ${CMAKE_COMMAND} 57 | -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} 58 | -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME} 59 | -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} 60 | -P ${_JAVA_SYMLINK_SCRIPT} 61 | WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH} 62 | DEPENDS "${_TARGET_NAME}_COPY" 63 | COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}" 64 | ) 65 | 66 | # Add the target and make sure we have the latest resource files. 67 | add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH}) 68 | 69 | set_property( 70 | TARGET 71 | ${_TARGET_NAME} 72 | PROPERTY 73 | INSTALL_FILES 74 | ${_JAVA_JAR_OUTPUT_PATH} 75 | ) 76 | 77 | if (_JAVA_TARGET_OUTPUT_LINK) 78 | set_property( 79 | TARGET 80 | ${_TARGET_NAME} 81 | PROPERTY 82 | INSTALL_FILES 83 | ${_JAVA_JAR_OUTPUT_PATH} 84 | ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} 85 | ) 86 | endif (_JAVA_TARGET_OUTPUT_LINK) 87 | 88 | set_property( 89 | TARGET 90 | ${_TARGET_NAME} 91 | PROPERTY 92 | JAR_FILE 93 | ${_JAVA_JAR_OUTPUT_PATH} 94 | ) 95 | 96 | set_property( 97 | TARGET 98 | ${_TARGET_NAME} 99 | PROPERTY 100 | CLASSDIR 101 | ${CMAKE_JAVA_CLASS_OUTPUT_PATH} 102 | ) 103 | 104 | endfunction(add_jar_no_compile) 105 | -------------------------------------------------------------------------------- /src/Track.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include "Track.hpp" 22 | #include "GrowRoi.hpp" 23 | #include "ScreenOut.hpp" 24 | 25 | #include "opencv2/video/tracking.hpp" 26 | 27 | namespace chilitags{ 28 | 29 | #ifdef HAS_MULTITHREADING 30 | Track::Track(): 31 | mRefine(), 32 | mPrevFrame(), 33 | mFromTags(), 34 | mInputLock(PTHREAD_MUTEX_INITIALIZER) 35 | #else 36 | Track::Track(): 37 | mRefine(), 38 | mPrevFrame(), 39 | mFromTags() 40 | #endif 41 | { 42 | } 43 | 44 | void Track::update(TagCornerMap const& tags) 45 | { 46 | #ifdef HAS_MULTITHREADING 47 | pthread_mutex_lock(&mInputLock); 48 | #endif 49 | 50 | auto targetIt = mFromTags.begin(); 51 | for(const auto& tag : tags){ 52 | while(targetIt != mFromTags.end() && targetIt->first < tag.first) 53 | targetIt++; 54 | 55 | if(targetIt != mFromTags.end() && targetIt->first == tag.first) 56 | targetIt->second = tag.second; 57 | else 58 | targetIt = mFromTags.insert(targetIt, tag); 59 | } 60 | 61 | #ifdef HAS_MULTITHREADING 62 | pthread_mutex_unlock(&mInputLock); 63 | #endif 64 | } 65 | 66 | TagCornerMap Track::operator()(cv::Mat const& grayscaleInputImage) 67 | { 68 | 69 | std::vector status; 70 | std::vector errors; 71 | 72 | //Do the tracking 73 | #ifdef HAS_MULTITHREADING 74 | pthread_mutex_lock(&mInputLock); 75 | #endif 76 | TagCornerMap trackedTags; 77 | Quad quad; 78 | for (auto tag : mFromTags) { 79 | Quad result; 80 | 81 | static const float GROWTH_RATIO = 20.0f/10.0f; 82 | cv::Rect roi = growRoi(grayscaleInputImage, cv::Mat_(tag.second), GROWTH_RATIO); 83 | cv::Point2f roiOffset = roi.tl(); 84 | for (int i : {0,1,2,3}) { 85 | tag.second(i,0) -= roiOffset.x; 86 | tag.second(i,1) -= roiOffset.y; 87 | } 88 | 89 | cv::calcOpticalFlowPyrLK( 90 | mPrevFrame(roi), grayscaleInputImage(roi), 91 | tag.second, result, 92 | status, errors, 93 | //TODO play with parameters (with tests) 94 | cv::Size(21,21), 3, 95 | cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 30, 0.01f) 96 | ); 97 | 98 | for (int i : {0,1,2,3}) { 99 | result(i,0) += roiOffset.x; 100 | result(i,1) += roiOffset.y; 101 | } 102 | 103 | if (cv::sum(cv::Mat(status))[0] == status.size()) { 104 | quad = mRefine(grayscaleInputImage, result, 0.5f/10.0f); 105 | if(ScreenOut::isConvex(quad)) 106 | trackedTags[tag.first] = quad; 107 | } 108 | } 109 | 110 | mFromTags = std::move(trackedTags); 111 | TagCornerMap tagsCopy = mFromTags; //TODO: Try to get around this copy 112 | #ifdef HAS_MULTITHREADING 113 | pthread_mutex_unlock(&mInputLock); 114 | #endif 115 | 116 | //Swap current and previous frames 117 | grayscaleInputImage.copyTo(mPrevFrame); 118 | 119 | return tagsCopy; 120 | } 121 | 122 | } /* namespace chilitags */ 123 | -------------------------------------------------------------------------------- /platforms/jni/samples/android-estimate3d-gui/src/ch/epfl/chili/chilitags/samples/estimate3d_gui/CameraController.java: -------------------------------------------------------------------------------- 1 | package ch.epfl.chili.chilitags.samples.estimate3d_gui; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | 6 | import android.graphics.SurfaceTexture; 7 | import android.hardware.Camera; 8 | import android.hardware.Camera.Size; 9 | import android.opengl.GLES20; 10 | 11 | public class CameraController implements Camera.PreviewCallback { 12 | 13 | private static byte[] image = null; //The image buffer that will hold the camera image when preview callback arrives 14 | 15 | private Camera camera = null; //The camera object 16 | 17 | //The camera image size 18 | public int cameraWidth = -1; 19 | public int cameraHeight = -1; 20 | 21 | //The image size that Chilitags will deal with 22 | public int processingWidth = -1; 23 | public int processingHeight = -1; 24 | 25 | //Dummy surface texture 26 | SurfaceTexture surf; 27 | 28 | /** 29 | * Initializes the camera 30 | */ 31 | public void onStart(){ 32 | 33 | //Only open the camera if it's not already open 34 | if(camera != null) 35 | return; 36 | 37 | //(Try to) Open the rear camera 38 | camera = Camera.open(0); 39 | 40 | //Tell the camera to call us when a preview is ready 41 | camera.setPreviewCallbackWithBuffer(this); 42 | 43 | //Set image size during preview 44 | Camera.Parameters params = camera.getParameters(); 45 | List sizeList = params.getSupportedVideoSizes(); //We don't get the preferred preview size because it somehow is a 4:3 size on a 16:9 camera 46 | if(sizeList != null){ 47 | Size[] sizes = sizeList.toArray(new Size[sizeList.size()]); 48 | cameraWidth = sizes[0].width; 49 | cameraHeight = sizes[0].height; 50 | } 51 | else{ //We might be on the emulator, set a very generic size that is 640x480 52 | cameraWidth = 640; 53 | cameraHeight = 480; 54 | } 55 | params.setPreviewSize(cameraWidth,cameraHeight); 56 | 57 | //Our YUV image is 12 bits per pixel 58 | if(image == null) 59 | image = new byte[cameraHeight*cameraWidth/8*12]; 60 | 61 | //Tell camera to autofocus continuously 62 | params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); 63 | 64 | //Set the parameters 65 | camera.setParameters(params); 66 | 67 | //Chilitags is too slow for HD so we downsample the image to a more reasonable size 68 | processingWidth = cameraWidth > 640 ? 640 : cameraWidth; 69 | processingHeight = cameraHeight * processingWidth / cameraWidth; 70 | } 71 | 72 | /** 73 | * Starts the preview 74 | */ 75 | public void onResume() { 76 | startPreview(); 77 | } 78 | 79 | /** 80 | * Stops the preview and detaches the dummy texture 81 | */ 82 | public void onPause() { 83 | detachDummyTexture(); 84 | stopPreview(); 85 | } 86 | 87 | /** 88 | * Releases the camera 89 | */ 90 | public void onStop() { 91 | camera.release(); 92 | camera = null; 93 | } 94 | 95 | /** 96 | * Gets the camera image. 97 | * 98 | * @return The latest camera image 99 | */ 100 | public byte[] getPictureData() { 101 | return image; 102 | } 103 | 104 | @Override 105 | public void onPreviewFrame(byte[] data, Camera camera) { 106 | 107 | //Dummy surface texture update 108 | if(surf != null) 109 | surf.updateTexImage(); 110 | 111 | //Send the buffer reference to the next preview so that a new buffer is not allocated and we use the same space 112 | camera.addCallbackBuffer(image); 113 | } 114 | 115 | /** 116 | * Starts the preview; requires an OpenGL context for dummy texture creation 117 | */ 118 | public void startPreview(){ 119 | camera.startPreview(); 120 | 121 | //Set the first buffer, the preview doesn't start unless we set the buffers 122 | camera.addCallbackBuffer(image); 123 | } 124 | 125 | /** 126 | * Stops the preview and frees the camera 127 | */ 128 | public void stopPreview(){ 129 | camera.stopPreview(); 130 | camera.setPreviewCallbackWithBuffer(null); 131 | } 132 | 133 | /** 134 | * Attaches a dummy texture to the camera; the preview won't start otherwise on some devices. 135 | * We need a GL context in order to call this! 136 | */ 137 | public void attachDummyTexture(){ 138 | if(surf == null){ 139 | int[] dummyTex = new int[1]; 140 | GLES20.glGenTextures(1, dummyTex, 0); 141 | surf = new SurfaceTexture(dummyTex[0]); 142 | try { 143 | camera.setPreviewTexture(surf); 144 | } catch (IOException e) {e.printStackTrace();} 145 | } 146 | } 147 | 148 | /** 149 | * Detaches the dummy texture to free GPU memory 150 | */ 151 | public void detachDummyTexture(){ 152 | if(surf != null){ 153 | surf.detachFromGLContext(); 154 | surf = null; 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/Filter.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include "Filter.hpp" 22 | 23 | #include 24 | 25 | namespace chilitags { 26 | 27 | FindOutdated::FindOutdated(int persistence) : 28 | mPersistence(persistence), 29 | mDisappearanceTime() 30 | { 31 | } 32 | 33 | std::vector FindOutdated::operator()(const std::map &tags){ 34 | 35 | std::vector tagsToForget; 36 | 37 | auto tagIt = tags.cbegin(); 38 | auto ageIt = mDisappearanceTime.begin(); 39 | 40 | // for each tags that are detected in the current frame 41 | while (tagIt != tags.end()) { 42 | 43 | // update all the tags that come before the current tag, 44 | // i.e. that haven't bee detected this time 45 | while (ageIt != mDisappearanceTime.end() 46 | && ageIt->first < tagIt->first) { 47 | 48 | if (ageIt->second >= mPersistence) { 49 | // remove the tags that haven't been seen for too long 50 | tagsToForget.push_back(ageIt->first); 51 | ageIt = mDisappearanceTime.erase(ageIt); 52 | } else { 53 | // mark as older the last update of the others 54 | ++(ageIt->second); 55 | ++ageIt; 56 | } 57 | } 58 | 59 | ageIt = mDisappearanceTime.insert(ageIt, std::make_pair(tagIt->first, 0)); 60 | 61 | ++tagIt; 62 | ++ageIt; 63 | } 64 | 65 | // update the remaining tags that have not been detected in this frame either 66 | while (ageIt != mDisappearanceTime.end()) { 67 | 68 | if (ageIt->second >= mPersistence) { 69 | // remove the tags that haven't been seen for too long 70 | tagsToForget.push_back(ageIt->first); 71 | ageIt = mDisappearanceTime.erase(ageIt); 72 | } else { 73 | // mark as older the last update of the others 74 | ++ageIt->second; 75 | ++ageIt; 76 | } 77 | } 78 | 79 | 80 | return tagsToForget; 81 | } 82 | 83 | Filter::Filter(int persistence, float gain): 84 | mFindOutdated(persistence), 85 | mGain(gain), 86 | mFilteredCoordinates() 87 | {} 88 | 89 | const std::map & Filter::operator()( 90 | const std::map &tags) { 91 | 92 | for(const auto &tagToForget : mFindOutdated(tags)) { 93 | //TODO lookup can be avoided if Ids are sorted 94 | mFilteredCoordinates.erase(tagToForget); 95 | } 96 | 97 | const float gainComplement = 1.0f - mGain; 98 | 99 | auto filteredIt = mFilteredCoordinates.begin(); 100 | for (const auto &tag : tags) { 101 | while (filteredIt != mFilteredCoordinates.end() 102 | && filteredIt->first < tag.first) { 103 | ++filteredIt; 104 | } 105 | 106 | if (filteredIt != mFilteredCoordinates.end() 107 | && filteredIt->first == tag.first) { 108 | cv::addWeighted(filteredIt->second, mGain, 109 | tag.second, gainComplement, 110 | 0.0f, filteredIt->second); 111 | } 112 | else { 113 | filteredIt = mFilteredCoordinates.insert(filteredIt, tag); 114 | } 115 | } 116 | 117 | return mFilteredCoordinates; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /platforms/jni/samples/README.md: -------------------------------------------------------------------------------- 1 | Chilitags JNI Samples 2 | ===================== 3 | 4 | Android samples 5 | --------------- 6 | 7 | These are some samples to get you started with Chilitags on Android. In order 8 | to be able to build and run these samples, OpenCV and Chilitags must be built 9 | first and then, their resulting dynamic libraries must be put inside the 10 | `libs/target_architecture_name/` (e.g `libs/armeabi-v7a/`) directory. A 11 | detailed description of how to do this is given in the 12 | [README-ANDROID.md](../README-ANDROID.md) file in the Chilitags project 13 | directory, you should definitely read that guide first. 14 | 15 | In the said guide, the Android project path referred to as 16 | `MY_ANDROID_PROJECT_PATH` is the path to the very sample you choose among 17 | these samples. In other words, assuming that you want to build and run the 18 | `estimate3d` sample, you only need to adapt the following line: 19 | 20 | ``` 21 | cmake .. -DCMAKE_TOOLCHAIN_FILE=$OpenCV_DIR/android.toolchain.cmake \ 22 | -DANDROID_PROJECT_ROOT=/platforms/jni/samples/android-estimate3d/ \ 23 | -DCMAKE_INSTALL_PREFIX=$ANDROID_STANDALONE_TOOLCHAIN/sysroot/usr/ 24 | ``` 25 | 26 | Remember to provide the absolute path to `ANDROID_PROJECT_ROOT` even though it 27 | is inside the Chilitags project directory. Then, adapt the following line: 28 | 29 | ``` 30 | cp libopencv_calib3d.so libopencv_core.so libopencv_features2d.so \ 31 | libopencv_flann.so libopencv_highgui.so libopencv_imgproc.so \ 32 | /platforms/jni/samples/android-estimate3d/libs/armeabi-v7a/ 33 | ``` 34 | 35 | in the guide. The rest should be common for all Android projects. In the end, 36 | you should have a `libs` directory inside your Android project that looks like 37 | the following: 38 | 39 | ``` 40 | ... 41 | ├── libs 42 | │   ├── armeabi-v7a 43 | │   │   ├── libchilitags_jni_bindings.so 44 | │   │   ├── libchilitags.so 45 | │   │   ├── libopencv_calib3d.so 46 | │   │   ├── libopencv_core.so 47 | │   │   ├── libopencv_features2d.so 48 | │   │   ├── libopencv_flann.so 49 | │   │   ├── libopencv_highgui.so 50 | │   │   └── libopencv_imgproc.so 51 | │   ├── chilitags-jni-wrapper.jar 52 | │   └── chilitags-jni-wrapper-sources.jar 53 | ... 54 | ``` 55 | 56 | To build and run any sample, simply import it in Eclipse and run it as an 57 | Android Application as usual (you need the Android SDK for this). 58 | 59 | ### estimate3d 60 | -------------- 61 | 62 | This is the barebone sample that takes the camera image, feeds it into 63 | Chilitags3D.estimate and prints the results on the screen. No camera preview is 64 | implemented. 65 | 66 | ### estimate3d-gui 67 | ------------------ 68 | 69 | This is a bit more advanced sample that takes the camera image, and feeds it 70 | into Chilitags3D.estimate, while drawing the live camera image to the screen 71 | and drawing the frames of reference of all the detected tags on top of the live 72 | image. 73 | 74 | The drawing is done in pure GLES 2.0, therefore it might not be straightforward 75 | for a developer who is not introduced to OpenGL. Here are the key GLES aspects 76 | of this sample: 77 | 78 | - The Android camera image is only guaranteed to be in the YUV format 79 | (YUV-NV21 is the default) and therefore it must be converted to RGB before it 80 | can be rendered. This is done via GLSL shaders in order for it to be fast 81 | enough to be real-time. 82 | 83 | - The lines that are drawn on top are simple vertex lists that are rendered 84 | with a much simpler GLSL shader that allows a 1D stretch of pixels to be 85 | colored in a uniform color. 86 | 87 | Here are the source files: 88 | 89 | - `CameraController.java` - Contains all the code that is specific to the 90 | interacting with the device camera. Also contains a dummy `SurfaceTexture` 91 | object that is attached to the camera preview. This is not fundamentally 92 | necessary but preview does not start without this on some devices. 93 | 94 | - `CameraPreviewGLSurfaceView.java` - The surface that GLES requires to draw 95 | something on. 96 | 97 | - `CameraPreviewRenderer.java` - Contains all the GLES specific code that does 98 | image rendering. Loads the shaders that do YUV-RGB conversion and line 99 | painting, calls Chilitags methods, does 3D transform and draws the lines. 100 | 101 | - `Estimate3DGUIActivity.java` - The main Activity, initializes all objects. 102 | 103 | - `GLESLine.java` - Contains all the code specific to line rendering. 104 | 105 | - `shader.Shader.java` - The base shader object. 106 | 107 | - `shader.LineShader.java` - The shader that paints all pixels between two 108 | pixels a single color. 109 | 110 | - `shader.YUV2RGBShader.java` - The shader that does the YUV-RGB conversion. 111 | Takes Y and UV planes as separate textures and draws the RGB image onto the 112 | target. 113 | 114 | Desktop samples 115 | --------------- 116 | 117 | Coming soon... 118 | -------------------------------------------------------------------------------- /src/Codec.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef _TAGTRANSCODER_H 22 | #define _TAGTRANSCODER_H 23 | 24 | namespace chilitags { 25 | 26 | // This class translates Chilitags bitmatrices to and from identifiers. 27 | // This class is an implementation of: 28 | // FIALA, Mark. ARTag, a fiducial marker system using digital techniques. In : 29 | // Computer Vision and Pattern Recognition, 2005. CVPR 2005. IEEE Computer 30 | // Society Conference on. IEEE, 2005. p. 590-596. 31 | class Codec { 32 | public: 33 | 34 | /** The default values will code and decode chilitags */ 35 | Codec( 36 | int bitsId = 10, 37 | int bitsCrc = 16, 38 | int bitsFec = 10, 39 | const char *xorMask = "1010101010", 40 | const char *crcPoly = "10001000000100001"); 41 | 42 | virtual ~Codec(); 43 | 44 | // The main method of the class, decoding a bit matrix 45 | bool decode(const unsigned char *data, int &id) const; 46 | 47 | // The inverse operation, encoding a tag identifier into a matrix. 48 | bool getTagEncodedId(int tagId, unsigned char *data) const; 49 | 50 | int getMaxTagsNumber() const { 51 | return m_maxTagsNumber; 52 | } 53 | 54 | private: 55 | 56 | void addTagToTrackingList(int id); 57 | 58 | struct tag_info_t { 59 | int id; // id of the tag 60 | int xor_id; // id after applying XOR mask 61 | long crc; // id after computing the crc 62 | unsigned char fec[36]; // id after computing the fec, used to draw the tag 63 | }; 64 | 65 | void encode(tag_info_t *tag); 66 | int computeCRC(tag_info_t *tag); 67 | int computeFEC(tag_info_t *tag); 68 | 69 | bool viterbi(const unsigned char *encoded_id, 70 | const unsigned char *tag_data, tag_info_t **tag) const; 71 | 72 | static void bin2int(const unsigned char *bin, int *out, int size); 73 | static unsigned long binstr2int(const char *bin); 74 | 75 | private: 76 | 77 | int m_bitsId; 78 | int m_bitsCrc; 79 | int m_bitsFec; 80 | unsigned long m_xorMask; 81 | unsigned long m_crcPoly; 82 | int m_maxTagsNumber; 83 | 84 | // table of tracked tags (index is trackingId), unused slots point to NULL 85 | tag_info_t *m_trackedTagsTable; 86 | 87 | int m_bitsBeforePuncturing; 88 | int m_bitsAfterPuncturing; 89 | 90 | // puncturing matrix 91 | unsigned char *m_puncturing; 92 | 93 | // decoding - fec decodes only the 20 first bits: enough to decode potential IDs 94 | // greatly saves time compared to the full Viterbi algorithm 95 | unsigned char *m_dec_fec_id; 96 | 97 | // tables used to save state at each level: avoids recursive calls that would be slower 98 | // there are 10 levels, corresponding to the 10 bits that have to be extracted, 11 here since 99 | // some values are referred to in previous levels 100 | int *m_hamming_dist; // hamming distance at level 101 | int *m_exploration_level; // number of tests done at this level (max 2, then back to previous level) 102 | int *m_fec_state; 103 | unsigned char *m_fec_decoded_id; 104 | 105 | struct fec_state { 106 | int output[2]; 107 | int next_state[2]; 108 | }; 109 | 110 | struct fec_state_dec { 111 | int input[2]; 112 | int output[2]; 113 | int next_state[2]; 114 | }; 115 | 116 | fec_state m_fec_fsm[4]; 117 | fec_state_dec m_fec_dec[4]; 118 | 119 | private: 120 | Codec(const Codec&); 121 | Codec &operator=(const Codec&); 122 | 123 | }; 124 | 125 | 126 | } 127 | 128 | #endif /* _TAGTRANSCODER_H */ 129 | 130 | -------------------------------------------------------------------------------- /platforms/javascript/src/chilitags-javascript.js: -------------------------------------------------------------------------------- 1 | function setFilter(persistence, gain) { 2 | Module.ccall('setFilter', 'void', ['float', 'float'], [persistence, gain]); 3 | } 4 | Module['setFilter'] = setFilter; 5 | 6 | function find (canvas) { 7 | var ctx = canvas.getContext('2d'); 8 | var inputBuf = Module._malloc(canvas.width*canvas.height); 9 | var img = ctx.getImageData(0, 0, canvas.width, canvas.height); 10 | var binary = new Uint8Array(img.data.length/4); 11 | for(var i=0; i 640 ? 640 : preferredSize.width; 65 | int processingHeight = preferredSize.height * processingWidth / preferredSize.width; 66 | 67 | //Create the Chilitags object (which also creates its native counterpart) 68 | //The default Android camera color space is YUV_NV21 69 | if(chilitags == null){ 70 | chilitags = new Chilitags3D(preferredSize.width,preferredSize.height, 71 | processingWidth,processingHeight,Chilitags3D.InputType.YUV_NV21); 72 | 73 | //A simple camera calibration based on a lot of assumptions 74 | double[] cc = { 75 | 270, 0, processingWidth/2, 76 | 0, 270, processingHeight/2, 77 | 0, 0, 1}; 78 | double[] dc = {}; 79 | chilitags.setCalibration(cc,dc); 80 | } 81 | } 82 | } 83 | 84 | @Override 85 | protected void onResume(){ 86 | super.onResume(); 87 | camera.startPreview(); 88 | } 89 | 90 | @Override 91 | protected void onPause(){ 92 | super.onPause(); 93 | detachDummyTexture(); 94 | camera.stopPreview(); 95 | } 96 | 97 | @Override 98 | protected void onStop(){ 99 | super.onStop(); 100 | camera.release(); 101 | camera = null; 102 | } 103 | 104 | @Override 105 | public void onPreviewFrame(byte[] data, Camera camera) { 106 | 107 | //Dummy surface texture update 108 | if(surf != null) 109 | surf.updateTexImage(); 110 | 111 | //Run 3D estimation on the camera image 112 | ObjectTransform[] results = chilitags.estimate(data,Chilitags3D.DetectionTrigger.DETECT_PERIODICALLY); 113 | 114 | //Report transform matrices of found tags 115 | if(results.length > 0){ 116 | String infos = "Found " + results.length + " tag(s):\n\n"; 117 | 118 | for(int i=0;i. * 19 | *******************************************************************************/ 20 | 21 | #ifdef OPENCV3 22 | #include 23 | #else 24 | #include 25 | #endif 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | namespace { 33 | const chilitags::TagCornerMap EMPTY_TAG_LIST; 34 | const chilitags::TagCornerMap ONLY_TAG_42 = {{42, {}}}; 35 | const chilitags::TagCornerMap ONLY_TAG_43 = {{43, {}}}; 36 | } 37 | 38 | TEST(FindOutdated, ZeroPersistence) { 39 | chilitags::FindOutdated findOutdated(0); 40 | 41 | EXPECT_EQ(0, findOutdated(EMPTY_TAG_LIST).size()); 42 | EXPECT_EQ(0, findOutdated(ONLY_TAG_42).size()); 43 | EXPECT_EQ(1, findOutdated(EMPTY_TAG_LIST).size()); 44 | } 45 | 46 | TEST(FindOutdated, InvalidateOne) { 47 | chilitags::FindOutdated findOutdated(3); 48 | 49 | EXPECT_EQ(0, findOutdated(EMPTY_TAG_LIST).size()); 50 | EXPECT_EQ(0, findOutdated(ONLY_TAG_42).size()); 51 | EXPECT_EQ(0, findOutdated(EMPTY_TAG_LIST).size()); 52 | EXPECT_EQ(0, findOutdated(EMPTY_TAG_LIST).size()); 53 | EXPECT_EQ(0, findOutdated(EMPTY_TAG_LIST).size()); 54 | EXPECT_EQ(1, findOutdated(EMPTY_TAG_LIST).size()); 55 | } 56 | 57 | TEST(FindOutdated, InvalidateFirst) { 58 | chilitags::FindOutdated findOutdated(2); 59 | 60 | EXPECT_EQ(0, findOutdated(EMPTY_TAG_LIST).size()); 61 | EXPECT_EQ(0, findOutdated(ONLY_TAG_42).size()); 62 | EXPECT_EQ(0, findOutdated(EMPTY_TAG_LIST).size()); 63 | EXPECT_EQ(0, findOutdated(EMPTY_TAG_LIST).size()); 64 | EXPECT_EQ(1, findOutdated(ONLY_TAG_43).size()); 65 | } 66 | 67 | TEST(FindOutdated, ChangePersistence) { 68 | chilitags::FindOutdated findOutdated(2); 69 | 70 | EXPECT_EQ(0, findOutdated(EMPTY_TAG_LIST).size()); 71 | EXPECT_EQ(0, findOutdated(ONLY_TAG_42).size()); 72 | findOutdated.setPersistence(1); 73 | EXPECT_EQ(0, findOutdated(EMPTY_TAG_LIST).size()); 74 | EXPECT_EQ(1, findOutdated(EMPTY_TAG_LIST).size()); 75 | } 76 | 77 | TEST(Filter, ZeroGain) { 78 | chilitags::Filter filter(0, 0.0f); 79 | chilitags::Quad coordinates { 80 | 1.0f,2.0f, 81 | 3.0f,4.0f, 82 | 5.0f,6.0f, 83 | 7.0f,8.0f, 84 | }; 85 | chilitags::Quad expected; 86 | chilitags::TagCornerMap tags; 87 | chilitags::TagCornerMap results; 88 | 89 | tags = {{0, coordinates}}; 90 | results = filter(tags); 91 | expected = coordinates; 92 | EXPECT_EQ(results.size(), tags.size()); 93 | EXPECT_EQ(0.0f, cv::norm(cv::Mat(expected) - cv::Mat(results[0]))); 94 | 95 | coordinates = cv::Mat(cv::Mat(coordinates) + 9.0f); 96 | tags = {{0, coordinates}}; 97 | results = filter(tags); 98 | expected = coordinates; 99 | EXPECT_EQ(results.size(), tags.size()); 100 | EXPECT_EQ(0.0f, cv::norm(cv::Mat(expected) - cv::Mat(results[0]))); 101 | } 102 | 103 | TEST(Filter, NonZeroGain) { 104 | chilitags::Filter filter(0, 0.1f); 105 | chilitags::Quad coordinates { 106 | 1.0f,2.0f, 107 | 3.0f,4.0f, 108 | 5.0f,6.0f, 109 | 7.0f,8.0f, 110 | }; 111 | chilitags::Quad expected; 112 | chilitags::TagCornerMap tags; 113 | chilitags::TagCornerMap results; 114 | 115 | tags = {{0, coordinates}}; 116 | results = filter(tags); 117 | expected = coordinates; 118 | EXPECT_EQ(results.size(), tags.size()); 119 | EXPECT_EQ(0.0f, cv::norm(cv::Mat(expected) - cv::Mat(results[0]))); 120 | 121 | chilitags::Quad coordinates2 = cv::Mat(cv::Mat(coordinates) + 9.0f); 122 | tags = {{0, coordinates2}}; 123 | results = filter(tags); 124 | expected = cv::Mat(0.1f*cv::Mat(coordinates)+0.9f*cv::Mat(coordinates2)); 125 | EXPECT_EQ(results.size(), tags.size()); 126 | EXPECT_EQ(0.0f, cv::norm(cv::Mat(expected) - cv::Mat(results[0]))); 127 | } 128 | 129 | CV_TEST_MAIN(".") 130 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright 2013-2014 EPFL # 3 | # Copyright 2013-2014 Quentin Bonnard # 4 | # # 5 | # This file is part of chilitags. # 6 | # # 7 | # Chilitags is free software: you can redistribute it and/or modify # 8 | # it under the terms of the Lesser GNU General Public License as # 9 | # published by the Free Software Foundation, either version 3 of the # 10 | # License, or (at your option) any later version. # 11 | # # 12 | # Chilitags is distributed in the hope that it will be useful, # 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 15 | # GNU Lesser General Public License for more details. # 16 | # # 17 | # You should have received a copy of the GNU Lesser General Public License # 18 | # along with Chilitags. If not, see . # 19 | ################################################################################ 20 | 21 | cmake_minimum_required(VERSION 2.8) 22 | 23 | project(chilitags) 24 | 25 | set(CPACK_PACKAGE_VERSION_MAJOR "2") 26 | set(CPACK_PACKAGE_VERSION_MINOR "0") 27 | set(CPACK_PACKAGE_VERSION_PATCH "0") 28 | 29 | add_definitions(-std=c++11) 30 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") 31 | find_package(OpenCV REQUIRED ) 32 | include_directories(${OpenCV_INCLUDE_DIRS}) 33 | message(STATUS "OpenCV version: ${OpenCV_VERSION}") 34 | 35 | ########################################## 36 | ## Options ### 37 | ########################################## 38 | 39 | option(WITH_SAMPLES "Build demos" OFF) 40 | option(WITH_TESTS "Build tests" OFF) 41 | option(WITH_JNI_BINDINGS "Build JNI bindings compatible with ordinary Java and Android" OFF) 42 | option(ANDROID_INSTALL_LIBRARIES "Install the chilitag libraries inside project at ANDROID_PROJECT_ROOT" OFF) 43 | 44 | if(DEFINED ANDROID) #OPENCV has a nice macro for this: OCV_OPTION, consider using it. 45 | option(WITH_PTHREADS "Multithreading support with pthreads" ON) 46 | option(WITH_TOOLS "provides the marker generation tool" OFF) 47 | 48 | #Set Android install path 49 | set(ANDROID_PROJECT_ROOT "/path/to/android/project" CACHE STRING "The path to the root of the target Android project") 50 | 51 | #Environment variables required by OpenCV for Android 52 | if(NOT DEFINED ENV{ANDROID_STANDALONE_TOOLCHAIN}) 53 | message(FATAL_ERROR "Please set the ANDROID_STANDALONE_TOOLCHAIN environment variable to your standalone toolchain root first, e.g /opt/android-toolchain") 54 | endif() 55 | if(NOT DEFINED ENV{ANDROID_NATIVE_API_LEVEL}) 56 | message(FATAL_ERROR "Please set the ANDROID_NATIVE_API_LEVEL environment variable first, e.g 14") 57 | endif() 58 | if(NOT DEFINED ENV{ANDROID_ABI}) 59 | message(FATAL_ERROR "Please define the ANDROID_ABI environment variable first, e.g armeabi-v7a") 60 | endif() 61 | if(NOT DEFINED ENV{ANDROID_TOOLCHAIN_NAME}) 62 | message(FATAL_ERROR "Please define the ANDROID_TOOLCHAIN_NAME environment variable first, e.g arm-linux-androideabi-4.8") 63 | endif() 64 | elseif(UNIX) 65 | option(WITH_PTHREADS "Multithreading support with pthreads" ON) 66 | option(WITH_TOOLS "provides the marker generation tool" ON) 67 | else() 68 | option(WITH_PTHREADS "Multithreading support with pthreads" OFF) 69 | option(WITH_TOOLS "provides the marker generation tool" ON) 70 | endif() 71 | 72 | ########################################## 73 | ## Chilitags lib ### 74 | ########################################## 75 | 76 | if(WITH_PTHREADS) 77 | add_definitions(-DHAS_MULTITHREADING) 78 | endif() 79 | 80 | if(${OpenCV_VERSION} VERSION_GREATER 2.9.0) 81 | add_definitions(-DOPENCV3) 82 | endif() 83 | 84 | include_directories(include) 85 | add_subdirectory(src) 86 | 87 | ########################################## 88 | ## Modules ### 89 | ########################################## 90 | 91 | include("${CMAKE_SOURCE_DIR}/cmake/TargetDoc.cmake" OPTIONAL) 92 | 93 | if (WITH_TOOLS) 94 | add_subdirectory(tools) 95 | endif() 96 | 97 | if (WITH_SAMPLES) 98 | add_subdirectory(samples) 99 | endif() 100 | 101 | if(WITH_TESTS) 102 | add_subdirectory(test) 103 | endif() 104 | 105 | if(WITH_JNI_BINDINGS) 106 | add_subdirectory(platforms/jni/src) 107 | endif() 108 | 109 | if(ANDROID_INSTALL_LIBRARIES) 110 | if(NOT ANDROID_PROJECT_ROOT) 111 | message(FATAL_ERROR "ANDROID_PROJECT_ROOT undefined, can't install libraries inside Android project.") 112 | endif() 113 | endif() 114 | 115 | -------------------------------------------------------------------------------- /test/float-precision.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifdef OPENCV3 22 | #include 23 | #else 24 | #include 25 | #endif 26 | 27 | #include 28 | 29 | #include "test-metadata.hpp" 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | TEST(FloatPrecision, Snapshots) { 37 | 38 | // Initialise the data path with en empty modulename, 39 | // to get the data from the root of the test data path 40 | cvtest::TS::ptr()->init(""); 41 | 42 | chilitags::Chilitags3Df chilitagsf; 43 | chilitagsf.getChilitags().setPerformance(chilitags::Chilitags::ROBUST); 44 | chilitagsf.enableFilter(false); 45 | 46 | chilitags::Chilitags3Dd chilitagsd; 47 | chilitagsd.getChilitags().setPerformance(chilitags::Chilitags::ROBUST); 48 | chilitagsd.enableFilter(false); 49 | 50 | for (auto testCase : TestMetadata::all) { 51 | std::string path = std::string(cvtest::TS::ptr()->get_data_path())+testCase.filename; 52 | cv::Mat image = cv::imread(path); 53 | 54 | if(image.data) { 55 | 56 | auto tagsd = chilitagsd.estimate(image, chilitags::Chilitags::DETECT_ONLY); 57 | auto tagsf = chilitagsf.estimate(image, chilitags::Chilitags::DETECT_ONLY); 58 | 59 | ASSERT_EQ(tagsf.size(), tagsd.size()) << 60 | "Single precision found " << tagsf.size() << 61 | " tags while double precision found " << tagsd.size() << " tags in " << testCase.filename; 62 | 63 | double diff; 64 | for(const auto& tag : tagsf){ 65 | const auto& matf = tag.second; 66 | const auto& matd = tagsd[tag.first]; 67 | 68 | //Test rotation component 69 | double failThreshold = 1e-5; //TODO: What does this threshold actually mean? 70 | for(int i=0;i<3;i++) 71 | for(int j=0;j<3;j++){ 72 | diff = (double)matf(i,j) - matd(i,j); 73 | if(!std::isnan(diff)) 74 | ASSERT_LT(diff, failThreshold) << 75 | tag.first << "'s single and double precision transforms differ more than " << failThreshold << "%% in (" 76 | << i << "," << j << ");" << std::endl << " Single precision transform: " << matf << std::endl 77 | << "Double precision transform:" << matd; 78 | } 79 | 80 | //Test translation component 81 | failThreshold = 1e-1; //Tenth of a millimeter 82 | for(int i=0;i<3;i++){ 83 | diff = (double)matf(i,3) - matd(i,3); 84 | if(!std::isnan(diff)) 85 | ASSERT_LT(diff, failThreshold) << 86 | tag.first << "'s single and double precision transforms differ more than " << failThreshold << "%% in (" 87 | << i << "," << "3);" << std::endl << " Single precision transform: " << matf << std::endl 88 | << "Double precision transform:" << matd; 89 | } 90 | 91 | //Test last row 92 | ASSERT_EQ(matf(3,0), 0.0f); ASSERT_EQ(matf(3,1), 0.0f); ASSERT_EQ(matf(3,2), 0.0f); ASSERT_EQ(matf(3,3), 1.0f); 93 | ASSERT_EQ(matd(3,0), 0.0); ASSERT_EQ(matd(3,1), 0.0); ASSERT_EQ(matd(3,2), 0.0); ASSERT_EQ(matd(3,3), 1.0); 94 | } 95 | } 96 | else { 97 | ADD_FAILURE() 98 | << "Unable to read: " << path << "\n" 99 | << "Did you correctly set the OPENCV_TEST_DATA_PATH environment variable?\n" 100 | << "CMake takes care of this if you set its TEST_DATA variable.\n" 101 | << "You can download the test data from\n" 102 | << "https://github.com/chili-epfl/chilitags-testdata"; 103 | } 104 | } 105 | } 106 | 107 | CV_TEST_MAIN(".") 108 | -------------------------------------------------------------------------------- /src/EstimatePose3D.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | /** 22 | * @file EstimatePose3D.cpp 23 | * @brief 6D pose calculator from image coordinates and camera parameters 24 | * @author Quentin Bonnard 25 | * @author Ayberk Özgür 26 | */ 27 | 28 | #include "EstimatePose3D.hpp" 29 | 30 | #include 31 | 32 | namespace chilitags{ 33 | 34 | template 35 | EstimatePose3D::EstimatePose3D(cv::Size cameraResolution) : 36 | mFilter3D(), 37 | mFilter3DEnabled(true), 38 | mCameraMatrix(), 39 | mDistCoeffs() 40 | { 41 | float focalLength = 700.0f; 42 | mCameraMatrix = (cv::Mat_(3,3) << 43 | focalLength, 0, cameraResolution.width/2, 44 | 0, focalLength, cameraResolution.height/2, 45 | 0, 0, 1 46 | ); 47 | } 48 | 49 | template 50 | void EstimatePose3D::setCameraCalibration(cv::Mat newCameraMatrix, cv::Mat newDistCoeffs) 51 | { 52 | mCameraMatrix = newCameraMatrix; 53 | mDistCoeffs = newDistCoeffs; 54 | } 55 | 56 | template 57 | cv::Mat const& EstimatePose3D::getCameraMatrix() const 58 | { 59 | return mCameraMatrix; 60 | } 61 | 62 | template 63 | cv::Mat const& EstimatePose3D::getDistortionCoeffs() const 64 | { 65 | return mDistCoeffs; 66 | } 67 | 68 | template 69 | void EstimatePose3D::enableFilter(bool enabled) 70 | { 71 | mFilter3DEnabled = enabled; 72 | } 73 | 74 | template 75 | void EstimatePose3D::setFilterPersistence(RealT persistence) 76 | { 77 | mFilter3D.setPersistence(persistence); 78 | } 79 | 80 | template 81 | void EstimatePose3D::setFilterProcessNoiseCovariance(cv::Mat const& covariance) 82 | { 83 | mFilter3D.setProcessNoiseCovariance(covariance); 84 | } 85 | 86 | template 87 | void EstimatePose3D::setFilterObservationNoiseCovariance(cv::Mat const& covariance) 88 | { 89 | mFilter3D.setObservationNoiseCovariance(covariance); 90 | } 91 | 92 | template 93 | void EstimatePose3D::setCamDelta(cv::Vec const& camDeltaR, cv::Vec const& camDeltaX) 94 | { 95 | if(mFilter3DEnabled) 96 | mFilter3D.setCamDelta(camDeltaR, camDeltaX); 97 | } 98 | 99 | template 100 | void EstimatePose3D::operator()(typename Chilitags3D_::TagPoseMap& objects) 101 | { 102 | if(mFilter3DEnabled) 103 | mFilter3D(objects); 104 | } 105 | 106 | template 107 | void EstimatePose3D::operator()(std::string const& name, 108 | std::vector> const& objectPoints, 109 | cv::Mat_ const& imagePoints, 110 | typename Chilitags3D_::TagPoseMap& objects) 111 | { 112 | 113 | // Find the 3D pose of our tag 114 | cv::solvePnP(objectPoints, imagePoints, 115 | mCameraMatrix, mDistCoeffs, 116 | mTempRotation, mTempTranslation, false, 117 | #ifdef OPENCV3 118 | cv::SOLVEPNP_ITERATIVE); 119 | #else 120 | cv::ITERATIVE); 121 | #endif 122 | //TODO: Rotation and translation vectors come out of solvePnP as double 123 | 124 | if(mFilter3DEnabled) 125 | mFilter3D(name, mTempTranslation, mTempRotation); 126 | 127 | cv::Rodrigues(mTempRotation, mTempRotMat); 128 | 129 | objects[name] = { 130 | (RealT)mTempRotMat(0,0), (RealT)mTempRotMat(0,1), (RealT)mTempRotMat(0,2), (RealT)mTempTranslation.at(0), 131 | (RealT)mTempRotMat(1,0), (RealT)mTempRotMat(1,1), (RealT)mTempRotMat(1,2), (RealT)mTempTranslation.at(1), 132 | (RealT)mTempRotMat(2,0), (RealT)mTempRotMat(2,1), (RealT)mTempRotMat(2,2), (RealT)mTempTranslation.at(2), 133 | 0, 0, 0, 1 134 | }; 135 | } 136 | 137 | //All possible instantiations of EstimatePose3D 138 | template class EstimatePose3D; 139 | template class EstimatePose3D; 140 | 141 | } /* namespace chilitags */ 142 | -------------------------------------------------------------------------------- /src/Detect.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include "Detect.hpp" 22 | 23 | #include 24 | 25 | namespace chilitags{ 26 | 27 | #ifdef OPENCV3 28 | #include 29 | #endif 30 | 31 | Detect::Detect() : 32 | mRefineCorners(true), 33 | mFindQuads(), 34 | mRefine(), 35 | mReadBits(), 36 | mDecode(), 37 | mFrame(), 38 | mTags() 39 | #ifdef HAS_MULTITHREADING 40 | ,mBackgroundThread(), 41 | mBackgroundRunning(false), 42 | mNeedFrame(true), 43 | mInputCond(PTHREAD_COND_INITIALIZER), 44 | mInputLock(PTHREAD_MUTEX_INITIALIZER) 45 | #endif 46 | { 47 | } 48 | 49 | void Detect::setMinInputWidth(int minWidth) 50 | { 51 | mFindQuads.setMinInputWidth(minWidth); 52 | } 53 | 54 | void Detect::setCornerRefinement(bool refineCorners) 55 | { 56 | mRefineCorners = refineCorners; 57 | } 58 | 59 | void Detect::doDetection(TagCornerMap& tags) 60 | { 61 | if(mRefineCorners){ 62 | for(const auto& quad : mFindQuads(mFrame)){ 63 | auto refinedQuad = mRefine(mFrame, quad, 1.5f/10.0f); 64 | auto tag = mDecode(mReadBits(mFrame, refinedQuad), refinedQuad); 65 | if(tag.first != Decode::INVALID_TAG) 66 | tags[tag.first] = tag.second; 67 | else{ 68 | tag = mDecode(mReadBits(mFrame, quad), quad); 69 | if(tag.first != Decode::INVALID_TAG) 70 | tags[tag.first] = tag.second; 71 | } 72 | } 73 | } 74 | else{ 75 | for(const auto& quad : mFindQuads(mFrame)){ 76 | auto tag = mDecode(mReadBits(mFrame, quad), quad); 77 | if(tag.first != Decode::INVALID_TAG) 78 | tags[tag.first] = tag.second; 79 | } 80 | } 81 | } 82 | 83 | void Detect::operator()(cv::Mat const& greyscaleImage, TagCornerMap& tags) 84 | { 85 | #ifdef HAS_MULTITHREADING 86 | //Run single threaded 87 | if(!mBackgroundRunning){ 88 | mFrame = greyscaleImage; 89 | doDetection(tags); 90 | } 91 | 92 | //Detection thread running in the background, just deliver the frame and tags 93 | else{ 94 | if(mNeedFrame){ 95 | pthread_mutex_lock(&mInputLock); 96 | 97 | greyscaleImage.copyTo(mFrame); 98 | mTags.clear(); 99 | 100 | //Wake up detection thread if it's waiting for the input frame 101 | pthread_cond_signal(&mInputCond); 102 | pthread_mutex_unlock(&mInputLock); 103 | } 104 | } 105 | #else 106 | mFrame = greyscaleImage; 107 | doDetection(tags); 108 | #endif 109 | } 110 | 111 | #ifdef HAS_MULTITHREADING 112 | void Detect::launchBackgroundThread(Track& track) 113 | { 114 | if(!mBackgroundRunning){ 115 | mTrack = &track; 116 | mBackgroundShouldRun = true; 117 | mBackgroundRunning = true; 118 | if(pthread_create(&mBackgroundThread, NULL, dispatchRun, (void*)this)){ 119 | mBackgroundShouldRun = false; 120 | mBackgroundRunning = false; 121 | std::cerr << "Error: Thread could not be launched in " << __PRETTY_FUNCTION__ 122 | << ", not enough resources or PTHREAD_THREADS_MAX was hit!" << std::endl; 123 | } 124 | } 125 | } 126 | 127 | void Detect::shutdownBackgroundThread() 128 | { 129 | if(mBackgroundRunning){ 130 | pthread_mutex_lock(&mInputLock); 131 | mBackgroundShouldRun = false; 132 | pthread_cond_signal(&mInputCond); 133 | pthread_mutex_unlock(&mInputLock); 134 | } 135 | } 136 | 137 | void* Detect::dispatchRun(void* args) 138 | { 139 | static_cast(args)->run(); 140 | return NULL; 141 | } 142 | 143 | void Detect::run() 144 | { 145 | while(mBackgroundShouldRun){ 146 | pthread_mutex_lock(&mInputLock); 147 | 148 | //Wait for the input frame to arrive 149 | pthread_cond_wait(&mInputCond, &mInputLock); //This releases the lock while waiting 150 | 151 | mNeedFrame = false; 152 | 153 | doDetection(mTags); 154 | mTrack->update(mTags); 155 | 156 | mNeedFrame = true; 157 | 158 | pthread_mutex_unlock(&mInputLock); 159 | } 160 | mBackgroundRunning = false; 161 | } 162 | #endif 163 | 164 | } /* namespace chilitags */ 165 | 166 | -------------------------------------------------------------------------------- /samples/multithreaded/async-detection.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include 22 | 23 | #ifdef OPENCV3 24 | #include // getTickCount... 25 | #include 26 | #endif 27 | 28 | #include // CV_AA 29 | 30 | #include 31 | 32 | #include 33 | 34 | cv::Scalar COLOR = cv::Scalar(0, 0, 255); 35 | 36 | void drawTags(cv::Mat outputImage, std::map const& tags); 37 | 38 | int main(int argc, char* argv[]) 39 | { 40 | // Initialising input video 41 | int xRes = 640; 42 | int yRes = 480; 43 | int cameraIndex = 0; 44 | if (argc > 2) { 45 | xRes = std::atoi(argv[1]); 46 | yRes = std::atoi(argv[2]); 47 | } 48 | if (argc > 3) { 49 | cameraIndex = std::atoi(argv[3]); 50 | } 51 | 52 | // The source of input images 53 | cv::VideoCapture capture(cameraIndex); 54 | if (!capture.isOpened()) 55 | { 56 | std::cerr << "Unable to initialise video capture." << std::endl; 57 | return 1; 58 | } 59 | #ifdef OPENCV3 60 | capture.set(cv::CAP_PROP_FRAME_WIDTH, xRes); 61 | capture.set(cv::CAP_PROP_FRAME_HEIGHT, yRes); 62 | #else 63 | capture.set(CV_CAP_PROP_FRAME_WIDTH, xRes); 64 | capture.set(CV_CAP_PROP_FRAME_HEIGHT, yRes); 65 | #endif 66 | cv::Mat inputImage; 67 | 68 | chilitags::Chilitags chilitags; 69 | chilitags.setFilter(0, 0.); 70 | 71 | cv::namedWindow("DisplayChilitags"); 72 | 73 | char keyPressed; 74 | const char* trigName = "DETECT_PERIODICALLY"; 75 | chilitags::Chilitags::DetectionTrigger trig = chilitags::Chilitags::DETECT_PERIODICALLY; 76 | while ('q' != (keyPressed = (char) cv::waitKey(1))) { 77 | 78 | // toggle the processing mode, according to user input 79 | if(keyPressed == 't'){ 80 | if(trig == chilitags::Chilitags::DETECT_PERIODICALLY){ 81 | trig = chilitags::Chilitags::ASYNC_DETECT_PERIODICALLY; 82 | trigName = "ASYNC_DETECT_PERIODICALLY"; 83 | } 84 | else if(trig == chilitags::Chilitags::ASYNC_DETECT_PERIODICALLY){ 85 | trig = chilitags::Chilitags::ASYNC_DETECT_ALWAYS; 86 | trigName = "ASYNC_DETECT_ALWAYS"; 87 | } 88 | else{ 89 | trig = chilitags::Chilitags::DETECT_PERIODICALLY; 90 | trigName = "DETECT_PERIODICALLY"; 91 | } 92 | } 93 | 94 | capture.read(inputImage); 95 | 96 | cv::Mat outputImage = inputImage.clone(); 97 | 98 | auto tags = chilitags.find(inputImage, trig); 99 | drawTags(outputImage, tags); 100 | 101 | //Print detection trigger 102 | cv::putText(outputImage, 103 | cv::format("Detection trigger: %s (press 't' to toggle)", trigName), 104 | cv::Point(8,yRes - 24), 105 | cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); 106 | 107 | cv::putText(outputImage, 108 | cv::format("Run 'top -H -p `pgrep async-detection`' to see running threads", trigName), 109 | cv::Point(8,yRes - 8), 110 | cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); 111 | 112 | cv::imshow("DisplayChilitags", outputImage); 113 | } 114 | 115 | cv::destroyWindow("DisplayChilitags"); 116 | capture.release(); 117 | 118 | return 0; 119 | } 120 | 121 | void drawTags( 122 | cv::Mat outputImage, 123 | const std::map &tags) 124 | { 125 | for(const auto& tag : tags){ 126 | 127 | const cv::Mat_ corners(tag.second); 128 | 129 | for(size_t i = 0; i < 4; ++i){ 130 | const int SHIFT = 16; 131 | const float PRECISION = 1 << SHIFT; 132 | cv::line( 133 | outputImage, 134 | PRECISION*corners(i), 135 | PRECISION*corners((i+1)%4), 136 | #ifdef OPENCV3 137 | COLOR, 3, cv::LINE_AA, SHIFT); 138 | #else 139 | COLOR, 3, CV_AA, SHIFT); 140 | #endif 141 | } 142 | 143 | cv::Point2f center = 0.5*(corners(0) + corners(2)); 144 | cv::putText(outputImage, cv::format("%d", tag.first), center, 145 | cv::FONT_HERSHEY_SIMPLEX, 0.5, COLOR); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /platforms/javascript/samples/detection-2d/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 |
Persistency: 30 |
Gain (%): 40 |
Processing time (ms):
Draw Borders: 50 |
53 |

Detected tags (px)

54 |
55 | 56 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /test/drawer.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifdef OPENCV3 22 | #include 23 | #else 24 | #include 25 | #endif 26 | 27 | #include 28 | 29 | #include "HardcodedIds.hpp" 30 | 31 | namespace { 32 | cv::Vec3b WHITE(255,255,255); 33 | cv::Vec3b BLACK(0,0,0); 34 | } 35 | 36 | TEST(Drawer, Defaults) { 37 | chilitags::Chilitags chilitags; 38 | cv::Mat image = chilitags.draw(0); 39 | ASSERT_EQ(CV_8UC3, image.type()); 40 | ASSERT_EQ(10,image.cols); 41 | ASSERT_EQ(10,image.rows); 42 | } 43 | 44 | TEST(Drawer, DrawCode) { 45 | HardcodedIds hardcodedIds; 46 | chilitags::Chilitags chilitags; 47 | 48 | for (int t = 0; t<1024; ++t) { 49 | cv::Mat image = chilitags.draw(t); 50 | ASSERT_EQ(CV_8UC3, image.type()); 51 | ASSERT_EQ(10,image.cols); 52 | ASSERT_EQ(10,image.rows); 53 | 54 | int contentStart = 2; 55 | for (int y = 0; y= image.cols-contentStart 59 | || y < contentStart || y >= image.rows-contentStart) { 60 | ASSERT_EQ(BLACK, image.at(y,x)); 61 | } 62 | } 63 | } 64 | 65 | for (int i = 0; i<6; ++i) { 66 | for (int j = 0; j<6; ++j) { 67 | ASSERT_EQ( 68 | hardcodedIds.id[t][6*i+j]?WHITE:BLACK, 69 | image.at(2+i,2+j)); 70 | } 71 | } 72 | } 73 | } 74 | 75 | TEST(Drawer, WithMargin) { 76 | HardcodedIds hardcodedIds; 77 | chilitags::Chilitags chilitags; 78 | 79 | for (int t = 0; t<1024; ++t) { 80 | cv::Mat image = chilitags.draw(t,1,true); 81 | ASSERT_EQ(CV_8UC3, image.type()); 82 | ASSERT_EQ(14,image.cols); 83 | ASSERT_EQ(14,image.rows); 84 | 85 | for (int i = 0; i<6; ++i) { 86 | for (int j = 0; j<6; ++j) { 87 | ASSERT_EQ( 88 | hardcodedIds.id[t][6*i+j]?WHITE:BLACK, 89 | image.at(4+i,4+j)); 90 | } 91 | } 92 | } 93 | } 94 | 95 | TEST(Drawer, Zoom) { 96 | HardcodedIds hardcodedIds; 97 | chilitags::Chilitags chilitags; 98 | 99 | int zoom = 10; 100 | for (int t = 0; t<1024; ++t) { 101 | cv::Mat image = chilitags.draw(t, zoom); 102 | ASSERT_EQ(CV_8UC3, image.type()); 103 | ASSERT_EQ(100,image.cols); 104 | ASSERT_EQ(100,image.rows); 105 | 106 | int contentStart = zoom*2; 107 | for (int y = 0; y= image.cols-contentStart 111 | || y < contentStart || y >= image.rows-contentStart) { 112 | ASSERT_EQ(BLACK, image.at(y,x)); 113 | } 114 | } 115 | } 116 | 117 | for (int i = 0; i<6; ++i) { 118 | for (int j = 0; j<6; ++j) { 119 | for (int y = zoom*(2+i); y(y,x)); 124 | } 125 | } 126 | } 127 | } 128 | } 129 | } 130 | 131 | TEST(Drawer, ZoomWithMargin) { 132 | HardcodedIds hardcodedIds; 133 | chilitags::Chilitags chilitags; 134 | 135 | int zoom = 10; 136 | for (int t = 0; t<1024; ++t) { 137 | cv::Mat image = chilitags.draw(t, zoom, true); 138 | ASSERT_EQ(CV_8UC3, image.type()); 139 | ASSERT_EQ(140,image.cols); 140 | ASSERT_EQ(140,image.rows); 141 | for (int i = 0; i<6; ++i) { 142 | for (int j = 0; j<6; ++j) { 143 | for (int y = zoom*(4+i); y(y,x)); 148 | } 149 | } 150 | } 151 | } 152 | } 153 | } 154 | 155 | CV_TEST_MAIN(".") 156 | -------------------------------------------------------------------------------- /cmake/TargetDoc.cmake: -------------------------------------------------------------------------------- 1 | # -helper macro to add a "doc" target with CMake build system. 2 | # and configure Doxyfile.in to Doxyfile 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 | SET (MKDIR_DOC ${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_PREFIX}/share/doc/chilitags) 22 | SET (INSTALL_DOC ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/doc/html ${CMAKE_INSTALL_PREFIX}/share/doc/chilitags) 23 | 24 | FIND_PACKAGE(Doxygen) 25 | 26 | IF (DOXYGEN_FOUND) 27 | 28 | # click+jump in Emacs and Visual Studio (for Doxyfile) (jw) 29 | IF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") 30 | SET(DOXY_WARN_FORMAT "\"$file($line) : $text \"") 31 | ELSE (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") 32 | SET(DOXY_WARN_FORMAT "\"$file:$line: $text \"") 33 | ENDIF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") 34 | 35 | # we need latex for doxygen because of the formulas 36 | FIND_PACKAGE(LATEX) 37 | IF (NOT LATEX_COMPILER) 38 | MESSAGE(STATUS "latex command LATEX_COMPILER not found but usually required. You will probably get warnings and user inetraction on doxy run.") 39 | ENDIF (NOT LATEX_COMPILER) 40 | IF (NOT MAKEINDEX_COMPILER) 41 | MESSAGE(STATUS "makeindex command MAKEINDEX_COMPILER not found but usually required.") 42 | ENDIF (NOT MAKEINDEX_COMPILER) 43 | IF (NOT DVIPS_CONVERTER) 44 | MESSAGE(STATUS "dvips command DVIPS_CONVERTER not found but usually required.") 45 | ENDIF (NOT DVIPS_CONVERTER) 46 | 47 | IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in") 48 | MESSAGE(STATUS "configured ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in --> ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile") 49 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in 50 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 51 | @ONLY ) 52 | # use (configured) Doxyfile from (out of place) BUILD tree: 53 | SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile") 54 | ELSE (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in") 55 | # use static hand-edited Doxyfile from SOURCE tree: 56 | SET(DOXY_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile") 57 | IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile") 58 | MESSAGE(STATUS "WARNING: using existing ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile instead of configuring from Doxyfile.in file.") 59 | ELSE (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile") 60 | IF (EXISTS "${CMAKE_MODULE_PATH}/Doxyfile.in") 61 | # using template Doxyfile.in 62 | MESSAGE(STATUS "configured ${CMAKE_CMAKE_MODULE_PATH}/Doxyfile.in --> ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile") 63 | CONFIGURE_FILE(${CMAKE_MODULE_PATH}/Doxyfile.in 64 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 65 | @ONLY ) 66 | SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile") 67 | ELSE (EXISTS "${CMAKE_MODULE_PATH}/Doxyfile.in") 68 | # failed completely... 69 | MESSAGE(SEND_ERROR "Please create ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in (or Doxyfile as fallback)") 70 | ENDIF(EXISTS "${CMAKE_MODULE_PATH}/Doxyfile.in") 71 | 72 | ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile") 73 | ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in") 74 | 75 | ADD_CUSTOM_TARGET(doc ${DOXYGEN_EXECUTABLE} ${DOXY_CONFIG}) 76 | ADD_CUSTOM_TARGET(install-doc ${MKDIR_DOC} COMMAND ${INSTALL_DOC}) 77 | 78 | # create a windows help .chm file using hhc.exe 79 | # HTMLHelp DLL must be in path! 80 | # fallback: use hhw.exe interactively 81 | IF (WIN32) 82 | FIND_PACKAGE(HTMLHelp) 83 | IF (HTML_HELP_COMPILER) 84 | SET (TMP "${CMAKE_CURRENT_BINARY_DIR}\\Doc\\html\\index.hhp") 85 | STRING(REGEX REPLACE "[/]" "\\\\" HHP_FILE ${TMP} ) 86 | # MESSAGE(SEND_ERROR "DBG HHP_FILE=${HHP_FILE}") 87 | ADD_CUSTOM_TARGET(winhelp ${HTML_HELP_COMPILER} ${HHP_FILE}) 88 | ADD_DEPENDENCIES (winhelp doc) 89 | 90 | IF (NOT TARGET_DOC_SKIP_INSTALL) 91 | # install windows help? 92 | # determine useful name for output file 93 | # should be project and version unique to allow installing 94 | # multiple projects into one global directory 95 | IF (EXISTS "${PROJECT_BINARY_DIR}/Doc/html/index.chm") 96 | IF (PROJECT_NAME) 97 | SET(OUT "${PROJECT_NAME}") 98 | ELSE (PROJECT_NAME) 99 | SET(OUT "Documentation") # default 100 | ENDIF(PROJECT_NAME) 101 | IF (${PROJECT_NAME}_VERSION_MAJOR) 102 | SET(OUT "${OUT}-${${PROJECT_NAME}_VERSION_MAJOR}") 103 | IF (${PROJECT_NAME}_VERSION_MINOR) 104 | SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_MINOR}") 105 | IF (${PROJECT_NAME}_VERSION_PATCH) 106 | SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_PATCH}") 107 | ENDIF(${PROJECT_NAME}_VERSION_PATCH) 108 | ENDIF(${PROJECT_NAME}_VERSION_MINOR) 109 | ENDIF(${PROJECT_NAME}_VERSION_MAJOR) 110 | # keep suffix 111 | SET(OUT "${OUT}.chm") 112 | 113 | #MESSAGE("DBG ${PROJECT_BINARY_DIR}/Doc/html/index.chm \n${OUT}") 114 | # create target used by install and package commands 115 | INSTALL(FILES "${PROJECT_BINARY_DIR}/Doc/html/index.chm" 116 | DESTINATION "doc" 117 | RENAME "${OUT}" 118 | ) 119 | ENDIF(EXISTS "${PROJECT_BINARY_DIR}/Doc/html/index.chm") 120 | ENDIF(NOT TARGET_DOC_SKIP_INSTALL) 121 | 122 | ENDIF(HTML_HELP_COMPILER) 123 | # MESSAGE(SEND_ERROR "HTML_HELP_COMPILER=${HTML_HELP_COMPILER}") 124 | ENDIF (WIN32) 125 | ENDIF(DOXYGEN_FOUND) 126 | 127 | -------------------------------------------------------------------------------- /src/EstimatePose3D.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | /** 22 | * @file EstimatePose3D.cpp 23 | * @brief 6D pose calculator from image coordinates and camera parameters 24 | * @author Quentin Bonnard 25 | * @author Ayberk Özgür 26 | */ 27 | 28 | #ifndef ESTIMATEPOSE3D_HPP 29 | #define ESTIMATEPOSE3D_HPP 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | #include "Filter3D.hpp" 38 | 39 | namespace chilitags { 40 | 41 | template 42 | class EstimatePose3D 43 | { 44 | public: 45 | 46 | /** 47 | * @brief Creates a new 6D pose calculator that uses camera image coordinates and camera parameters 48 | * 49 | * @param cameraResolution Height and width of the camera image 50 | */ 51 | EstimatePose3D(cv::Size cameraResolution = cv::Size(640,480)); 52 | 53 | /** 54 | * @brief Updates the camera calibration parameters 55 | * 56 | * See http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html for parameter details 57 | * 58 | * @param newCameraMatrix 3x3 camera matrix 59 | * @param newDistCoeffs 4x1 or 5x1 or 8x1 distortion coefficients, pass empty matrix if unused 60 | */ 61 | void setCameraCalibration(cv::Mat newCameraMatrix, cv::Mat newDistCoeffs); 62 | 63 | /** 64 | * @brief Returns the camera matrix 65 | * 66 | * @return The 3x3 camera matrix 67 | */ 68 | cv::Mat const& getCameraMatrix() const; 69 | 70 | /** 71 | * @brief Returns the distortion coefficients 72 | * 73 | * @return The 4x1 or 5x1 or 8x1 or empty distortion coefficients 74 | */ 75 | cv::Mat const& getDistortionCoeffs() const; 76 | 77 | /** 78 | * @brief Enabled/disables Kalman filtering on tag pose 79 | * 80 | * @param enabled Whether tag pose filtering is enabled/disabled 81 | */ 82 | void enableFilter(bool enabled); 83 | 84 | /** 85 | * @brief Sets the persistence of tags against being discarded when not observed 86 | * 87 | * @param persistence Persistence value, roughly correponds to number of frames 88 | */ 89 | void setFilterPersistence(RealT persistence); 90 | 91 | /** 92 | * @brief Sets the process noise covariance matrix for the Kalman filter 93 | * 94 | * @param covariance 7x7 covariance matrix 95 | */ 96 | void setFilterProcessNoiseCovariance(cv::Mat const& covariance); 97 | 98 | /** 99 | * @brief Sets the observation noise covariance matrix for the Kalman filter 100 | * 101 | * @param covariance 7x7 covariance matrix 102 | */ 103 | void setFilterObservationNoiseCovariance(cv::Mat const& covariance); 104 | 105 | /** 106 | * @brief Informs the rotation and translation of the current camera frame in the previous camera frame 107 | * 108 | * @param camDeltaR Rotation of current camera frame in previous camera frame in unit quaternion format (w,vx,vy,vz) 109 | * @param camDeltaX Translation of current camera frame in previous camera frame 110 | */ 111 | void setCamDelta(cv::Vec const& camDeltaR, cv::Vec const& camDeltaX); 112 | 113 | /** 114 | * @brief Updates the poses of all known tags via statistical filtering 115 | * 116 | * @param objects Map to update in which ID maps to the transform 117 | */ 118 | void operator()(typename Chilitags3D_::TagPoseMap& objects); 119 | 120 | /** 121 | * @brief Updates/inserts the pose of the given object in the given map 122 | * 123 | * @param name Unique ID of the object 124 | * @param objectPoints Reference points on the object 125 | * @param imagePoints Where reference points are found in the image 126 | * @param objects Map to update in which ID maps to the transform 127 | */ 128 | void operator()(std::string const& name, 129 | std::vector> const& objectPoints, 130 | cv::Mat_ const& imagePoints, 131 | typename Chilitags3D_::TagPoseMap& objects); 132 | 133 | protected: 134 | 135 | Filter3D mFilter3D; ///< Kalman filter to increase stability of the tag 136 | bool mFilter3DEnabled; ///< Whether to enable pose filtering 137 | 138 | cv::Mat mCameraMatrix; ///< 3x3 camera matrix 139 | cv::Mat mDistCoeffs; ///< Empty or 4x1 or 5x1 or 8x1 Distortion coefficients of the camera 140 | 141 | cv::Mat mTempRotation; ///< 3x1 axis-angle: (rx,ry,rz) 142 | cv::Mat mTempTranslation; ///< 3x1 translation: (x,y,z) 143 | 144 | //TODO: This is double because of rodrigues, it doesn't accept float at the time of writing 145 | cv::Matx33d mTempRotMat; ///< 3x3 rotation matrix representation of mTempRotation 146 | 147 | }; 148 | 149 | } /* namespace chilitags */ 150 | 151 | #endif /* ESTIMATEPOSE3D_HPP */ 152 | -------------------------------------------------------------------------------- /src/FindQuads.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #include "FindQuads.hpp" 22 | #include 23 | 24 | 25 | //#define DEBUG_FindQuads 26 | #ifdef DEBUG_FindQuads 27 | #include 28 | #include // CV_AA 29 | #endif 30 | 31 | namespace { 32 | const int MATRIX_SIZE = 10; 33 | const int MIN_TAG_SIZE = 1.1f*MATRIX_SIZE; 34 | 35 | #ifdef DEBUG_FindQuads 36 | void drawContour(cv::Mat &image, cv::Mat &contour, cv::Scalar color, cv::Point offset) { 37 | std::vector >contours; 38 | contours.push_back(contour); 39 | cv::drawContours(image, contours, 0, color, 1, CV_AA, cv::noArray(), INT_MAX, offset); 40 | float perimeter = std::abs(cv::arcLength(contour, true)); 41 | cv::putText(image, cv::format("%.1f", perimeter), offset+contours[0][0], 42 | cv::FONT_HERSHEY_SIMPLEX, 1.0f, color); 43 | } 44 | #endif 45 | 46 | } 47 | 48 | namespace chilitags{ 49 | 50 | FindQuads::FindQuads() : 51 | mGrayPyramid(1), 52 | mBinaryPyramid(1), 53 | mMinInputWidth(160) 54 | { 55 | #ifdef DEBUG_FindQuads 56 | cv::namedWindow("FindQuads"); 57 | #endif 58 | } 59 | 60 | std::vector FindQuads::operator()(const cv::Mat &greyscaleImage) 61 | { 62 | //TODO function too long, split it 63 | 64 | std::vector quads; 65 | #ifdef DEBUG_FindQuads 66 | cv::RNG rNG( 0xFFFFFFFF ); 67 | cv::Mat debugImage = cv::Mat::zeros( 68 | cv::Size(2*greyscaleImage.cols, greyscaleImage.rows), 69 | CV_8UC3); 70 | #endif 71 | 72 | mGrayPyramid[0] = greyscaleImage; 73 | 74 | // Subsample the image by a factor two, 75 | // as long as the width is at least mMinInputWidth 76 | unsigned int nPyramidLevel = 1; 77 | if (mMinInputWidth > 0) { 78 | while (mGrayPyramid[nPyramidLevel-1].cols/2 >= mMinInputWidth) { 79 | if (nPyramidLevel >= mGrayPyramid.size()) mGrayPyramid.push_back(cv::Mat()); 80 | cv::resize(mGrayPyramid[nPyramidLevel-1], mGrayPyramid[nPyramidLevel], cv::Size(), 0.5f, 0.5f, cv::INTER_NEAREST); 81 | ++nPyramidLevel; 82 | } 83 | } 84 | 85 | while (mBinaryPyramid.size() < nPyramidLevel) mBinaryPyramid.push_back(cv::Mat()); 86 | for (unsigned int i = 0; i < nPyramidLevel; ++i) { 87 | cv::Canny(mGrayPyramid[i], mBinaryPyramid[i], 100, 200, 3); 88 | } 89 | 90 | for (int i = nPyramidLevel-1; i>=0; --i) //starting with the lowest definition, so the highest definition are last, and can simply override the first ones. 91 | { 92 | int scale = 1 << i; 93 | #ifdef DEBUG_FindQuads 94 | cv::Point offset(debugImage.cols-2*mBinaryPyramid[i].cols,0); 95 | cv::rectangle(debugImage, cv::Rect(offset.x, offset.y, greyscaleImage.cols/scale, greyscaleImage.rows/scale), cv::Scalar::all(255)); 96 | #endif 97 | std::vector > contours; 98 | cv::findContours(mBinaryPyramid[i], contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); 99 | 100 | for (std::vector >::iterator contour = contours.begin(); 101 | contour != contours.end(); 102 | ++contour) 103 | { 104 | float perimeter = std::abs(cv::arcLength(*contour, true)); 105 | float area = std::abs(cv::contourArea(*contour)); 106 | 107 | if (perimeter > 4*MIN_TAG_SIZE && area > MIN_TAG_SIZE*MIN_TAG_SIZE) 108 | { 109 | cv::Mat approxContour; 110 | cv::approxPolyDP( *contour, approxContour, perimeter*0.05f, true); 111 | 112 | cv::Mat normalisedContour; 113 | cv::convexHull(approxContour, normalisedContour, false); 114 | 115 | if (normalisedContour.rows == 4) 116 | { 117 | #ifdef DEBUG_FindQuads 118 | drawContour(debugImage, normalisedContour, cv::Scalar(0,255,0), offset); 119 | #endif 120 | normalisedContour *= scale; 121 | quads.push_back(normalisedContour.reshape(1)); 122 | } 123 | #ifdef DEBUG_FindQuads 124 | else // not quadrilaterals 125 | { 126 | drawContour(debugImage, normalisedContour, cv::Scalar(0,0,255), offset); 127 | } 128 | #endif 129 | } 130 | #ifdef DEBUG_FindQuads 131 | else // too small 132 | { 133 | //drawContour(debugImage, *contour, cv::Scalar(128,128,128), offset); 134 | } 135 | #endif 136 | } 137 | #ifdef DEBUG_FindQuads 138 | cv::putText(debugImage, cv::format("%d, %d", quads.size(), contours.size()), offset+cv::Point(32,32), 139 | cv::FONT_HERSHEY_SIMPLEX, 0.5f, cv::Scalar::all(255)); 140 | #endif 141 | } 142 | #ifdef DEBUG_FindQuads 143 | cv::imshow("FindQuads", debugImage); 144 | cv::waitKey(0); 145 | #endif 146 | 147 | return quads; 148 | } 149 | 150 | } /* namespace chilitags */ 151 | -------------------------------------------------------------------------------- /test/test-metadata.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 EPFL * 3 | * Copyright 2013-2014 Quentin Bonnard * 4 | * * 5 | * This file is part of chilitags. * 6 | * * 7 | * Chilitags is free software: you can redistribute it and/or modify * 8 | * it under the terms of the Lesser GNU General Public License as * 9 | * published by the Free Software Foundation, either version 3 of the * 10 | * License, or (at your option) any later version. * 11 | * * 12 | * Chilitags is distributed in the hope that it will be useful, * 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | * GNU Lesser General Public License for more details. * 16 | * * 17 | * You should have received a copy of the GNU Lesser General Public License * 18 | * along with Chilitags. If not, see . * 19 | *******************************************************************************/ 20 | 21 | #ifndef TestMetadata_HPP 22 | #define TestMetadata_HPP 23 | 24 | namespace TestMetadata { 25 | 26 | struct TestCase { 27 | std::string filename; 28 | std::vector expectedTagIds; 29 | std::vector knownMissedTagIds; 30 | bool isExpected (int id) const { 31 | return contains(expectedTagIds, id); 32 | } 33 | bool isKnownToMiss(int id) const { 34 | return contains(knownMissedTagIds, id); 35 | } 36 | static bool contains(const std::vector &v, int x) { 37 | return std::find(v.begin(), v.end(), x) != v.end(); 38 | } 39 | }; 40 | 41 | // The string is the filename of an image, 42 | // the first list correspond to the ids of tags shown on the image, 43 | // and the second list to the ids of the tags that are undetected. 44 | std::vector< TestCase > all = { 45 | {"stills/4360x2448/smartphone01.jpg", 46 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34}, 47 | {}}, 48 | {"stills/4360x2448/smartphone02.jpg", 49 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34}, 50 | {}}, 51 | {"stills/4360x2448/smartphone04.jpg", 52 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34}, 53 | {}}, 54 | {"stills/4360x2448/smartphone03.jpg", 55 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34}, 56 | {6,27,34}}, 57 | {"stills/1600x1200/thesis01.jpg", 58 | {369,370,371,372,373,374,375,377,378,379,380,381,382,383,384,385,386,394,395,396,397,398,399,400,401,402,405,406,407,408,409}, 59 | {}}, 60 | {"stills/1600x1200/thesis02.jpg", 61 | {588,589,590,591,592,593,594,595,596,597,598,599,1000}, 62 | {}}, 63 | {"stills/1600x1200/thesis03.jpg", 64 | {576,577,588,589,590,591,593,594,595,1023}, 65 | {}}, 66 | {"stills/1600x1200/thesis04.jpg", 67 | {573,574,575,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,1022}, 68 | {}}, 69 | {"stills/640x480/issue22.jpg", 70 | {51}, 71 | {}}, 72 | {"stills/640x480/severin01.jpg", 73 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 74 | {13,}}, 75 | {"stills/640x480/severin02.jpg", 76 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 77 | {}}, 78 | {"stills/640x480/severin03.jpg", 79 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 80 | {}}, 81 | {"stills/640x480/severin04.jpg", 82 | { 3, 8,9,10, 14 }, 83 | {14,}}, 84 | {"stills/640x480/severin05.jpg", 85 | {0,1, 4,5,6,7, 12,13,14, 17,18 }, 86 | {5,13,18,}}, 87 | {"stills/640x480/severin06.jpg", 88 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 89 | {}}, 90 | {"stills/640x480/nasty01.jpg", 91 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 92 | {}}, 93 | {"stills/640x480/nao01.jpg", 94 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 95 | {}}, 96 | {"stills/640x480/nao02.jpg", 97 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 98 | {}}, 99 | {"stills/640x480/nao03.jpg", 100 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 101 | {}}, 102 | {"stills/640x480/nao04.jpg", 103 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 104 | {}}, 105 | {"stills/640x480/nao05.jpg", 106 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 107 | {}}, 108 | {"stills/640x480/nao06.jpg", 109 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 110 | {1,4,6,8,}}, 111 | {"stills/640x480/occlusion01.jpg", 112 | { 1,17 }, 113 | {1,}}, 114 | {"stills/640x480/occlusion02.jpg", 115 | { 1,17 }, 116 | {1,17,}}, 117 | {"stills/320x240/nao01.png", 118 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 119 | {1,2,6,10,11,13,15,16,19,}}, 120 | {"stills/320x240/nao02.png", 121 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 122 | {1,2,4,5,6,7,8,11,13,14,15,16,19,}}, 123 | {"stills/320x240/nao03.png", 124 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 125 | {7,13,19}}, 126 | {"stills/320x240/nao04.png", 127 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 128 | {3,}}, 129 | {"stills/320x240/nao05.png", 130 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, 131 | {0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,}}, 132 | {"stills/320x240/nao06.png", 133 | {46, 50, 51, 55, 59, 62}, 134 | {46,50,59,62,}}, 135 | {"stills/320x240/nao07.png", 136 | {46, 50, 51, 55, 59, 62}, 137 | {46,50,59,62,}}, 138 | {"stills/320x240/nao08.png", 139 | {50, 51, 55, 62}, 140 | {62,}}, 141 | }; 142 | } 143 | 144 | #endif 145 | --------------------------------------------------------------------------------