Giter VIP home page Giter VIP logo

chilitags's Introduction

Chilitags 2: Robust Fiducial Markers for Augmented Reality and Robotics

Chilitags are a C++ cross-platform software library for the detection and identification of 2D fiducial markers (a.k.a. tags). Their purpose is to be printed and placed on objects from the real world, to form the basis of Robotics or Augmented Reality (AR) applications. Using a camera, the position of the tagged objects can be acquired by a computer.

Chilitags were developed internally for projects of the CHILI lab (Computer-Human Interaction in Learning and Instruction, formerly CRAFT), such as Metroscope or TapaCarp. There are already many alternatives (e.g. ARToolKit, or reacTIVision, among many others), but we decided to release Chilitags anyway, as there seemed to be a demand for it.

The following videos show real applications of Chilitags for research in tangible learning or paper-based interfaces.

Overview

Features

Chilitags features two main functionalities:

  • Detecting tags on images, i.e. finding their position on an input image.

  • Estimating the pose in 3D, i.e. finding their position and orientation and in the real world.

Additionnally, Chilitags features various utilities to deal with imperfect detection, such as filters to smooth the position of tags/3Dobjects.

The characteristics of Chilitags come from their original use:

  • Illumination tolerance: Chilitags were developed for use in projector/camera systems, which required the detection to be robust to the illumination constraints of the projector.

  • Precision: Chilitags were used in applications to teach geometry, which required the detection to be as precise as possible to match the requirement on the quality of work of the students.

  • Reliability: Chilitags were used for long experiments in ecologically valid conditions, which required to build systems stable even in various, uncontrolled settings.

Chilitags can be recognized even from low resolution images (tags as narrow as 12 pixels are recognized). However, they are very sensitive to occlusions: if a border is occluded, the tag will not be detected.

The Chilitags demonstration video gives a worst case scenario for the sample code running in real time on a single thread of an Intel Core i7-620m, with a camera set for 960x720x30fps, in an unevenly lit, large scene. The detection has been improved since this video was made.

Content

This release of Chilitags consists of five components:

  • platforms, the source code to expose the Chilitags API in various languages,

  • include and src, the library itself,

  • tools, containing a utility to generate tags,

  • samples and samples-android, sample programs illustrating how to use the library,

  • test, a suite of automated tests.

Getting Started

Chilitags have been developed on Linux (Ubuntu 64 bits), and are known to run on Windows, MacOS X and Android.

Dependencies

Chilitags rely on OpenCV 2.4+ and C++11. They have has been recently tested with OpenCV 2.4 and on Ubuntu (64 bits) 13.04, 13.10 and 14.04. The documentation on how to install OpenCV can be found for various platforms and IDE.

On Ubuntu 12.04, you need to manually install a compiler supporting enough of C++11 (for instance, gcc-4.7) and opencv >= 2.4. The .travis.yml file contains commands to do this, in the before_install section

Set up

CMake can be used to generate configuration files of the most popular IDE's of the main platforms. A CMakeLists file is provided in the release. Please refer to online documentation on how to use CMake.

Example

For example on Ubuntu, the software can be compiled via makefile with the following commands:

  • sudo apt-get install libopencv-dev cmake

to install the OpenCV libraries and cmake

  • mkdir build && cd build

to create the build folder where the compilation output will be placed

  • ccmake ..

to configure the build. Activate the WITH_SAMPLES option.

  • make

to build the library, the tag creation tool and the sample programs

  • sudo make install

to install the library system-wide (see CMake options to install in another prefix).

  • ./samples/detect-live

to start the sample program with default parameters for the camera.

Tag Generation

Once the software is up and running, the tags can be generated using the creator executable in tools. We also generated sets of tags with various settings.

The README file accompanying creator gives important guidelines on how to design and print chilitags. It also explains the usage of creator.

The main design principles for tags are summarized below:

Tag design principles

Documentation

The documentation regarding the usage of chilitags is provided under the form of the sample code detect-live. Please refer to its README file and comments in its source code.

Platforms

Specific instructions for building Chilitags for Android can be found under README-ANDROID.md.

Coding style

This repository uses uncrustify, a tool that does automatic code formatting based on a predefined configuration defined in uncrustify.cfg. In order to keep the code formatting consistent, it is useful to uncrustify before committing. You may consider using a git pre-commit hook to remind you of this.

For example, you can add a pre-commit hook that inhibits you from committing if the source files are not formatted correctly. Simply add a file .git/hooks/pre-commit that contains the following

#!/bin/sh

exec uncrustify -c uncrustify.cfg --check src/* include/*

More complex hooks can be built, such as this one that runs uncrustify before every commit and stores the diff in a patch.

Licence

Chilitags is released under the LGPL3.

In short, it means that you can do more or less what you want with Chilitags, as long as you publish the modifications you make to Chilitags under the same terms (but you don't have to share the sources of the rest of your software).

You should also credit the authors.

We especially appreciate a reference in your paper, should you use Chilitags for a research project. Let us make that easy for you:

  • Chilitags: Robust Fiducial Markers for Augmented Reality. Q. Bonnard, S. Lemaignan, G. Zufferey, A. Mazzei, S. Cuendet, N. Li, P. Dillenbourg. CHILI, EPFL, Switzerland. http://chili.epfl.ch/software. 2013.
	@misc{chilitags,
		title = {Chilitags 2: Robust Fiducial Markers for Augmented Reality and Robotics.},
		author={Bonnard, Quentin and Lemaignan, S\'{e}verin and Zufferey, Guillaume and Mazzei, Andrea and Cuendet, S\'{e}bastien and Li, Nan and \"{O}zg\"{u}r, Ayberk and Dillenbourg, Pierre},
		publisher={CHILI, EPFL, Switzerland},
		url={http://chili.epfl.ch/software},
		year={2013}
	}

Should you require a different licence, please contact CHILI.

chilitags's People

Contributors

crossvr avatar hesmar avatar kshitijkshitij avatar lorenzolightsgdwarf avatar naokiibe avatar severin-lemaignan avatar ste-m5s avatar syrianspock avatar tulip-reprepro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

chilitags's Issues

Use floats instead of double when possible

After playing a bit with the compile flags to get the best possible performances on Android, it appears that floats are much nicer to ARM Neon instructions than double.

It would be useful to replace all doubles by floats (including literals! 1.0 is a double while 1.0f is a float) where possible.

For the record:
Based on https://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/ARM-Options.html#ARM-Options and http://community.arm.com/groups/tools/blog/2013/04/15/arm-cortex-a-processors-and-gcc-command-lines, the best flag combination I come up with is:

-O3 -mcpu=cortex-a15 -mfpu=neon-vfpv4 -mfloat-abi=hard -ffast-math

Also, neon vectorization only works on single-precision floats. It may make sense to check that we use float instead of double (which include: every float literal should be 1.0f instead of 1.0 !)...

-O3

Is there a reason why we are not compiling with -O3 right now?

+Z direction should be outwards from the visible tag surface

Currently, the +Z direction of the tag transform is towards the inside of the visible tag surface since the top left corner is the first corner and is the origin of the tag. For a virtual reality application, this creates a very awkward 3D model building process where the model is on the positive side of the X and Y axes but is on the negative side of the Z axis and is upside down. When exporting models (e.g to FBX), this also creates confusion concerning the positive axis directions. If the first corner is the bottom left one, the +Z axis will naturally point outwards when +X and +Y axes point towards the inside of the tag.

3d estimation with marker configuration returns a wrong transformation

When using 3d pose estimation with a 'compound object' defined by several tags, the compound object has an incorrect pose.

After some bisecting, it appears that the bug was introduced in d9f4b1d. After inspection, I do not see obvious issues, so I open this bug.

Step to reproduce:

Expected result:
The object a4sheet should appear in the center of the 4 others tags.

Actual result:
The object a4sheet is translated (no apparent rotation) out of the sheet.

Remove timing based tests

I don't think timing based tests are a good idea; they are not reliable enough for unit testing. E.g integration fails regularly on my machine, about 50% of the time. This failure is not due to division by zero; it's just due to background load that happens to be there.

marker configuration for a cube ?

hi,
i try to build a marker configuration for a cube. The cube has on 5 sides, only the bottom is free, because there is a clip, chilitags. Every side of the cube is 2x2 cm, so the chilitag is 2x2cm, but the black-square inside is only 13x13mm, to have a white surrounding for detection.

Now i dont get how to define it ? Lets say we got this cube http://goinkscape.com/wp-content/uploads/2014/09/rubiks-13.png and the yellow side is side-nr.1.

On side-nr.1, we got 9 yellow cubes, where only the center-cube is the black-square of the chilitag, and the rest of the yellow-cubes are the white surrounding.

So when the first marker in the configuration file has: translation [0.0, 0.0, 0.0] and rotation [0.0, 0.0, 0.0] what does the second marker has as configuraton ?

If we go clockwise, so the green-side of the cube is side-nr.2, we got translation [0.0, 0.0, -20.0] and rotation [ +90.0, 0.0, 0.0](or a negative rotation ?)

is there anywhere a cube configuration as example, or are there anythings that could help me in designing this config file ?

thanks

Improve tracking

I'll move some comments from the review of #38 (by @severin-lemaignan) here as a reminder of things to experiment with tracking tests:

  • automatically detect when two consecutive frames are different, to enable tracking by default and automatically disable it when needed
  • I'm surprised you call separately calcOpticalFlowPyrLK for each tags. Have you tried running the algorithm on the full image, with a vector containing all corners of all tags? That's how I understood the algorithm was intended to be used, but I may have gotten that wrong (or maybe it kills performances... but I don't think so)
  • should mRefineCorner be respected in Track ?
  • the demo should show better the various detection triggers
  • make sure users know that tracking is available and useful

More comments from @ayberkozgur :

  • tracking is lost as soon as a corner leaves the frame
  • tracking is sometimes too aggressive and make disappeared tags "stick"

Tags amount

Is it possbile to encreae amount of tags in set.
Currently 1023 tags. Would be greate to have 16k...

Is it possbile?

Thank you for your work.

Tag size adjustment and resolution

Hi everyone, I'm new to chilitags. I made some tags of my own, and the size of the my tags is different from the initialized tag size, so when I'm reading from the transformation matrix, the translation vector is a little odd. Could somebody how to fix this? Or where I can reset the tag size (maybe the length of the black and white boxes) in the code?

And I also have some difficulty adjusting my camera's resolution, my Logitech webcam have pretty good resolution, in the estimate3d-gui the resolution is set to 640*480, anyone know where I can change that?

Should be some basic questions, thanks a lot, Chi

Use parallel processing

It would be easy to exploit multi core processors by making Chilitags parallel. There are several parallel processing functionalities built in C++11 that could help with that.

android-estimate3d-gui sample's camera preview won't start on some devices

android-estimate3d-gui sample's camera preview doesn't start on some devices. The culprit is that it requires a SurfaceTexture attached even though it is not needed to start the preview. This is not documented in the official Android docs.

Attaching a dummy SurfaceTexture is still not enough to restart the camera preview after the application is suspended/resumed.

Ignore tags that are more than X distance away from camera

Using the following information:

  • Tag's given size in configuration
  • Camera image resolution
  • Camera calibration values

We can calculate a very reliable X value further than which any tag would be too small to be detected reliably (each bit taking up only a few pixels). Currently, these far away tags cause intermittent noisy detection and this would help us greatly reduce these misdetections.

jni.h not found

Compilation of the java bindings failed because jni.h was not found, even with openjdk-7-jdk installed (tested on Ubuntu 14.04).

Explicitely setting -I/usr/lib/jvm/java-7-openjdk-amd64/include/ solves the problem, but this is not so nice.

Any idea how to instruct CMake to add this include?

Remove upside-down tags

We should add an option to remove upside-down tags, which is probably the ultimate solution to the tag-flipping issue. This can be achieved via:

  1. Discard tags whose z axes make a negative angle with the plane perpendicular to the camera y axis (in other words, the plane defined by the camera z and x axes).
  2. Discard tags whose z axes make a negative angle with the floor plane (or e.g less than -45 degrees). The latest sensor fusion code in the kalman branch provides very stable and reliable device orientation w.r.t the world and we can use these in mobile devices with IMUs.

We should make DETECT_PERIODICALLY default

We should make DETECT_PERIODICALLY the default detection trigger because with DETECT_ONLY the "doesn't care about tweaking settings" user is missing out on tracking goodness. He/she will not even notice we have tracking at all.

Returned tags should have confidence values

Returned tags should have confidence values (e.g between 0 and 1) just like the skeleton joint confidences returned by OpenNI skeleton tracker for Kinect. This would be very useful on the user side where we can e.g decide to trust some tag more than another in a multi-tag setting.

It should be according to some metric or a combination of multiple metrics, some ideas are:

  • Pixel colors on top of tag bits indicate confidence, i.e black/white indicate high confidence while gray tones indicate low confidence etc.
  • Give tags with lower visual area lower confidence
  • Give lower confidence to tags that have lower visual area than a certain threshold
  • Give flatter tags, i.e tags that are seen from a narrower angle, lower confidence

Compilation fails on Visual Studio 2012

Here I post the errors for each file;

FindQuadsWithLSD.cpp
1>findquadswithlsd.cpp(58): error C2552: 'seg00' : non-aggregates cannot be initialized with initializer list
1>          'cv::Point_<_Tp>' : Types with user defined constructors are not aggregate
1>          with
1>          [
1>              _Tp=float
1>          ]
1>findquadswithlsd.cpp(59): error C2552: 'seg01' : non-aggregates cannot be initialized with initializer list
1>          'cv::Point_<_Tp>' : Types with user defined constructors are not aggregate
1>          with
1>          [
1>              _Tp=float
1>          ]
1>findquadswithlsd.cpp(68): error C2552: 'seg10' : non-aggregates cannot be initialized with initializer list
1>          'cv::Point_<_Tp>' : Types with user defined constructors are not aggregate
1>          with
1>          [
1>              _Tp=float
1>          ]
1>findquadswithlsd.cpp(69): error C2552: 'seg11' : non-aggregates cannot be initialized with initializer list
1>          'cv::Point_<_Tp>' : Types with user defined constructors are not aggregate
1>          with
1>          [
1>              _Tp=float
1>          ]
1>findquadswithlsd.cpp(118): error C2552: 'p0' : non-aggregates cannot be initialized with initializer list
1>          'cv::Vec<_Tp,cn>' : Types with a base are not aggregate
1>          with
1>          [
1>              _Tp=float,
1>              cn=2
1>          ]
1>findquadswithlsd.cpp(119): error C2552: 'p1' : non-aggregates cannot be initialized with initializer list
1>          'cv::Vec<_Tp,cn>' : Types with a base are not aggregate
1>          with
1>          [
1>              _Tp=float,
1>              cn=2
1>          ]
1>findquadswithlsd.cpp(138): error C2143: syntax error : missing ')' before '{'
1>findquadswithlsd.cpp(138): error C2661: 'std::vector<_Ty>::push_back' : no overloaded function takes 0 arguments
1>          with
1>          [
1>              _Ty=cv::Vec2i
1>          ]
1>findquadswithlsd.cpp(138): error C2143: syntax error : missing ';' before '{'
1>findquadswithlsd.cpp(138): error C2143: syntax error : missing ';' before '}'
1>findquadswithlsd.cpp(138): error C2059: syntax error : ')'
1>findquadswithlsd.cpp(147): error C2065: 'LSD_REFINE_NONE' : undeclared identifier
1>findquadswithlsd.cpp(147): error C3861: 'createLineSegmentDetector': identifier not found
1>findquadswithlsd.cpp(149): error C2614: 'chilitags::FindQuads' : illegal member initialization: 'lsd' is not a base or member
1>findquadswithlsd.cpp(167): error C2065: 'lsd' : undeclared identifier
1>findquadswithlsd.cpp(167): error C2227: left of '->detect' must point to class/struct/union/generic type
1>          type is ''unknown-type''
1>findquadswithlsd.cpp(238): error C2552: 'rawquad' : non-aggregates cannot be initialized with initializer list
1>          'std::vector<_Ty>' : Types with a base are not aggregate
1>          with
1>          [
1>              _Ty=cv::Point2f
1>          ]
1>findquadswithlsd.cpp(242): error C3861: 'convexHull': identifier not found
--------------------------------------------------------------------------------------------------------------------------------
ReadBits.cpp
1>readbits.cpp(43): error C2059: syntax error : '{'
1>readbits.cpp(43): error C2143: syntax error : missing ';' before '{'
1>readbits.cpp(43): error C2143: syntax error : missing ';' before '}'
1>readbits.cpp(43): error C2143: syntax error : missing ';' before ','
1>readbits.cpp(44): error C2143: syntax error : missing ';' before '{'
1>readbits.cpp(44): error C2143: syntax error : missing ';' before '}'
1>readbits.cpp(44): error C2143: syntax error : missing ';' before ','
1>readbits.cpp(45): error C2143: syntax error : missing ';' before '{'
1>readbits.cpp(45): error C2143: syntax error : missing ';' before '}'
1>readbits.cpp(45): error C2143: syntax error : missing ';' before ','
1>readbits.cpp(46): error C2143: syntax error : missing ';' before '{'
1>readbits.cpp(46): error C2143: syntax error : missing ';' before '}'
--------------------------------------------------------------------------------------------------------------------------------
ObjectConfig.cpp
1>objectconfig.hpp(15): error C2864: 'chilitags::MarkerConfig::size' : only static const integral data members can be initialized within a class
1>objectconfig.hpp(16): error C2059: syntax error : '{'
1>objectconfig.hpp(16): error C2334: unexpected token(s) preceding '{'; skipping apparent function body
1>objectconfig.hpp(19): error C2059: syntax error : '{'
1>objectconfig.hpp(19): error C2334: unexpected token(s) preceding '{'; skipping apparent function body
1>objectconfig.hpp(20): error C2864: 'chilitags::MarkerConfig::keep' : only static const integral data members can be initialized within a class
1>objectconfig.cpp(31): error C2039: 'translation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(32): error C2039: 'translation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(33): error C2039: 'translation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(34): error C2039: 'rotation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(35): error C2039: 'rotation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(36): error C2039: 'rotation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(86): warning C4305: 'initializing' : truncation from 'double' to 'const float'
1>objectconfig.cpp(98): error C2039: 'rotation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(99): error C2039: 'rotation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(100): error C2039: 'rotation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(101): error C2039: 'rotation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(102): error C2039: 'rotation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(103): error C2039: 'rotation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(106): error C3536: 'C': cannot be used before it is initialized
1>objectconfig.cpp(106): error C3536: 'E': cannot be used before it is initialized
1>objectconfig.cpp(106): error C3536: 'F': cannot be used before it is initialized
1>objectconfig.cpp(106): error C3536: 'D': cannot be used before it is initialized
1>objectconfig.cpp(106): error C2039: 'translation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(107): error C3536: 'B': cannot be used before it is initialized
1>objectconfig.cpp(107): error C3536: 'D': cannot be used before it is initialized
1>objectconfig.cpp(107): error C3536: 'E': cannot be used before it is initialized
1>objectconfig.cpp(107): error C3536: 'A': cannot be used before it is initialized
1>objectconfig.cpp(107): error C3536: 'F': cannot be used before it is initialized
1>objectconfig.cpp(107): error C3536: 'C': cannot be used before it is initialized
1>objectconfig.cpp(107): error C2039: 'translation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(108): error C3536: 'A': cannot be used before it is initialized
1>objectconfig.cpp(108): error C3536: 'D': cannot be used before it is initialized
1>objectconfig.cpp(108): error C3536: 'E': cannot be used before it is initialized
1>objectconfig.cpp(108): error C3536: 'B': cannot be used before it is initialized
1>objectconfig.cpp(108): error C3536: 'F': cannot be used before it is initialized
1>objectconfig.cpp(108): error C3536: 'C': cannot be used before it is initialized
1>objectconfig.cpp(108): error C2039: 'translation' : is not a member of 'chilitags::MarkerConfig'
1>          objectconfig.hpp(12) : see declaration of 'chilitags::MarkerConfig'
1>objectconfig.cpp(111): error C2059: syntax error : '{'
1>objectconfig.cpp(111): error C2143: syntax error : missing ';' before '}'
--------------------------------------------------------------------------------------------------------------------------------
Objects.cpp
1>objectconfig.hpp(15): error C2864: 'chilitags::MarkerConfig::size' : only static const integral data members can be initialized within a class
1>objectconfig.hpp(16): error C2059: syntax error : '{'
1>objectconfig.hpp(16): error C2334: unexpected token(s) preceding '{'; skipping apparent function body
1>objectconfig.hpp(19): error C2059: syntax error : '{'
1>objectconfig.hpp(19): error C2334: unexpected token(s) preceding '{'; skipping apparent function body
1>objectconfig.hpp(20): error C2864: 'chilitags::MarkerConfig::keep' : only static const integral data members can be initialized within a class

Bindings directory

Should we rename the bindings directory to platforms? It looks like a more favored practice, e.g OpenCV uses that directory.

Discard concave quads

These kind of quads are frequently detected during tracking:

________        ________
\      /       |     _.ยด
 \    /        |   .ยด
  \  /         |  /
   \/          | /
   /\          |/
  /  \
 /    \
/______\

It is impossible for a tag to be concave from any perspective. It would be extremely cheap to calculate whether they are concave in order to discard them.

FindQuad.cpp image scaling

Are you sure line 72

cv::resize(greyscaleImage, mGrayPyramid[0], cv::Size(mMaxInputWidth, greyscaleImage.rows*mMinInputWidth/greyscaleImage.cols), .0, .0, cv::INTER_NEAREST)

is correct?

I think mMinInputWidth should be mMaxInputWidth...

Tune the speed/precision compromise as a parameter

Chilitags tries to optimize both detection performance and processing time, but sometimes it has to decide for a compromise. It would be nice to have a Chilitats::setPerformance(level) that would take values like FASTEST, FAST, PRECISE, MOST_PRECISE, etc. and set various parameters all over Chilitags to implement the user's compromise.

This issue aims at collecting parameters that could be adjusted to implement this:

  • [speed] first test on the non-refined quad and only if it fails, refine + test the refined quad
  • [speed] disable refinement
  • [speed] try the edge detection at only one (specified?) scale
  • [speed] use a simpler edge detection: simpler filter + binarization, or only binarization
  • [speed] no pyramids
  • [precision] increase the size of the window of the edge detection

Implement DETECT_PARTIALLY

(name negociable)

The idea is to combine detection and tracking, where detection whould happen only on a subregion of the input image. The point is to have a faster detection/tracking, which would happen in a more constant time than DETECT_PERIODICALLY.

Simply put, DETECT_PARTIALLY would start the detection on the top left quadrant, and tracking on the full input image. On the next frame, the same would happen with the top right quadrant, then the bottom left, bottom right.

In practice, the subregion would have to slide more smoothly to avoid misdetection of tags on the borders of the quadrants. We also need to take the full input image to handle big tags. Ideally, we could set the size of the subregion as a parameter.

Quad refinements are randomly selected

If multiple quads are found to contain a tag, the latest detected is chosen. This may explain why the corners are sometimes "shaking".
There should be a better way to pick the best quad for a detected tag.

SIGSEGV on tags appearing in frame

I'm getting sigsegv on tags appearing in ReadBits::run(), line 95. It appears with one and with more tags in input.

System: Ubuntu 13.10 x64, OpenCV 2.4.5
chilitags compiled with debug flags, but the problem originally occurred without them.

Allow to specify the pixel format

When we don't use opencv's framegrabber (e.g. on android or Qt), we're not very likely to have BGR24 as a pixel format.

Chilitags converts the image to grayscale anyway, and OpenCV allows for more conversions than just the BGR2Gray we're using.

If we can specify the input pixel format, we don't have to convert the image to BGR24 before giving it to Chilitags for a second conversion.

Build is broken on Ubuntu 12.04

CMake stops on an error due to a misdetection of highgui
g++ is too old for the -std=c++11 flag
opencv default version is 2.3, but we dropped support

Use the GPU

The image processing part of Chilitags could be done on a GPU if available. This would speed up detection a lot.

Get rid of YAML

We should definitely get rid of YAML for external config files. While YAML is a nice spec by itself, there simply isn't any decent standalone cross-platform parsers/dumpers for C++ since it's pretty much dead (well, there's yaml-cpp but the documentation sucks hard). We are currently relying on OpenCV to do the parsing but this might change in the future, and we might have to change all our config files by hand.

I suggest we switch to XML or even better, JSON (to be much more easily compatible with other Java projects such as Cellulo) before it's too late. Since JSON is a subset of YAML, it should be fairly easy to migrate at this point.

camera calibration

hi,
the only text about camera calibration i could found is on ros_markers site: images and camera calibration are read from a standard ROS camera

What does this mean ? The roslaunch command only uses the image-topic and the camera-frame-topic, no camera_info topic ? Or is there anywhere a config file ?

I use a kinect2, but i think i got no good camera calibration in chilitags for this, or am i wrong ? (auto-calibration )

Integrate test data as a submodule

Is there a good reason for having test share in a separate repo? Is it that big (currently it looks like 34M), or do we expect it to become huge in the future?

If there's a good reason, it should at least be a git submodule.

Remove (hide) detection

2D tags are a lot more accessible to developers who don't eat matrices for breakfast. If the camera is orthogonal to the tag plane, transformation matrices are a not so necessary complication (there are many such application in the real world, e.g. all the tabletop interfaces), when most of the time, all we care about is the center of the tag.

However we'd probably making our life as maintainer more complicated than it needs to be, because we could just do everything in 3D, and just give acces to a 2D project, that would by default assume an plane parallel to the image plane for example. Then we can get rid (internally) of 2D filtering, users can have "tag assemblies" in 2D too, we remove the inconsistance between tagIds as int and as "tag_##" strings...

We'd just have to check that the 3d estimation wouldn't hit performance too much in case we don't (really) need it.

Automatic camera calibration

We should try and implement the automatic calibration of the camera during runtime. Assuming that we don't have nonlinear camera elements (spherical, cylindrical etc.) and that the focal point is in the middle of the image, we effectively need to calibrate just two numbers: elements (1,1) and (2,2) of the calibration matrix, i.e the focal lengths in pixel units.

OpenCV does this with a checkerboard. We can do this with our tags: we know their dimensions beforehand. While we see any tags, we can tune the focal lengths until its 3D transform back to the screen matches its actual place on the screen (detected via FindQuads). We should even be able to calculate the focal lengths exactly using algebra.

Here is what I propose for an application that uses Chilitags; there are exactly two alternatives and no more or no less:

  • The application provides a calibration file that is empty/nonexistent, we do this calibration for the first e.g 1000 frames and dump the values to that file. The next time that application runs, the values will be there.
  • The application provides the calibration values without a file.

GUI tool to create multi-tag configurations

We need a small GUI tool to create multi-tag configurations. It doesn't even need to be too complex, e.g manipulation of tags via mouse. It might be just enough that it displays a given tag configuration (and prints it to a file) so that we can know the exact transforms of the involved tags with respect to the multi-tag object frame.

JNI bindings for desktop

JNI bindings for desktop need to be documented. They also need proper build routines, this will be solved partly by solving #33.

Integration test sometimes fails

Integration test sometimes fails due to EXPECT_GT(150.0f, 100.0f*timeWith/referenceTime) because 150.0f is not greater than -nan. Probably a division by zero.

IDs detected, that don't exist anymore.

I'm using a very basic setup where I feed single images (batch) into Chilitags::find using DETECT_ONLY. After detection I draw the found tags into the image and display them.

I noticed that a tag, which was found in the first image, is still detected at the same position in the second image, even if it is not present anymore in the second image.

If the second image is processed multiple times, the "ghost" tag disappears after 3-4 tries.

Automated testing from videos

We do not test chilitags works with tracking (as implemented in #38). To fix that, we need to develop video-based tests. One 'easy' way to do that is to shoot videos where a set of tag remain always in the field of view of the camera (but possible blurry, etc). We can then simply count on how many frames the tags were not all detected.

Chilitags crashes occasionally on Android

Chilitags crashes occasionally on Android. This might be an issue with insufficient native memory, or accessing a Java object from native code while it's being moved/garbage collected (this shouldn't happen with the way we do it according to the JNI documentation).

Below is the tombstone when the app crashes:

03-20 18:14:08.265: I/DEBUG(1973): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
03-20 18:14:08.265: I/DEBUG(1973): Build fingerprint: 'samsung/t0ltexx/t0lte:4.1.2/JZO54K/N7105XXDLL4:user/release-keys'
03-20 18:14:08.265: I/DEBUG(1973): Revision: '10'
03-20 18:14:08.265: I/DEBUG(1973): pid: 15112, tid: 15129, name: Thread-7176  >>> ch.epfl.chili.cellulo <<<
03-20 18:14:08.265: I/DEBUG(1973): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 57d083c3
03-20 18:14:08.435: I/DEBUG(1973):     r0 57d083c3  r1 00018b00  r2 57cef8be  r3 57d083c3
03-20 18:14:08.435: I/DEBUG(1973):     r4 5192ac40  r5 5192b4f8  r6 00000004  r7 40a77e90
03-20 18:14:08.435: I/DEBUG(1973):     r8 5ef27b6c  r9 40a77e84  sl 417a4ba8  fp 5ef27784
03-20 18:14:08.435: I/DEBUG(1973):     ip 400d9dc0  sp 5ef27588  lr 594cfcd8  pc 594cfcdc  cpsr 40070010
03-20 18:14:08.435: I/DEBUG(1973):     d0  433000000000009e  d1  4063c00000000000
03-20 18:14:08.435: I/DEBUG(1973):     d2  3f58034f40000000  d3  4063d5db00000000
03-20 18:14:08.435: I/DEBUG(1973):     d4  3fd0dfa0cc100000  d5  4043d9fa4da4c000
03-20 18:14:08.435: I/DEBUG(1973):     d6  401e000000000000  d7  0000009e60000000
03-20 18:14:08.435: I/DEBUG(1973):     d8  4026000000000000  d9  402700000000000b
03-20 18:14:08.435: I/DEBUG(1973):     d10 423c000042100000  d11 41f0000041300000
03-20 18:14:08.435: I/DEBUG(1973):     d12 0000000042100000  d13 0000000000000000
03-20 18:14:08.435: I/DEBUG(1973):     d14 0000000000000000  d15 0000000000000000
03-20 18:14:08.435: I/DEBUG(1973):     d16 4063c00000000000  d17 4330000000000000
03-20 18:14:08.435: I/DEBUG(1973):     d18 3fbf51e00136732c  d19 bfd3a37a02400000
03-20 18:14:08.435: I/DEBUG(1973):     d20 3fc54cc82f5858d4  d21 3e66376972bea4d0
03-20 18:14:08.435: I/DEBUG(1973):     d22 bfd4a4309d05b1a9  d23 3fe0000000000000
03-20 18:14:08.435: I/DEBUG(1973):     d24 4002948613a0b635  d25 3fa5d133732b548b
03-20 18:14:08.435: I/DEBUG(1973):     d26 847f847f847f847f  d27 4000000000000000
03-20 18:14:08.435: I/DEBUG(1973):     d28 bfa5d13374cef37e  d29 3fd0e95393a62190
03-20 18:14:08.435: I/DEBUG(1973):     d30 3ff0000000000000  d31 3fd78b56362cef38
03-20 18:14:08.435: I/DEBUG(1973):     scr 20000013
03-20 18:14:08.435: I/DEBUG(1973): backtrace:
03-20 18:14:08.435: I/DEBUG(1973):     #00  pc 00031cdc  /data/app-lib/ch.epfl.chili.cellulo-1/libchilitags.so (chilitags::ReadBits::operator()(cv::Mat const&, cv::Matx<float, 4, 2> const&)+820)
03-20 18:14:08.435: I/DEBUG(1973):     #01  pc 00031cd4  /data/app-lib/ch.epfl.chili.cellulo-1/libchilitags.so (chilitags::ReadBits::operator()(cv::Mat const&, cv::Matx<float, 4, 2> const&)+812)
03-20 18:14:08.435: I/DEBUG(1973): stack:
03-20 18:14:08.435: I/DEBUG(1973):          5ef27548  00000005  
03-20 18:14:08.435: I/DEBUG(1973):          5ef2754c  594cf614  /data/app-lib/ch.epfl.chili.cellulo-1/libchilitags.so (cvRound(double)+24)
03-20 18:14:08.435: I/DEBUG(1973):          5ef27550  60000000  /dev/ump
03-20 18:14:08.435: I/DEBUG(1973):          5ef27554  4063b7b1  /system/lib/libgui.so
03-20 18:14:08.435: I/DEBUG(1973):          5ef27558  5ef2756c  
03-20 18:14:08.435: I/DEBUG(1973):          5ef2755c  0000009e  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27560  00000005  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27564  5ef2772c  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27568  5ef27584  
03-20 18:14:08.435: I/DEBUG(1973):          5ef2756c  5ef27584  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27570  5192b638  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27574  5ef2772c  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27578  5ef2772c  
03-20 18:14:08.435: I/DEBUG(1973):          5ef2757c  5ef27604  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27580  df0027ad  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27584  00000000  
03-20 18:14:08.435: I/DEBUG(1973):     #00  5ef27588  5ef27568  
03-20 18:14:08.435: I/DEBUG(1973):          5ef2758c  5ef27590  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27590  00000008  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27594  00000008  
03-20 18:14:08.435: I/DEBUG(1973):          5ef27598  42ff400d  /dev/ashmem/dalvik-heap (deleted)
03-20 18:14:08.435: I/DEBUG(1973):          5ef2759c  5ef27798  
03-20 18:14:08.435: I/DEBUG(1973):          5ef275a0  5ef277dc  
03-20 18:14:08.435: I/DEBUG(1973):          5ef275a4  5192b49c  
03-20 18:14:08.435: I/DEBUG(1973):          5ef275a8  bc7ad3b4  
03-20 18:14:08.435: I/DEBUG(1973):          5ef275ac  bf090a50  
03-20 18:14:08.435: I/DEBUG(1973):          5ef275b0  40b059e0  /system/lib/libcrypto.so (c2i_ASN1_INTEGER+275)
03-20 18:14:08.435: I/DEBUG(1973):          5ef275b4  3ac01a7a  
03-20 18:14:08.435: I/DEBUG(1973):          5ef275b8  c17dd8f7  
03-20 18:14:08.435: I/DEBUG(1973):          5ef275bc  431eaed8  /dev/ashmem/dalvik-heap (deleted)
03-20 18:14:08.435: I/DEBUG(1973):          5ef275c0  ba9696d1  
03-20 18:14:08.435: I/DEBUG(1973):          5ef275c4  bdc6b84c  
03-20 18:14:08.435: I/DEBUG(1973): memory near r0:
03-20 18:14:08.435: I/DEBUG(1973):     57d083a0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d083b0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d083c0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d083d0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d083e0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d083f0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d08400 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d08410 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d08420 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d08430 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d08440 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d08450 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d08460 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d08470 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d08480 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     57d08490 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973): memory near r1:
03-20 18:14:08.435: I/DEBUG(1973):     00018ae0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     00018af0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     00018b00 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     00018b10 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     00018b20 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.435: I/DEBUG(1973):     00018b30 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     00018b40 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     00018b50 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     00018b60 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     00018b70 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     00018b80 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     00018b90 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     00018ba0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     00018bb0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     00018bc0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     00018bd0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973): memory near r2:
03-20 18:14:08.440: I/DEBUG(1973):     57cef89c 1c1e1c1b 1e1e1e1d 1d1e1e1d 201e1d1e  
03-20 18:14:08.440: I/DEBUG(1973):     57cef8ac 2021211f 1b181e20 3c26201d 3e3c3f41  
03-20 18:14:08.440: I/DEBUG(1973):     57cef8bc 4c46423f 68655e55 3d406067 58824e42  
03-20 18:14:08.440: I/DEBUG(1973):     57cef8cc 6d6c6962 7270706e 76747472 7a7a7977  
03-20 18:14:08.440: I/DEBUG(1973):     57cef8dc 817e7d7b 8f898683 dcdbd4a6 dcdcdcdc  
03-20 18:14:08.440: I/DEBUG(1973):     57cef8ec dcdbdbdc dcdbdcdb dbdbdbdc dadadada  
03-20 18:14:08.440: I/DEBUG(1973):     57cef8fc d8d9dadb dadad9da dadad9d9 d9d9dada  
03-20 18:14:08.440: I/DEBUG(1973):     57cef90c dadadada dadbdada c7c6c8d6 cac7c7c7  
03-20 18:14:08.440: I/DEBUG(1973):     57cef91c cdcececd d5d0cbc8 d6d6d6d7 cdd1d4d6  
03-20 18:14:08.440: I/DEBUG(1973):     57cef92c d2cac9c9 d4d3d4d3 d2d4d4d2 d1d3d2d2  
03-20 18:14:08.440: I/DEBUG(1973):     57cef93c cfcecfd1 c3c5cacc c2c1c3c6 bdbfc0c0  
03-20 18:14:08.440: I/DEBUG(1973):     57cef94c bfbdbdbf c6c3c2c0 ccccc8c6 d1d0d0cd  
03-20 18:14:08.440: I/DEBUG(1973):     57cef95c cfd1cfd1 d1d0d1d0 cccecdce c7c9cdcb  
03-20 18:14:08.440: I/DEBUG(1973):     57cef96c c3c2c1c5 bfbfc2c1 bfbcbdc0 b9bdbcbc  
03-20 18:14:08.440: I/DEBUG(1973):     57cef97c b7b4b7b9 b3b5b3b5 a6aaacb0 a2a0a0a3  
03-20 18:14:08.440: I/DEBUG(1973):     57cef98c aba19f9f 9fa0a5a6 9b9a9b9e 9c9b9897  
03-20 18:14:08.440: I/DEBUG(1973): memory near r3:
03-20 18:14:08.440: I/DEBUG(1973):     57d083a0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d083b0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d083c0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d083d0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d083e0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d083f0 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d08400 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d08410 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d08420 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d08430 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d08440 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d08450 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d08460 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d08470 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d08480 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973):     57d08490 ffffffff ffffffff ffffffff ffffffff  
03-20 18:14:08.440: I/DEBUG(1973): memory near r4:
03-20 18:14:08.440: I/DEBUG(1973):     5192ac20 6e616c66 6f732e6e 00000000 0000004b  
03-20 18:14:08.440: I/DEBUG(1973):     5192ac30 4016e180 4016e180 6c667065 5192ac30  
03-20 18:14:08.440: I/DEBUG(1973):     5192ac40 61687178 687a4b50 4a525a61 4d555a62  
03-20 18:14:08.440: I/DEBUG(1973):     5192ac50 58603d49 3a3f4752 42484f5c a276343c  
03-20 18:14:08.440: I/DEBUG(1973):     5192ac60 33389871 00000001 69646e69 2e73676e  
03-20 18:14:08.440: I/DEBUG(1973):     5192ac70 00000048 00000023 0000000f 0000000f  
03-20 18:14:08.440: I/DEBUG(1973):     5192ac80 00000001 74616546 32657275 52422e44  
03-20 18:14:08.440: I/DEBUG(1973):     5192ac90 004b5349 00000023 0000000f 0000000f  
03-20 18:14:08.440: I/DEBUG(1973):     5192aca0 00000001 74616546 32657275 52422e44  
03-20 18:14:08.440: I/DEBUG(1973):     5192acb0 00464549 00000023 0000000e 0000000e  
03-20 18:14:08.440: I/DEBUG(1973):     5192acc0 00000001 74616546 32657275 41462e44  
03-20 18:14:08.440: I/DEBUG(1973):     5192acd0 00005453 00000023 0000000f 0000000f  
03-20 18:14:08.440: I/DEBUG(1973):     5192ace0 00000001 74616546 32657275 41462e44  
03-20 18:14:08.440: I/DEBUG(1973):     5192acf0 00585453 0000001b 00000000 00000000  
03-20 18:14:08.440: I/DEBUG(1973):     5192ad00 00000000 5192ace4 00000000 0000008b  
03-20 18:14:08.440: I/DEBUG(1973):     5192ad10 41f564f0 41f56510 41f540f0 41f54118  
03-20 18:14:08.440: I/DEBUG(1973): memory near r5:
03-20 18:14:08.440: I/DEBUG(1973):     5192b4d8 00000000 5192b4bc 5192b4e4 00000024  
03-20 18:14:08.440: I/DEBUG(1973):     5192b4e8 00000001 5192b760 5192b784 5192b784  
03-20 18:14:08.440: I/DEBUG(1973):     5192b4f8 5950edc0 5192ba98 5192bac0 5192bae8  
03-20 18:14:08.440: I/DEBUG(1973):     5192b508 5192bb10 5950edd8 0000000a 00000010  
03-20 18:14:08.440: I/DEBUG(1973):     5192b518 0000000a 000002aa 00011021 00000400  
03-20 18:14:08.440: I/DEBUG(1973):     5192b528 418ed008 00000038 00000024 5192bb38  
03-20 18:14:08.440: I/DEBUG(1973):     5192b538 5192bb78 5192bb90 5192bbc0 5192bbf0  
03-20 18:14:08.440: I/DEBUG(1973):     5192b548 5192bc20 00000000 00000003 00000000  
03-20 18:14:08.440: I/DEBUG(1973):     5192b558 00000002 00000001 00000002 00000000  
03-20 18:14:08.440: I/DEBUG(1973):     5192b568 00000002 00000003 00000000 00000001  
03-20 18:14:08.440: I/DEBUG(1973):     5192b578 00000003 00000002 00000001 00000001  
03-20 18:14:08.440: I/DEBUG(1973):     5192b588 00000003 00000000 00000000 00000000  
03-20 18:14:08.440: I/DEBUG(1973):     5192b598 00000000 00000000 0040f660 5976f4e8  
03-20 18:14:08.440: I/DEBUG(1973):     5192b5a8 00000005 0000010f 00000000 00000000  
03-20 18:14:08.440: I/DEBUG(1973):     5192b5b8 00000000 00000000 00000000 00000000  
03-20 18:14:08.440: I/DEBUG(1973):     5192b5c8 00000000 00000000 00000000 00000000  
03-20 18:14:08.440: I/DEBUG(1973): memory near r7:
03-20 18:14:08.440: I/DEBUG(1973):     40a77e70 5ebbcdd0 5806a5f0 00000000 00000000  
03-20 18:14:08.440: I/DEBUG(1973):     40a77e80 f0e00001 5192b288 00000000 37100005  
03-20 18:14:08.440: I/DEBUG(1973):     40a77e90 40a77ec8 5ec1bc28 5806a748 5ebbcdd0  
03-20 18:14:08.440: I/DEBUG(1973):     40a77ea0 00000000 5192b288 00000000 41f48ec0  
03-20 18:14:08.440: I/DEBUG(1973):     40a77eb0 41c9d048 40a77f14 5ec21e8e 5802f798  
03-20 18:14:08.440: I/DEBUG(1973):     40a77ec0 5ec1bc28 00000000 e07c538b 00000144  
03-20 18:14:08.440: I/DEBUG(1973):     40a77ed0 00000000 40410000 00000000 5ec21e2e  
03-20 18:14:08.440: I/DEBUG(1973):     40a77ee0 00000014 00000000 41f48ec0 41c9d048  
03-20 18:14:08.440: I/DEBUG(1973):     40a77ef0 33333334 401b3333 00000000 41b95848  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f00 40a77f6c 59fcd282 58030448 5ec21e8e  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f10 00000000 00000000 59fccc78 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f20 00000000 00000000 00000000 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f30 00000001 40a77f6c 5a6078c0 000053d9  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f40 41b95848 41b92e50 41b92e50 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f50 41b96020 41beb5a0 40a77fdc 59fcd8d8  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f60 58034040 59fcd282 00000000 41b96020  
03-20 18:14:08.445: I/DEBUG(1973): memory near r8:
03-20 18:14:08.445: I/DEBUG(1973):     5ef27b4c 409bf2c0 11a00009 4016e310 41c9d048  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27b5c 5806a5f0 5ef27b84 4092cb10 37100005  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27b6c 40958401 40a77e80 00000001 5ec86c9f  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27b7c 41f48ec0 fe0000ff 4095d45b 40a77e80  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27b8c 5ec86c9c 57c277a0 417a4ba8 409bac78  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27b9c 00000015 00000000 00000000 fe0000ff  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27bac 4016e310 4184e138 4184e138 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27bbc 00000018 00000018 41b80008 409bac78  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27bcc 4092cc80 00000000 5929b2d0 fe0000ff  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27bdc 4201f6a8 4184e138 4184e138 4201f6a8  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27bec 40981ceb 409bac78 409bac78 409bf2c0  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27bfc 4016e310 00000018 409390c4 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27c0c 00000000 00000000 00000000 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27c1c 00000000 00000000 00000000 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27c2c 00000000 00000000 00000000 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27c3c 001f4000 0000e800 4015e978 000003e8  
03-20 18:14:08.445: I/DEBUG(1973): memory near r9:
03-20 18:14:08.445: I/DEBUG(1973):     40a77e64 00000000 41b92ee8 40a77ea4 5ebbcdd0  
03-20 18:14:08.445: I/DEBUG(1973):     40a77e74 5806a5f0 00000000 00000000 f0e00001  
03-20 18:14:08.445: I/DEBUG(1973):     40a77e84 5192b288 00000000 37100005 40a77ec8  
03-20 18:14:08.445: I/DEBUG(1973):     40a77e94 5ec1bc28 5806a748 5ebbcdd0 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     40a77ea4 5192b288 00000000 41f48ec0 41c9d048  
03-20 18:14:08.445: I/DEBUG(1973):     40a77eb4 40a77f14 5ec21e8e 5802f798 5ec1bc28  
03-20 18:14:08.445: I/DEBUG(1973):     40a77ec4 00000000 e07c538b 00000144 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     40a77ed4 40410000 00000000 5ec21e2e 00000014  
03-20 18:14:08.445: I/DEBUG(1973):     40a77ee4 00000000 41f48ec0 41c9d048 33333334  
03-20 18:14:08.445: I/DEBUG(1973):     40a77ef4 401b3333 00000000 41b95848 40a77f6c  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f04 59fcd282 58030448 5ec21e8e 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f14 00000000 59fccc78 00000000 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f24 00000000 00000000 00000000 00000001  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f34 40a77f6c 5a6078c0 000053d9 41b95848  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f44 41b92e50 41b92e50 00000000 41b96020  
03-20 18:14:08.445: I/DEBUG(1973):     40a77f54 41beb5a0 40a77fdc 59fcd8d8 58034040  
03-20 18:14:08.445: I/DEBUG(1973): memory near sl:
03-20 18:14:08.445: I/DEBUG(1973):     417a4b88 00000015 41783668 00000000 00000453  
03-20 18:14:08.445: I/DEBUG(1973):     417a4b98 59fccd62 40a77e80 5806a748 51e3a000  
03-20 18:14:08.445: I/DEBUG(1973):     417a4ba8 41c9d048 00000144 5ef27ca0 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     417a4bb8 5ef27cd4 0000000b 00000000 4092cc80  
03-20 18:14:08.445: I/DEBUG(1973):     417a4bc8 00000000 00000000 57109070 40a74300  
03-20 18:14:08.445: I/DEBUG(1973):     417a4bd8 00000000 00000000 00000001 00004000  
03-20 18:14:08.445: I/DEBUG(1973):     417a4be8 00000000 417a4898 4092cc80 40931bc0  
03-20 18:14:08.445: I/DEBUG(1973):     417a4bf8 00000000 40935cbc 40935d30 40935be0  
03-20 18:14:08.445: I/DEBUG(1973):     417a4c08 40935c00 40935c5c 00000000 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     417a4c18 4178a388 00000028 00000000 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     417a4c28 00000000 00000006 00001e9e 409bf9ec  
03-20 18:14:08.445: I/DEBUG(1973):     417a4c38 41bebbd8 580418b0 00000002 417a4fe8  
03-20 18:14:08.445: I/DEBUG(1973):     417a4c48 00000001 00000040 00000200 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     417a4c58 00000009 5ebcdafc 5ebcdafc 0000000e  
03-20 18:14:08.445: I/DEBUG(1973):     417a4c68 5ebcdb1c 58064b58 601693e2 6014e5a5  
03-20 18:14:08.445: I/DEBUG(1973):     417a4c78 601c64a8 601c70ec 600bde64 6015fb6f  
03-20 18:14:08.445: I/DEBUG(1973): memory near fp:
03-20 18:14:08.445: I/DEBUG(1973):     5ef27764 00000003 5950c428 5ef27688 5192ac41  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27774 5950c428 5192b4f8 5950fdd8 5ef27854  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27784 594dc1e0 409bac78 57c2c050 5192b380  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27794 5ef27880 433382cf 43b7576c 43336b8f  
03-20 18:14:08.445: I/DEBUG(1973):     5ef277a4 43b84564 432e42b5 43525c0c 43335104  
03-20 18:14:08.445: I/DEBUG(1973):     5ef277b4 4350f3e7 ffffffff 00000000 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     5ef277c4 00000000 00000000 00000000 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     5ef277d4 00000000 00000000 42ff4000 00000002  
03-20 18:14:08.445: I/DEBUG(1973):     5ef277e4 00000168 00000280 57ccf010 57d07410  
03-20 18:14:08.445: I/DEBUG(1973):     5ef277f4 57ccf010 57d07410 57d07410 00000000  
03-20 18:14:08.445: I/DEBUG(1973):     5ef27804 5ef277e4 5ef2780c 00000280 00000001  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27814 57899bb0 57899b70 5192b298 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27824 41856de8 41856de8 41856de8 00000001  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27834 57899a70 57899bb0 57899c70 57899b70  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27844 5ef27834 5806a5f0 417a4b98 5ef2786c  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27854 594dc958 5ef2786c 57c2c050 5192b298  
03-20 18:14:08.450: I/DEBUG(1973): memory near ip:
03-20 18:14:08.450: I/DEBUG(1973):     400d9da0 dd485429 3ff5ab07 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9db0 00000000 80000000 00000000 80000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9dc0 00000000 43300000 00000000 c3300000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9dd0 4b000000 cb000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9de0 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9df0 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9e00 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9e10 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9e20 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9e30 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9e40 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9e50 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9e60 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9e70 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9e80 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     400d9e90 00000000 00000000 00000000 00000000  
03-20 18:14:08.450: I/DEBUG(1973): memory near sp:
03-20 18:14:08.450: I/DEBUG(1973):     5ef27568 5ef27584 5ef27584 5192b638 5ef2772c  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27578 5ef2772c 5ef27604 df0027ad 00000000  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27588 5ef27568 5ef27590 00000008 00000008  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27598 42ff400d 5ef27798 5ef277dc 5192b49c  
03-20 18:14:08.450: I/DEBUG(1973):     5ef275a8 bc7ad3b4 bf090a50 40b059e0 3ac01a7a  
03-20 18:14:08.450: I/DEBUG(1973):     5ef275b8 c17dd8f7 431eaed8 ba9696d1 bdc6b84c  
03-20 18:14:08.450: I/DEBUG(1973):     5ef275c8 3f800000 42ff400d 00000002 00000004  
03-20 18:14:08.450: I/DEBUG(1973):     5ef275d8 00000001 57899c80 57899ca0 57899c80  
03-20 18:14:08.450: I/DEBUG(1973):     5ef275e8 57899ca0 57899ca0 00000000 5ef275d4  
03-20 18:14:08.450: I/DEBUG(1973):     5ef275f8 5ef275fc 00000008 00000008 42ff8000  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27608 00000002 00000098 00000006 57cef8be  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27618 57d07410 57ccf010 57d07410 57d07410  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27628 00000000 5ef2760c 5ef27634 00000280  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27638 00000001 5192b758 5192b638 432e0000  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27648 43500000 000000ae 000000d0 00000006  
03-20 18:14:08.450: I/DEBUG(1973):     5ef27658 00000098 60352c38 8001000d 5ef275cc  
03-20 18:14:08.450: I/DEBUG(1973): code around pc:
03-20 18:14:08.450: I/DEBUG(1973):     594cfcbc e51b1028 eb0002f2 e24b2d06 e24b3058  
03-20 18:14:08.450: I/DEBUG(1973):     594cfccc e1a00002 e1a01003 eb000303 e1a03000  
03-20 18:14:08.450: I/DEBUG(1973):     594cfcdc e5d33000 e5c43000 e24b3f51 e1a00003  
03-20 18:14:08.450: I/DEBUG(1973):     594cfcec eb0002cf e24b2f51 e24b3f52 e1a00002  
03-20 18:14:08.450: I/DEBUG(1973):     594cfcfc e1a01003 eb0002b6 e1a03000 e3530000  
03-20 18:14:08.450: I/DEBUG(1973):     594cfd0c 1affffe0 e51b31e0 e2833018 e24b2050  
03-20 18:14:08.450: I/DEBUG(1973):     594cfd1c e1a00002 e1a01003 ebffebb7 e51b31e0  
03-20 18:14:08.450: I/DEBUG(1973):     594cfd2c e2833050 e24b203c e1a00002 e1a01003  
03-20 18:14:08.450: I/DEBUG(1973):     594cfd3c eb0002fe e24b0050 e24b103c e3a02000  
03-20 18:14:08.450: I/DEBUG(1973):     594cfd4c e3a03000 e3433ff0 e1cd20f0 e3a03008  
03-20 18:14:08.450: I/DEBUG(1973):     594cfd5c e58d3008 e3a02000 e3a03000 e34b3ff0  
03-20 18:14:08.450: I/DEBUG(1973):     594cfd6c ebffebf3 e51b31e0 e2834050 e24b3d06  
03-20 18:14:08.450: I/DEBUG(1973):     594cfd7c e1a00003 ebffeeb0 e24b3f6e e1a00003  
03-20 18:14:08.450: I/DEBUG(1973):     594cfd8c ebffeff7 e1a03004 ea00001b ea000015  
03-20 18:14:08.450: I/DEBUG(1973):     594cfd9c ea000014 ea000013 ea000012 ea000011  
03-20 18:14:08.455: I/DEBUG(1973):     594cfdac ea000010 e24b30f4 e1a00003 ebffeea2  
03-20 18:14:08.455: I/DEBUG(1973): code around lr:
03-20 18:14:08.455: I/DEBUG(1973):     594cfcb8 e1a00003 e51b1028 eb0002f2 e24b2d06  
03-20 18:14:08.455: I/DEBUG(1973):     594cfcc8 e24b3058 e1a00002 e1a01003 eb000303  
03-20 18:14:08.455: I/DEBUG(1973):     594cfcd8 e1a03000 e5d33000 e5c43000 e24b3f51  
03-20 18:14:08.455: I/DEBUG(1973):     594cfce8 e1a00003 eb0002cf e24b2f51 e24b3f52  
03-20 18:14:08.455: I/DEBUG(1973):     594cfcf8 e1a00002 e1a01003 eb0002b6 e1a03000  
03-20 18:14:08.455: I/DEBUG(1973):     594cfd08 e3530000 1affffe0 e51b31e0 e2833018  
03-20 18:14:08.455: I/DEBUG(1973):     594cfd18 e24b2050 e1a00002 e1a01003 ebffebb7  
03-20 18:14:08.455: I/DEBUG(1973):     594cfd28 e51b31e0 e2833050 e24b203c e1a00002  
03-20 18:14:08.455: I/DEBUG(1973):     594cfd38 e1a01003 eb0002fe e24b0050 e24b103c  
03-20 18:14:08.455: I/DEBUG(1973):     594cfd48 e3a02000 e3a03000 e3433ff0 e1cd20f0  
03-20 18:14:08.455: I/DEBUG(1973):     594cfd58 e3a03008 e58d3008 e3a02000 e3a03000  
03-20 18:14:08.455: I/DEBUG(1973):     594cfd68 e34b3ff0 ebffebf3 e51b31e0 e2834050  
03-20 18:14:08.455: I/DEBUG(1973):     594cfd78 e24b3d06 e1a00003 ebffeeb0 e24b3f6e  
03-20 18:14:08.455: I/DEBUG(1973):     594cfd88 e1a00003 ebffeff7 e1a03004 ea00001b  
03-20 18:14:08.455: I/DEBUG(1973):     594cfd98 ea000015 ea000014 ea000013 ea000012  
03-20 18:14:08.455: I/DEBUG(1973):     594cfda8 ea000011 ea000010 e24b30f4 e1a00003  
03-20 18:14:08.455: I/DEBUG(1973): memory map around fault addr 57d083c3:
03-20 18:14:08.455: I/DEBUG(1973):     57ccf000-57d08000 rw- 
03-20 18:14:08.455: I/DEBUG(1973):     (no map for address)
03-20 18:14:08.455: I/DEBUG(1973):     57d29000-57d2a000 --- /dev/ashmem/dalvik-LinearAlloc (deleted)

We should implement multithreaded DETECT_PERIODICALLY

We agree that there should be 3 ways to use Chilitags:

  1. Detect all the time, simplest.
  2. Detect and track all the time, takes more time, more robust, OK.
  3. Detect periodically.

Now, the current periodic detection is "1 call detect, 14 calls track, and so on". This must run on the same thread on the user side as the user cannot determine whether Chilitags will be tracking or detecting (without counting the frames manually or calling with TRACK_ONLY and DETECT_ONLY, but neither is the point of DETECT_PERIODICALLY; and this wouldn't be thread safe without appropriate locks). As these run in the same thread, detection delays the pose update of tags significantly; assume that detection takes 200 ms while tracking takes 15 ms. A 200 ms call every half a second causes hiccups even if the visual camera image update is running on another thread.

Now, assume that detection and tracking run on separate threads, once one detect cycle is sacrificed, Chilitags can run at 30 FPS since the detect cycle can catch up with the track cycle.

The easiest way to do this is to launch an additional "detection" thread when Chilitags is created. During a normal Chilitags3D::estimate() call, the frame is copied for the use of tracking and detection. The detection thread, having a new frame, updates the "detected" tag poses as soon as it can. Meanwhile, the Chilitags3D::estimate() call, after copying the frame, takes the most recent detected tag poses and uses it to track and return the results. I'm assuming that we place mutexes where necessary.

At this point, we have alternatives to choose from for various performance presets:

  • Run detection every N frames completed of tracking, if possible; and as long as there's a new camera frame
  • Run detection as frequently as possible, as long as there's a new camera frame

In short, I see no "correct" way of implementing DETECT_PERIODICALLY without at least 1 additional thread. The above implementation can be done with pthreads for cross-platform compatibility.

Or, another solution might be to remove DETECT_PERIODICALLY altogether, lock the appropriate members (such as image buffers and tag poses) across calls to estimate() with mutexes and expect the user to implement periodic detection with DETECT_ONLY and TRACK_ONLY.

What do you think?

Updated chilitags.js

If I try to use the chilitags-javascript.js file (available here), I get "Module is not defined".

I've tried rebuilding it with the instructions there and emscripten, but that hasn't worked so far.

Does anyone have an update js file?

Cheers

Get JNI bindings for Android into Maven repositories

We should get the JNI bindings into the Maven repositories for automatic access by Maven/Gradle enabled projects such as libgdx projects. There is relevant information at http://maven.apache.org/repository/index.html.

We must provide a build server from which Maven fetches the nightly libs. We can also make it fetch native non-Java libs that we build on the server. An example of this is libgdx, it provides native libs and Java wrappers from the build server and the Maven configuration is kept on github: https://github.com/libgdx/libgdx

As a requirement for this, we should build the Java part of JNI bindings with Maven instead of fiddling around with limited Java support in CMake.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.