Fiducial Marker Detection

In this demo application, we will try to detect markers in real-time in an input image stream.

shadow

The main class for this demo is the icl::markers::FiducialDetector, which implements the Configurable interface 1 for dynamic property handling. The FiducialDetector is instantiated with a marker type string. In the example, we use “bch” markers. Once, the marker type is defined, marker IDs can be loaded. For most markers, these are just integer values. For “art” type markers, valid ID’s are marker pattern files, i.e. images, that define valid pattern-images for markers. The actual marker detection is then applied using the:

FiducialDetector::detect(ImgBase*)

method. This returns a vector of Fiducial instances, that provide access to all marker features, such as ID, position, boundary and even 3D pose.

 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
35
36
37
38
39
40
41
42
#include <ICLQt/Common.h>
#include <ICLMarkers/FiducialDetector.h>

HSplit gui;
GenericGrabber grabber;
FiducialDetector fid("bch","[100-200]","size=30x30");

void init(){
  fid.setConfigurableID("fid");

  gui << Draw().handle("draw")
      << Prop("fid").maxSize(18,100)
      << Show();

  grabber.init(pa("-input"));
}

void run(){
  static DrawHandle draw = gui["draw"];
  const ImgBase *image = grabber.grab();
  const std::vector<Fiducial> &fids = fid.detect(image);

  draw = image;
  draw->linewidth(2);
  for(unsigned int i=0;i<fids.size();++i){
    Point32f c = fids[i].getCenter2D();
    float rot = fids[i].getRotation2D();

    draw->color(255,0,0,255);
    draw->linestrip(fids[i].getCorners2D());
    draw->text(fids[i].getName(),c.x,c.y,10);
    draw->color(0,255,0,255);
    draw->fill(0,255,0,255);
    draw->arrow(c, c+Point32f( cos(rot), sin(rot))*25, 5);
  }

  draw.render();
}

int main(int n, char **ppc){
  return ICLApp(n,ppc,"[m]-input|-i(2)",init,run).exec();
}

Step by Step

After including the headers needed, the global application data is instantiated. This time, we use a special top level GUI container of type HSplit which is a horizontal split widget. The FidudicalDetector is directly set up to track “bch”-markers with IDs in range 100 to 200.

#include <ICLQt/Common.h>
#include <ICLMarkers/FiducialDetector.h>

HSplit gui;
GenericGrabber grabber;
FiducialDetector fid("bch","[100-200]","size=30x30");

In the initialization method the fiducial detector is set up with a configurable ID (“fid”), which is used to link the Prop GUI component to the fiducial detector’s properties.

void init(){
  fid.setConfigurableID("fid");

  gui << Draw().handle("draw")
      << Prop("fid").maxSize(18,100)
      << Show();

  grabber.init(pa("-input"));
}

In run, the fiducials are detected and then visualized. The visualization part demonstrates some extra abilities of the Draw() component as well as some of the fiducial features. For each detected marker, the outline, the ID and an arrow to indicate the marker rotation is drawn.

void run(){
  static DrawHandle draw = gui["draw"];
  const ImgBase *image = grabber.grab();
  const std::vector<Fiducial> &fids = fid.detect(image);

  draw = image;
  draw->linewidth(2);
  for(unsigned int i=0;i<fids.size();++i){
    Point32f c = fids[i].getCenter2D();
    float rot = fids[i].getRotation2D();

    draw->color(255,0,0,255);
    draw->linestrip(fids[i].getCorners2D());
    draw->text(fids[i].getName(),c.x,c.y,10);
    draw->color(0,255,0,255);
    draw->fill(0,255,0,255);
    draw->arrow(c, c+Point32f( cos(rot), sin(rot))*25, 5);
  }

  draw.render();
}

Footnotes

1

as shown in an extra chapter of the tutorial