SwisTrack/Version 3/Contributing

 This page refers to version 3 of SwisTrack. Unless you are still using this old version, you may want to read the documentation of the most recent version of SwisTrack.

=Introduction= SwisTrack is programmed in C++ and should compile on Windows, Linux, and MacOS platforms.

SwisTrack's is divided in three parts
 * The tracking core that takes care of image acquisition and analysis
 * A graphical user interface that provides tools for visualizing different steps in the tracking process
 * A command line interface

The three parts are linked by an XML description that can be found in the file swistrack.exp in the SwisTrack directory. Here, the different processes in the tracking process are organized in components with different modes (see /Using SwisTrack/). For the component input suitable modes are for instance image acquisition from a camera or from a file.

Based on this description (which also specifies the parameter type, e.g. list or integer), the GUI provides appropriate controls for modifying each parameter and storing it to a configuration file, which is a subset of swistrack.exp (see for instance example.cfg in the example directory). Also, the GUI provides panels that allow changing parameters during tracking and observing their influence on the tracking result at the same time (see /Using SwisTrack/).

On the other hand, the structure defined in swistrack.exp should reflect the class hierarchy of the tracking core. As a rule of thumb, each component in swistrack.exp is encapsulated in its own class, whereas modes are implemented using switch statements in the class' member functions. Here, it is the duty of the programmer to verify in the constructor of each class, whether the current operational mode and its parameters are provided in the actual configuration file and throw an exception otherwise.

See /Installing Swistrack/ for information about setting up a developer's environment.

Example
The  section in swistrack.exp describes the distinct tracking steps that are implemented in the tracking core and require parameter input from the user.

         

The  section for instance might have 2 modes (in this example)

 20 <FIXED desc="Fixed" type="boolean" variable="1">0</FIXED> <BGIMAGE desc="Background Image" type="open" param="*.bmp">example/bg.bmp</BGIMAGE> </SEGMENTER> <SEGMENTER mode="1" desc="Running Average" long="The image is segmented by subtracting a static background image from every frame in the video. The 'Threshold' determines the minimal difference for the gray value of an object to be recognized, and 'Max. Number' is the maximal number of contours processed (sorted by size). 'Alpha' is the speed of the exponential averager."> <THRESHOLD desc="Threshold" type="integer" min="1" max="150" variable="1">20</THRESHOLD> <ALPHA desc="Averaging Speed" type="double" min="0" max="1" variable="1">0.02</ALPHA> </SEGMENTER>

Here mode 0 has three parameters (<THRESHOLD>, <FIXED>, and <BGIMAGE>), whereas mode 1 has two parameters (<THRESHOLD>,<ALPHA>), that are of different type. For instance the type "open" of <BGIMAGE> with attribute param="*.bmp" tells the GUI to use an Open File control (the developer should reserve a string variable in its application).

In the source code, the segmenter component can be found in the class Segmenter (segmenter.cpp, segmenter.h). The constructor then needs to look like

if(!IsAttrByXPath(cfgRoot,"/CFG/COMPONENTS/SEGMENTER","mode")) throw "[Segmenter::Segmenter] Segmenter mode undefined (/CFG/COMPONENTS/SEGMENTER)"; mode=GetIntAttrByXPath(cfgRoot,"/CFG/COMPONENTS/SEGMENTER","mode"); switch(mode) {  case 0 : {    CreateExceptionIfEmpty(cfgRoot,"/CFG/SEGMENTER[@mode='0']"); CreateExceptionIfEmpty(cfgRoot,"/CFG/SEGMENTER[@mode='0']/BGIMAGE"); CreateExceptionIfEmpty(cfgRoot,"/CFG/SEGMENTER[@mode='0']/THRESHOLD"); CreateExceptionIfEmpty(cfgRoot,"/CFG/SEGMENTER[@mode='0']/FIXED"); }  case 1 : {    CreateExceptionIfEmpty(cfgRoot,"/CFG/SEGMENTER[@mode='1']"); CreateExceptionIfEmpty(cfgRoot,"/CFG/SEGMENTER[@mode='1']/THRESHOLD"); CreateExceptionIfEmpty(cfgRoot,"/CFG/SEGMENTER[@mode='1']/ALPHA"); }  default : throw "[Segmenter::Segmenter] Segmenter mode not implemented"; } SetParameters;

The parameters themselves are queried in the member function SetParameters, which will be called whenever the user changes parameters during run-time.

=Setting up your Developer Environment=

After downloading all necessary library packages (don't forget to compile them using your development environment), create a project for the SwisTrack core. Then create a project for the SwisTrack GUI, which links the core together with the other libraries. Make sure that you compile both projects as Multithreaded DLL.

Libraries
You will need to link the following libraries


 * libxml++.lib
 * libxml2.lib
 * wxbase26_net.lib
 * wxmsw26_adv.lib
 * wxmsw26_core.lib
 * wxbase26.lib
 * wxtiff.lib
 * wxjpeg.lib
 * wxpng.lib
 * wxzlib.lib
 * wxregex.lib
 * wxexpat.lib
 * winmm.lib
 * comctl32.lib
 * rpcrt4.lib
 * wsock32.lib
 * oleacc.lib
 * odbc32.lib
 * objecttracker.lib
 * 1394camera.lib
 * cv.lib
 * highgui.lib
 * cxcore.lib
 * vispolygon_dll.lib
 * libgeom_dll.lib

=Contributing components and modes= This section addresses how to extend SwisTrack's core functionality by extending a component by a new mode or by adding a new component.

Extending a component by a new mode

 * 1) Add a new section into swistrack.cfg and set the mode attribute to a number not yet used. Also specify the mode's description and its parameters
 * 2) Add your mode into the switch(mode) statement in the constructor of the class that represents the component you want to extend, and throw exceptions for each missing parameter
 * 3) Define appropriate variables in the private section in the class's interface (to be found in .h file)
 * 4) Add your mode into the switch(mode) statement in the SetParameters member function to fetch the parameters from the XML description
 * 5) Go through each member function of the class that you are extending and add code into the switch statement so to implement the functionality that you have in mind. If some of the functionality is redundand, you might want to put your 'case' statement under a case that represents your functionality and remove its 'break;' statement (don't forget to add a break; in your case though)

Adding a new component

 * 1) Have a look at other components to see how they are implemented
 * 2) Inherit your class from the 'Component' class, including component.h also includes some handy macros that you need for accessing the XML structure
 * 3) Your class should be instantiated in the class that is above your component; in turn, your class needs to instantiate the class that is below your component in the functional hierarchy

=Contributing Panels=