Browse Source

added factory support for MultiDataSet to dynamically creating objects handling the creation of LabelSets at runtime

Johannes Ruehle 13 years ago
parent
commit
71c895c44e

+ 2 - 0
cbaselib/BoundingBox.cpp

@@ -19,6 +19,7 @@ BoundingBox::BoundingBox()
 	bottom_right_.x = -1;
 	bottom_right_.y = -1;
 	id_ = -1;
+    unique_id_ = -1;
 }
 
 // A copy-constructor
@@ -27,6 +28,7 @@ BoundingBox::BoundingBox(const BoundingBox &copy)
 	top_left_ = copy.topLeft();
 	bottom_right_ = copy.bottomRight();
 	id_ = copy.id();
+    unique_id_ = copy.unique_id_;
 }
 
 //! A desctructor

+ 6 - 0
cbaselib/BoundingBox.h

@@ -42,7 +42,13 @@ class BoundingBox
   private:
     NICE::CoordT< int > top_left_;
     NICE::CoordT< int > bottom_right_;
+
+    /// id interpreted as a class label
     int id_;
+
+public:
+    /// unique id that distinguishs this particular bounding box object from all others
+    int unique_id_;
 };
 
 } //namespace

+ 102 - 120
cbaselib/ImageInfo.cpp

@@ -23,6 +23,8 @@
 #include <QDomNode>
 #include <QDomElement>
 #include <QPoint>
+#include <QStringList>
+#include <QVariant>
 
 #endif //NICE_USELIB_QT4_XML
 
@@ -115,14 +117,11 @@ ImageInfo::loadImageInfo(const string &aFilename)
 			/* tags */
 			else if (element.tagName() == "tags") {
 				string_buffer = element.text();
-				if (string_buffer.isEmpty()) {
-					rootNode = rootNode.nextSibling();
-					cout << "tags are empty\n";
-					continue;
-				}
-				QByteArray array = string_buffer.toAscii();
-				//TODO: make parsing into the string list 
-				tags_ = string(array.data());
+                if ( !string_buffer.isEmpty()) {
+                    QByteArray array = string_buffer.toAscii();
+                    //TODO: make parsing into the string list
+                    tags_ = string(array.data());
+                }
 			}
 			/* legend */
 			else if (element.tagName() == "legend") {
@@ -152,19 +151,41 @@ ImageInfo::loadImageInfo(const string &aFilename)
 						continue;
 					}
 
-					string_buffer = subElement.text();
+                    // try reading a unique object/bounding box id, which identifies
+                    // this object against all others (not a label)
+                    string_buffer = subElement.attribute("uniqueObjectId");
+                    ok = 1;
+                    int uniqueObjectId = string_buffer.toInt(&ok, 10);
+                    if(!ok)
+                        uniqueObjectId = -1;
 
+
+                    string_buffer = subElement.text();
 					if (subElement.tagName() == "bbox") {
-						BoundingBox bbox = BBoxFromData(&string_buffer, id);
-						//bbox.setID(id);
-						bboxes_.push_back(bbox);
+                        BoundingBox bbox;
+                        bool bValid = BBoxFromData(&string_buffer, id, bbox);
+                        if( bValid )
+                        {
+                            bbox.unique_id_ = uniqueObjectId;
+
+                            bboxes_.push_back(bbox);
+                        }
 					}
 					if (subElement.tagName() == "poly") {
-						Polygon poly = polyFromData(&string_buffer);
-						poly.setID(id);
-						polys_.push_back(poly);
+                        Polygon poly;
+                        bool bValid = polyFromData(&string_buffer, poly);
+                        if(bValid)
+                        {
+                            poly.setID(id);
+                            poly.unique_id_ = uniqueObjectId;
+
+                            polys_.push_back(poly);
+                        }
+
 					}
 
+
+
 					subNode = subNode.nextSibling();
 				}
 			}
@@ -316,120 +337,81 @@ ImageInfo::loadCategoryInfo(QDomElement *anElement)
 /*!
  * format is x;y;w;h where w - width and h - height
  */
-BoundingBox
-ImageInfo::BBoxFromData(
-	QString *aBBoxData,
-	int &id
-)
+bool ImageInfo::BBoxFromData( QString *aBBoxData, int &id, BoundingBox &p_bbox )
 {
-	BoundingBox bbox;
-	bbox.setID(id);
-
-	QString buffer;
-	int startPos = 0;
-	bool ok = 1;
-
-	int counter = 0;
-	for (int i = 0; i < aBBoxData->size(); i++) {
-		if (';' != aBBoxData->at(i))
-			continue;
-
-		buffer = aBBoxData->mid(startPos, i - startPos);
-
-		int bboxData = buffer.toInt(&ok, 10);
-		if (!ok) {
-			cout <<
-				"BBoxFromData: "
-				"bbox format is corrupted\n";
-			break;
-		}
-
-		if (!counter) {
-			bbox.setTopLeft(bboxData, 0);
-			counter++;
-		}
-		else if (1 == counter) {
-			int x = bbox.topLeft().x;
-			bbox.setTopLeft(x, bboxData);
-			counter++;
-		}
-		else if (2 == counter) {
-			bbox.setWidth(bboxData);
-			counter++;
-		}
-		else if (3 == counter) {
-			bbox.setHeight(bboxData);
-			counter++;
-		}
-
-		startPos = i + 1;
-	}
-
-	if (!bbox.isValid() || !ok) {
-		cout <<
-			"BBoxFromData: "
-			"bbox format is corrupted\n";
-		bbox.setTopLeft(0, 0);
-		bbox.setBottomRight(0, 0);
-	}
 
-	return bbox;
+    p_bbox.setID(id);
+
+    QStringList coordsList = aBBoxData->split(";", QString::SkipEmptyParts);
+
+    try
+    {
+        if( coordsList.size() == 4)
+        {
+            int x = QVariant(coordsList[0]).toInt();
+            int y = QVariant(coordsList[1]).toInt();
+            int w = QVariant(coordsList[2]).toInt();
+            int h = QVariant(coordsList[3]).toInt();
+
+            p_bbox.setTopLeft(x,y);
+            p_bbox.setWidth( w );
+            p_bbox.setHeight( h );
+        }
+        else
+        {
+            std::cout <<
+                "BBoxFromData: "
+                "bbox format is corrupted\n";
+
+            return false;
+        }
+    }
+    catch(std::exception &e)
+    {
+        std::cout << "BBoxFromData: exception:" << e.what() << std::endl;
+        return false;
+    }
+
+    if ( !p_bbox.isValid() )
+    {
+        std::cout << "BBoxFromData not valid:"<< aBBoxData->toStdString() << std::endl;
+        p_bbox.setTopLeft(0, 0);
+        p_bbox.setBottomRight(0, 0);
+        return false;
+    }
+
+    return true;
 }
 
 //! A protected member parsing string data and returning a Polygon from it
 /*!
  * format is x0;y0;x1;y1;...
  */
-Polygon
-ImageInfo::polyFromData(
-	QString *aPolyData
-)
+bool ImageInfo::polyFromData( QString *aPolyData, Polygon &p_Poly)
 {
-	Polygon poly;
-	QPoint point;
-	QString buffer;
-	int startPos = 0;
-	bool ok = 1;
-	/* indicates whether coordinate x or y */
-	bool evenFlag = 0;
-
-	for (int i = 0; i < aPolyData->size(); i++) {
-		/* ";" is a separator */
-		if (';' != aPolyData->at(i))
-			continue;
-
-		buffer = aPolyData->mid(startPos, i - startPos);
-
-		int polyCoor = buffer.toInt(&ok, 10);
-		if (!ok) {
-			cout <<
-				"polyFromData: "
-				"poly format is corrupted\n";
-			break;
-		}
-
-		if (!evenFlag) {
-			point.setX(polyCoor);
-			evenFlag = 1;
-		}
-		else {
-			point.setY(polyCoor);
-			poly.push(point.x(), point.y());
-			evenFlag = 0;
-		}
-		startPos = i + 1;
-	}
-
-	/* last coordinate was Xi what means an error or
-	   last converting from string was not successful */
-	if (evenFlag || !ok) {
-		cout <<
-			"polyFromData: "
-			"poly format is corrupted\n";
-		//poly.clear();
-	}
-
-	return poly;
+    QStringList coordsList = aPolyData->split(";", QString::SkipEmptyParts);
+    try
+    {
+        if( coordsList.size() % 2 == 0)
+        {
+            for( int i = 0; i < coordsList.size(); i += 2)
+            {
+                p_Poly.push( QVariant(coordsList[i]).toInt(),
+                              QVariant(coordsList[i+1]).toInt() );
+            }
+        }
+        else
+        {
+            std::cout << "polyFromData: not valid (coordinates not multiple of two)" << std::endl;
+            return false;
+        }
+    }
+    catch(std::exception &e)
+    {
+        std::cout << "polyFromData: exception:" << e.what() << std::endl;
+        return false;
+    }
+    return true;
 }
 
 //!

+ 3 - 2
cbaselib/ImageInfo.h

@@ -54,8 +54,9 @@ class ImageInfo
 
 #ifdef NICE_USELIB_QT4_XML
 
-    Polygon polyFromData ( QString *aPolyData );
-    BoundingBox BBoxFromData ( QString *aBBoxData, int &id );
+    bool polyFromData( QString *aPolyData, Polygon &p_Poly);
+    bool BBoxFromData(QString *aBBoxData, int &id , BoundingBox &p_bbox);
+
     void loadLegendFromElement ( QDomElement *anElement );
     bool loadCategoryInfo ( QDomElement *anElement );
     NICE::ImageT< unsigned int > imageTFromData (

+ 10 - 3
cbaselib/LabeledFileList.cpp

@@ -270,7 +270,6 @@ void LabeledFileList::getFromList (
 	    ls.printInformation();
 }
 
-
 void LabeledFileList::get ( 
     const std::string & dir,
     const Config & datasetconf,
@@ -281,6 +280,8 @@ void LabeledFileList::get (
 {
     std::string pattern = datasetconf.gS("main", "pattern", "");
     std::string filelist = datasetconf.gS("main", "filelist", "");
+    std::string factoryxmlfile = datasetconf.gS("main", "factoryxml", "");
+
     this->debug_dataset = debugDataset;
 
     if ( pattern.size() > 0 ) 
@@ -288,10 +289,16 @@ void LabeledFileList::get (
     else if ( filelist.size() > 0 ) {
 
 		std::string cfilelist = datasetconf.gS("main", "filelist");
-		std::string filelist = ( cfilelist.substr(0,1) == "/" ) ? cfilelist : dir + "/" + cfilelist;
+        std::string filelist = ( cfilelist.substr(0,1) == "/" ) ? cfilelist : dir + "/" + cfilelist;
 
 		getFromList ( filelist, datasetconf, classnames, ls, localizationInfoDisabled );
-    } else {
+    }
+    else if( !factoryxmlfile.empty() &&  m_pLabeledSetFactory != NULL )
+    {
+        factoryxmlfile = ( factoryxmlfile.substr(0,1) == "/" ) ? factoryxmlfile : dir + "/" + factoryxmlfile;
+        m_pLabeledSetFactory->createLabeledSetFromXml( factoryxmlfile, datasetconf,classnames, ls );
+    }
+    else {
 		fprintf (stderr, "LabeledFileList: Unable to obtain labeled file list\n");
 		exit(-1);
     }

+ 20 - 0
cbaselib/LabeledFileList.h

@@ -15,6 +15,7 @@
 #include "ClassNames.h"
 #include "LocalizationResult.h"
 #include "LabeledSet.h"
+#include "LabeledSetFactory.h"
 
 namespace OBJREC {
 
@@ -26,6 +27,8 @@ class LabeledFileList
     private:
 	bool debug_dataset;
 
+    LabeledSetFactory *m_pLabeledSetFactory;
+
     public:
   
 	/** simple constructor */
@@ -39,6 +42,17 @@ class LabeledFileList
 					    const std::string & file,
 					    const NICE::Config & conf ) const;
 
+    /**
+    * @brief extract multiple label information from different sources.
+    *
+    * Different sources specified in the logfile under section "main":
+    *-"pattern" <br>
+    *-"filelist" <br>
+    *-"factoryxml" <br>
+    *  xml file whose information is extracted and inserted into a LabeledSet. In order to use the right xml loader, a factory had to be provided
+    * ( ::setFactory() ). [Johannes Ruehle]
+    * @see LabeledSetFactory
+    */
 	void get ( const std::string & dir,
 		   const NICE::Config & datasetconf,
 		   const ClassNames & classnames, 
@@ -58,6 +72,12 @@ class LabeledFileList
 		   LabeledSet & ls,
 		   bool localizationInfoDisabled = false ) const;
 
+
+    void setFactory(LabeledSetFactory *pLabeledSetFactory)
+    {
+         m_pLabeledSetFactory = pLabeledSetFactory;
+    }
+
 };
 
 

+ 43 - 0
cbaselib/LabeledSetCreatorInterface.h

@@ -0,0 +1,43 @@
+#ifndef LABELEDSETCREATORINTERFACE_H
+#define LABELEDSETCREATORINTERFACE_H
+
+#include "core/basics/Config.h"
+#include "vislearning/cbaselib/ClassNames.h"
+#include "vislearning/cbaselib/LabeledSet.h"
+
+namespace OBJREC
+{
+
+/**
+ * @brief Interface for extraction of information from xml files.
+ *
+ * This is used to have variable way of creating a LabeledSet from possibly many different xml file formats.
+ * Each xml file has its own interface implementation to enable xml specific loadings.
+ *
+ * @see LabeledSetFactory
+ *
+ * @author Johannes Ruehle
+ * @date 2012/05/18
+ */
+class LabeledSetCreatorInterface
+{
+public:
+    LabeledSetCreatorInterface(){};
+
+    virtual ~LabeledSetCreatorInterface(){};
+
+    /**
+     * @brief Extract label information from a xml file and insert in a LabeledSet data structure.
+     * @param p_sXmlFilename xml file name to load
+     * @param p_LabelSet LabeledSet to be filled by data extracted from the xml file.
+     */
+    virtual void createLabeledSet( std::string    p_sXmlFilename,
+                                   const NICE::Config & p_conf,
+                                   const ClassNames & p_classnames,
+                                   LabeledSet &p_LabelSet) = 0;
+
+};
+
+}//Namespace
+
+#endif // LABELEDSETCREATORINTERFACE_H

+ 66 - 0
cbaselib/LabeledSetFactory.cpp

@@ -0,0 +1,66 @@
+#include <stdio.h>
+
+#include <QDomDocument>
+#include <QFile>
+
+#include "LabeledSetFactory.h"
+
+namespace OBJREC
+{
+
+LabeledSetFactory::LabeledSetFactory()
+{
+}
+
+void LabeledSetFactory::createLabeledSetFromXml(std::string sXmlFilename,
+                                                       const NICE::Config &p_conf,
+                                                       const ClassNames &p_classnames,
+                                                       LabeledSet &p_LabelSet)
+{
+
+    QDomDocument doc("dummy");
+    QFile file(sXmlFilename.c_str());
+    if (!file.open(QIODevice::ReadOnly)) {
+        std::cout << "Can not open such file" << std::endl;
+        return;
+    }
+
+    QString errMsg;
+    if (!doc.setContent(&file, &errMsg)) {
+        std::cout << errMsg.toStdString() << std::endl;
+        file.close();
+        return;
+    }
+
+    file.close();
+
+    /* getting all info */
+    QDomElement elements = doc.documentElement();
+    QDomDocumentType type= doc.doctype();
+    std::string sTypeName = type.name().toStdString();
+
+    //choose appropriate xml-LabeledSet loader according to the documenttype, which had previously been added by ::addCreator
+    LabeledSetCreatorInterface *pCreator = this->m_MapLSCreators[ sTypeName ];
+    if( pCreator == NULL )
+    {
+        std::cout << "LabeledSetFactory::createLabeledSetFromXml No creator found for xml type " << sTypeName << std::endl;
+        return;
+    }
+
+    //call specific loading function for the given xml file.
+    pCreator->createLabeledSet( sXmlFilename, p_conf, p_classnames, p_LabelSet );
+
+}
+
+void LabeledSetFactory::addCreator(std::string sCreatorName, LabeledSetCreatorInterface *pCreator)
+{
+    //is there already a mapper for this document type registered?
+    if (this->m_MapLSCreators.find(sCreatorName) != this->m_MapLSCreators.end() )
+        return;  //element already exist, so don't try to overwrite it
+
+    // store the mapping
+    this->m_MapLSCreators[sCreatorName] = pCreator;
+}
+
+
+}//namespace

+ 70 - 0
cbaselib/LabeledSetFactory.h

@@ -0,0 +1,70 @@
+#ifndef LABELEDSETFACTORY_H
+#define LABELEDSETFACTORY_H
+
+#include <string>
+#include <map>
+
+#include "vislearning/cbaselib/LabeledSet.h"
+#include "LabeledSetCreatorInterface.h"
+
+namespace OBJREC
+{
+
+
+/**
+ * @brief Factory providing xml loading classes according to their document type.
+ *
+ * In order to extract ground truth information or - in general - structured data into a MultiDataset, xml files can be used as
+ * containers of file and label information. This factory is used to choose the right loading function for different xml file formats
+ * according to the stated document type in the xml file (e.g. < !DOCTYPE DaimlerStereoPedRecXml > ). This enables a flexible program design
+ * that can handle loading different xml files at runtime.
+ *
+ * When initializing this factory, you map a given document type to the appropriate loading class, which implements the interface given by LabeledSetCreatorInterface.
+ * For example, using the document type "DaimlerStereoPedRecXml" from above, by calling ::addCreator() this string is mapped to the xml load LabeledSetCreatorDaimlerXml,
+ * which exactly knows how to handle the internal xml structure and create a LabeledSet out of it.
+ *
+ * \date 2012/05/18
+ * \author Johannes Ruehle
+ */
+class LabeledSetFactory
+{
+public:
+    LabeledSetFactory();
+
+
+    /**
+    * @brief Fill a LabeledSet with data loaded from a xml file using the right loading object specified by the xml document type.
+    *
+    * Reads the document type of a xml file containing training / test data and calls the appropriate xml extraction class accordingly.
+    * As a result, the xml loaded extract label information and stores them into a LabeledSet
+    *
+    * Note: An appropriate class derived from LabeledSetCreatorInterface had to be added in advance, by LabeledSetFactory::addCreator().
+    *
+    * @param sXmlFilename name of the config file (xml) containing a specific structure stated by the document type
+    *                      according to which the appropriate LabeledSetCreatorInferface implementation is called for xml loading
+    * @param p_conf Global config structure
+    * @param p_classnames Structure containing all classnames of the ground truth
+    * @param p_LabelSet labeled set of data to be created. All loaded data is appended to this structure.
+    */
+    void createLabeledSetFromXml(std::string sXmlFilename,
+                                        const NICE::Config & p_conf,
+                                        const ClassNames & p_classnames,
+                                        LabeledSet &p_LabelSet);
+
+    /**
+     * @brief Create mapping from a xml document type to the appropriate loading function for a xml file.
+     *
+     * @param sCreatorName xml document type stating a specific xml format and its contents
+     * @param pCreator object reference that knows how to load / parse the specific xml file and create a LabeledData set of it.
+     */
+    void addCreator(std::string sCreatorName, LabeledSetCreatorInterface *pCreator);
+
+protected:
+    /// Mapping from xml document type to loader implementation.
+    std::map<std::string, LabeledSetCreatorInterface*> m_MapLSCreators;
+
+};
+
+} //namespace
+
+#endif // LABELEDSETFACTORY_H

+ 20 - 5
cbaselib/LocalizationResult.cpp

@@ -14,7 +14,7 @@
 #include <core/image/LineT.h>
 
 #include "vislearning/cbaselib/LocalizationResult.h"
-#include "vislearning/cbaselib/ImageInfo.h"
+#include "ImageInfo.h"
 #include "core/basics/StringTools.h"
 
 // use this macro to show labeled images
@@ -34,12 +34,14 @@ using namespace NICE;
 SingleLocalizationResult::SingleLocalizationResult ( ClassificationResult *_r, const NICE::Region & _reg, int _controlPoints ) 
     : controlPoints(_controlPoints), hasRegionInformation_bool(true), reg(_reg), r(_r)
 {
+    objectid = -1;
     reg.getRect(xi,yi,xa,ya);
 }
 
 SingleLocalizationResult::SingleLocalizationResult ( ClassificationResult *_r, int _xi, int _yi, int _xa, int _ya ) 
     : controlPoints(4), xi(_xi), yi(_yi), xa(_xa), ya(_ya), hasRegionInformation_bool(true), r(_r)
 {
+    objectid = -1;
 //    reg.add (xi,yi,xa,ya);
 //    this might lead to problems...in general the current Region representation is awful !
 }
@@ -361,14 +363,21 @@ void LocalizationResult::restore (istream & is, int format)
     }
 }
 
-void LocalizationResult::loadImageInfo(std::string sFilename)
+void LocalizationResult::loadImageInfo(std::string sFilename, int selectObjectWithUniqueId)
 {
+    ImageInfo info;
+    info.loadImageInfo(sFilename);
+
+    this->loadImageInfo(info, selectObjectWithUniqueId);
+}
+
+void LocalizationResult::loadImageInfo(ImageInfo &p_ImageInfo, int selectObjectWithUniqueId)
+{
+
     try
     {
-        ImageInfo info;
-        info.loadImageInfo(sFilename);
 
-        const std::list< OBJREC::BoundingBox > *listBBoxes = info.bboxes();
+        const std::list< OBJREC::BoundingBox > *listBBoxes = p_ImageInfo.bboxes();
 
         const double score = 1.0;
         OBJREC::BoundingBox box;
@@ -378,6 +387,10 @@ void LocalizationResult::loadImageInfo(std::string sFilename)
             box = *itBBoxes;
             int id = box.id();
 
+            if( selectObjectWithUniqueId != -1 && selectObjectWithUniqueId != box.unique_id_ )
+                //only extract bounding boxes with a specific unique id. for why, see @
+                continue;
+
             std::stringstream ss;
             ss << id;
 
@@ -388,10 +401,12 @@ void LocalizationResult::loadImageInfo(std::string sFilename)
                 fprintf (stderr, "LocalizationResult::loadImageInfo: no classno found for classname %s (using classno=-1)\n", classname.c_str());
             }
             ClassificationResult *r = new ClassificationResult ( classno, score, cn->getMaxClassno() );
+            r->classname = cn->text( classno );
             SingleLocalizationResult *sr = new SingleLocalizationResult ( r, box.topLeft().x,
                                                                              box.topLeft().y,
                                                                              box.width(),
                                                                              box.height() );
+            sr->objectid = box.unique_id_;
             this->push_back ( sr );
         }
 

+ 11 - 1
cbaselib/LocalizationResult.h

@@ -27,6 +27,8 @@
 
 namespace OBJREC {
 
+class ImageInfo;
+
 class SingleLocalizationResult 
 {
     private:
@@ -43,6 +45,12 @@ class SingleLocalizationResult
     
 	ClassificationResult *r;
 
+    /** Unique object identifier.
+     * (set when loading bounding box information from a ImageInfo file.
+     * @see ImageInfo::loadImageInfo()
+     */
+    int objectid;
+
 
 	SingleLocalizationResult ( ClassificationResult *r, const NICE::Region & reg, int controlPoints = 0 );
 
@@ -134,11 +142,13 @@ class LocalizationResult : public std::vector<SingleLocalizationResult *>, publi
      * So, trying to use for instance Polygon data created with the ImageLabeler will fail (empty LocalizationResult).
      *
      * @param sFilename file name of the image label file (usually *.dat, xml formatted)
+     * @param selectObjectWithUniqueId unique object id for specifying a bounding box that is to be extracted from the label file(default -1, deactivated)
      * @see OBJREC::ImageInfo
      * @author Johannes Rühle
      * @date 2012-05-11
      */
-    void loadImageInfo(std::string sFilename);
+    void loadImageInfo(std::string sFilename, int selectObjectWithUniqueId = -1);
+    void loadImageInfo(ImageInfo &p_ImageInfo, int selectObjectWithUniqueId = -1);
 
     void restore (std::istream & is, int format = 0);
     void store (std::ostream & os, int format = 0) const;

+ 12 - 4
cbaselib/MultiDataset.cpp

@@ -133,11 +133,13 @@ void MultiDataset::selectExamples ( const std::string & examples_command,
 }
 
 /** MultiDataset ------- constructor */
-MultiDataset::MultiDataset( const Config *conf )
+MultiDataset::MultiDataset( const Config *conf , LabeledSetFactory *pSetFactory)
 {
     std::set<string> blocks;
     conf->getAllBlocks ( blocks );
 
+    lfl.setFactory( pSetFactory );
+
     map<string, Config> dsconfs;
     map<string, string> dirs;
     for ( set<string>::iterator i = blocks.begin();
@@ -187,7 +189,7 @@ MultiDataset::MultiDataset( const Config *conf )
 			classnames["traintest"].readFromConfig ( dsconfs["traintest"], classselection_train );
 		}
 		
-		lfl.get ( dirs["traintest"], dsconfs["traintest"], classnames["traintest"], ls_base,
+        lfl.get ( dirs["traintest"], dsconfs["traintest"], classnames["traintest"], ls_base,
 			localizationInfoDisabled, conf->gB("traintest", "debug_dataset", false ) ); 
 
 		std::string examples_train =  conf->gS("traintest", "examples_train" );
@@ -252,8 +254,14 @@ MultiDataset::MultiDataset( const Config *conf )
 			classnames[name].readFromConfig ( dsconfs[name], classselection );
 		}
 		
-		lfl.get ( dirs[name], dsconfs[name], classnames[name], ls_base,
-			localizationInfoDisabled, conf->gB(name, "debug_dataset", false ) ); 
+
+        lfl.get (   dirs[name],
+                    dsconfs[name],
+                    classnames[name],
+                    ls_base,
+                    localizationInfoDisabled,
+                    conf->gB(name, "debug_dataset", false ) );
+
 #ifdef DEBUG_MultiDataset
 		fprintf (stderr, "MultiDataset: class names -->\n" );
 		classnames[name].store ( cerr );

+ 8 - 2
cbaselib/MultiDataset.h

@@ -17,6 +17,7 @@
 
 #include "LabeledSetSelection.h"
 #include "LabeledFileList.h"
+#include "LabeledSetFactory.h"
 #include "LabeledSet.h"
 #include "ClassNames.h"
 
@@ -40,8 +41,13 @@ class MultiDataset
 
     public:
   
-	/** simple constructor */
-	MultiDataset( const NICE::Config *conf );
+    /** Create a new data set consiting of multiple datasets.
+     *
+     * @param pSetFactory factory for creating the right loading object (@see LabeledSetCreatorInterface) for a specified xml config file.
+     *                      The factory is used when the log tag "factoryxml = < file >.xml" is specified in section " [main] ".
+     *  @see LabeledFileList::get()
+     */
+    MultiDataset( const NICE::Config *conf, LabeledSetFactory *pSetFactory = NULL );
       
 	/** simple destructor */
 	virtual ~MultiDataset();

+ 4 - 1
cbaselib/Polygon.cpp

@@ -15,7 +15,8 @@ using namespace NICE;
 Polygon::Polygon()
 {
 	points_.clear();
-	id_ = -1;
+    id_ = -1;
+    unique_id_ = -1;
 }
 
 // A copy-constructor
@@ -23,6 +24,7 @@ Polygon::Polygon(const Polygon &copy)
 {
 	points_ = PointsList(*(copy.points()));
 	id_ = copy.id();
+    unique_id_ = copy.unique_id_;
 }
 
 //! A desctructor
@@ -72,6 +74,7 @@ Polygon::setID(const int &anID)
 		return;
 		/* NOTREACHED */
 	}
+    this->id_ = anID;
 }
 
 //! returns a constant pointer to the list of polygon points(coordinates)

+ 6 - 0
cbaselib/Polygon.h

@@ -35,7 +35,13 @@ class Polygon
 
   private:
     PointsList points_;
+
+    /// id interpreted as a class label
     int id_;
+
+  public:
+    /// unique id that distinguishs this particular bounding box object from all others
+    int unique_id_;
 };
 
 } //namespace