VSLAM Evaluation Framework API Documentation

The Framework API consists of three classes:

All classes are in the namespace vslam_evaluation.

1. Including the API in your program

To use the API copy the source code from the
$basedir/vslam_api_src/
directory to your own source tree.

The following third-party libraries are required:

The API has been tested with libpng 1.2 and libxml++ 2.6.

Give the following flags when linking: (or similar, depending on the library versions you use.)

-lpng12 -lboost_filesystem `pkg-config --libs libxml++-2.6`

2. Using the SequenceReader

As mentioned above, the SequenceReader acts as a camera, providing timestamped images. Typically, your code will have an interface to a live camera, or recorded image sequences. You will want to write a wrapper around SequenceReader, such that you can make it interchangeably with your normal camera interface.

When you construct a SequenceReader, you pass the filename of an XML experiment file. The experiment file says which sequence to load and can contain arbitrary additional parameters. Additional parameters are given as name-value pairs and can be queried by the SequenceReader::existsParameter() and SequenceReader::getParameterValue() methods. Experiment files are not automatically created by the framework, you have to create them yourself. Here is an example:

<?xml version="1.0"?>
<!DOCTYPE experiment SYSTEM "http://vslam.inf.tu-dresden.de/dtds/v0.1/experiment.dtd">
<experiment>
  <sequence_name>textured_plane</sequence_name>
</experiment>
Lets say, you store this file as "my_experiment.xml" and pass the filename to the SequenceReader constructor This will tell the SequenceReader to load the sequence in the directory $FOOTAGE_PATH/textured_plane/.

You have to set the environment variable $FOOTAGE_PATH to the directory where your sequences are stored If you just left your sequences in the frameworks standard $basedir/footage directory, then

$ export FOOTAGE_PATH=$basedir/footage

Here is another experiment.xml example:

<?xml version="1.0"?>
<!DOCTYPE experiment SYSTEM "http://vslam.inf.tu-dresden.de/dtds/v0.1/experiment.dtd">
<experiment>
  <sequence_name>textured_plane</sequence_name>
  <parameters>
    <parameter>
      <name>pixel_noise_sigma</name>
      <value>2</value>
    </parameter>
    <parameter>
      <name>pixel_noise_seed</name>
      <value>1234567890</value>
    </parameter>
  </parameters>
</experiment>
This time we have given two additional parameters, pixel_noise_sigma and pixel_noise_seed. These two are special parameters, that are handled by the SequenceReader itself. By giving pixel_noise_sigma, you tell the SequenceReader that it should add Gaussian noise to the sequence images (with standard deviation pixel_noise_sigma).

You can additionally give a pixel_noise_seed to seed the random number generator. By doing this, you can make sure, that you will get identical noisy images between different program runs.

Two other special parameters handled by the SequenceReader are blur_sigma and blur_mask_width. If the blur_sigma parameter is present, the SequenceReader will blur the input images with a Gaussian kernel. Additionally with blur_mask_width you can set the width in pixels of the convolution kernel. If blur_mask_width is not given, a standard kernel size of (3 + 6 * (int) blur_sigma) is used. For example

    ...
    <parameter>
      <name>blur_sigma</name>
      <value>2</value>
    </parameter>
    <parameter>
      <name>blur_mask_width</name>
      <value>5</value>
    </parameter>
    ...
will convolve the inupt image with a Gaussian kernel with standard deviation 2 pixel. A 5x5 pixel convolution mask is used. Blurring is always done before adding noise.

Once you have constructed the SequenceReader, it is ready to use. You can get the camera parameters (which are read from the sequence.xml file) using the following methods:

and for stereo cameras additionally

You can get the initial camera pose by

Make sure to use the initial camera pose to set up your system! Not all trajectories start in the coordinate origin, and you will get wrong evaluation results, if you start out with the wrong pose.

Once you have set up everything, you can get sequence images in a loop:

  SequenceReader reader("my_experiment.xml");
  ...
  while (reader.next ()) {
    double timestamp = reader.getTimestamp ();
    unsigned char* imagedata = reader.getImage ();

    // process current image
    ...
  }
  // end of sequence
SequenceReader::getTimestamp returns the timestamp of the current image in seconds from the start of the sequence.

SequenceReader::getImage returns a pointer to a unsigned char buffer containing the current image. Data in the buffer is stored as interleaved RGB bytes. (The size of the buffer is resX * resY * 3.)
For stereo cameras, both the buffer contains both images side by side. (In this case, the size of the buffer is (2 * resX) * resY * 3.)

3. Using the LogWriter

You can use the LogWriter to store log data from a SLAM run into a set of XML files. Set up the LogWriter in the following way:
  // SequenceReader reader ("my_experiment.xml");

  LogWriter writer;
  writer.open ("logdir");
  writer.copySetupFile (reader);
LogWriter::open creates a set of XML log files in the directory you provided. If the directory does not exist, it is created.

LogWriter::copySetupFile copies the file setup.xml from the sequence currently open in the argument SequenceReader.
This setup file will later be necessary for the creation of ground truth. (The setup file tells the framework, which camera, scene, and trajectory were used to create the sequence.)

When the LogWriter is setup, you can log data from the running experiment, as described below. When the experiment is complete, call

  writer.finish ();
to complete and close the log files. (finish is also called from the LogWriter destructor).

3.1. Logging Camera Poses

You can log the estimated camera pose at every timestep, where timesteps are identified by the timestamps obtained from the SequenceReader. A camera pose consists of the 3-dimensional location of the camera center and a quaternion rotation. The quaternion describes the orientation of the camera in the world frame, i.e., it rotates points in camera coordinates to points in world coordinates. Poses are logged using LogWriter::logPose.

3.2. Logging Feature Initialisations

A "feature initialisation" consists of the first observation of the feature, the timestamp of the camera frame in which this first observation was made, and an ID for that feature. Later measurements or 3D position estimates of this feature will be associated with this feature using the feature ID. Loggin initialisations is mandatory, because this information is needed to trace ground truth feature positions during the evaluation!

A feature initialisation is logged using LogWriter::logFeatureInit where an observation consists of (u,v) image coordinates, or LogWriter::logFeatureInitStereo where the observation additionally has a disparity coordinate.

3.3. Logging Feature Measurements

A measurement consists of the ID of the feature that was measured, the image coordinates of the observation, and the timestamp of the frame in which the observation was made. Measurements are logged using LogWriter::logMeasurement where an observation consists of (u,v) image coordinates, or LogWriter::logMeasurementStereo where the observation additionally has a disparity coordinate.

3.4. Logging the Estimated Map

You can log the estimated map at every timestep, where timesteps are identified by the timestamps obtained from the SequenceReader. A map estimate consists of a set of feature estimates (LogWriter::MapFeature). A feature estimate consists of the features ID and its 3D world position. Optionally, the feature estimate may contain a normal vector. To log a map estimate collect all your feature estimates into a std::vector and use LogWriter::logMap.

4. Using the FeatureInitsReader

A nice property of the evaluation framework is that it lets your program decide when and where new map features should be initialised. Sometimes however, you would like to force two program runs to use exactly the same features in order to compare the estimated maps afterwards. In this case, you can use the FeatureInitsReader class. The slamlog created by the LogWriter contains a file "feature_inits.xml" with feature initialisation events. When you construct the FeatureInitsReader, you pass this feature_inits file. Then you can get a vector of feature initialisations for every timestamp using FeatureInitsReader::getInitsForTimestamp. Use this instead of your standard new-feature-detection method.

In actual code, this may look similar to the following:

  SequenceReader reader ("my_experiment.xml");
  FeatureInitsReader initsreader ("mylog/feature_inits.xml");
  ...
  while (reader.next ()) {
    double timestamp = reader.getTimestamp ();
    vector <FeatureInitsReader::FeatureInit> inits = initsreader.getInitsForTimestamp (timestamp);

    // initialise features (if any) for current frame
    for (vector <FeatureInitsReader::FeatureInit>::iterator i = inits.begin (); i != inits.end (); ++i) {
      int id = i->feature_id_;
      double u = i->image_position_u_;
      double v = i->image_position_v_;

      // initialise feature
      ...
    }
    ...
  }
  // end of sequence

Generated on Mon Jan 11 13:11:57 2010 for VSLAM API by  doxygen 1.5.6