/** * @file ClassNames.cpp * @brief simple interface for class name confusion * @author Erik Rodner * @date 02/08/2008 */ #include "core/image/ImageT.h" #include "core/vector/VectorT.h" #include "core/vector/MatrixT.h" #include #include #include #include #include #include "vislearning/cbaselib/ClassNames.h" #include "core/basics/StringTools.h" #include "core/image/ImageTools.h" #include "vislearning/baselib/ICETools.h" using namespace OBJREC; using namespace std; using namespace NICE; ClassNames::ClassNames() { maxClassNo = 0; } ClassNames::ClassNames ( const ClassNames & cn, const std::string & classselection ) { std::set selection; cn.getSelection ( classselection, selection ); maxClassNo = 0; store ( cerr ); for ( map::const_iterator i = cn.tbl_code_text.begin(); i != cn.tbl_code_text.end(); i++ ) { const std::string & classname = i->second; std::string code = i->first; if ( cn.tbl_code_classno.find ( code ) == cn.tbl_code_classno.end() ) { fprintf ( stderr, "class %s excluded in base classnames\n", code.c_str() ); continue; } int classno = cn.classno ( code ); if ( selection.find ( classno ) != selection.end() ) { addClass ( classno, code, classname ); if ( classno > maxClassNo ) maxClassNo = classno; #ifdef DEBUG_ClassNames fprintf ( stderr, "class %s (%d) inherited\n", code.c_str(), classno ); #endif } else { #ifdef DEBUG_ClassNames fprintf ( stderr, "class %s (%d) excluded in selection\n", code.c_str(), classno ); #endif } } } ClassNames::ClassNames ( const ClassNames & cn ) : tbl_code_text ( cn.tbl_code_text ), tbl_text_code ( cn.tbl_text_code ), tbl_classno_code ( cn.tbl_classno_code ), tbl_code_classno ( cn.tbl_code_classno ), tbl_color_classno ( cn.tbl_color_classno ), tbl_classno_color ( cn.tbl_classno_color ), maxClassNo ( cn.maxClassNo ) { } ClassNames::~ClassNames() { } int ClassNames::classnoFromText ( std::string text ) const { map::const_iterator j = tbl_text_code.find ( text ); if ( j == tbl_text_code.end() ) return -1; map::const_iterator jj = tbl_code_classno.find ( j->second ); if ( jj == tbl_code_classno.end() ) return -1; return jj->second; } void ClassNames::getSelection ( const std::string & classselection, std::set & classnos ) const { if ( classselection.size() <= 0 ) return; std::vector classlist; StringTools::split ( classselection, ',', classlist ); if ( classlist.size() <= 0 ) { fprintf ( stderr, "FATAL ERROR: wrong format for classselection\n" ); exit ( -1 ); } else if ( classlist[0] == "*" ) { map forbidden_classes; for ( size_t k = 1 ; k < classlist.size() ; k++ ) if ( classlist[k].substr ( 0, 1 ) == "-" ) { std::string f_class = classlist[k].substr ( 1 ); #if defined DEBUG_ClassNames fprintf ( stderr, "ClassNames: class %s excluded !\n", f_class.c_str() ); #endif forbidden_classes[ f_class ] = true; } else { fprintf ( stderr, "FATAL ERROR: wrong format for classselection: *,-class0,class1,...\n" ); exit ( -1 ); } for ( map::const_iterator i = tbl_classno_code.begin(); i != tbl_classno_code.end(); i++ ) { int myclassno = i->first; const std::string & classname = text ( myclassno ); if ( forbidden_classes.find ( classname ) != forbidden_classes.end() ) continue; classnos.insert ( myclassno ); } } else { for ( vector::const_iterator i = classlist.begin(); i != classlist.end(); i++ ) { const std::string & classname = *i; map::const_iterator j = tbl_text_code.find ( classname ); if ( j == tbl_text_code.end() ) { fprintf ( stderr, "ClassNames: FATAL ERROR This is not a selection of a subset: %s [%s]\n", classname.c_str(), classselection.c_str() ); exit ( -1 ); } const std::string & code = j->second; int myclassno = classno ( code ); if ( myclassno < 0 ) { fprintf ( stderr, "ClassNames: FATAL ERROR This is not a selection of a subset\n" ); exit ( -1 ); } classnos.insert ( myclassno ); } } } std::string ClassNames::text ( int classno ) const { map::const_iterator i = tbl_code_text.find ( code ( classno ) ); if ( i == tbl_code_text.end() ) { fprintf ( stderr, "ClassNames: no name found for classno %d\n", classno ); return "unknown"; } else { return i->second; } } std::string ClassNames::code ( int classno ) const { map::const_iterator i = tbl_classno_code.find ( classno ); if ( i == tbl_classno_code.end() ) { fprintf ( stderr, "ClassNames: no code found for classno %d\n", classno ); return "unknown"; } else { return i->second; } } int ClassNames::classno ( std::string code ) const { map::const_iterator i = tbl_code_classno.find ( code ); if ( i == tbl_code_classno.end() ) { fthrow ( Exception, "no classno found for code <" << code << ">" ); } else { return i->second; } } int ClassNames::numClasses () const { return tbl_classno_code.size(); } void ClassNames::addClass ( int classno, const std::string & code, const std::string & text ) { tbl_classno_code[classno] = code; tbl_text_code[text] = code; tbl_code_text[code] = text; tbl_code_classno[code] = classno; if ( classno > maxClassNo ) maxClassNo = classno; } bool ClassNames::existsClassno ( int classno ) const { return ( tbl_classno_code.find ( classno ) != tbl_classno_code.end() ); } // refactor-nice.pl: check this substitution // old: bool ClassNames::existsClassCode ( const string & classcode ) const bool ClassNames::existsClassCode ( const std::string & classcode ) const { return ( tbl_code_classno.find ( classcode ) != tbl_code_classno.end() ); } bool ClassNames::readFromConfig ( const Config & datasetconf, // refactor-nice.pl: check this substitution // old: const string & classselection ) const std::string & classselection ) { datasetconf.getAllS ( "classnames", tbl_code_text ); if ( tbl_code_text.size() <= 0 ) { fprintf ( stderr, "ClassNames: no classnames specified\n" ); return false; } // reverse map and lower case for ( map::const_iterator i = tbl_code_text.begin(); i != tbl_code_text.end(); i++ ) tbl_text_code [ i->second ] = i->first; #if defined DEBUG_ClassNames cerr << "ClassNames::read: selection = " << classselection << endl; #endif std::vector classlist; StringTools::split ( classselection, ',', classlist ); if ( classlist.size() <= 0 ) { fprintf ( stderr, "FATAL ERROR: wrong format for classselection\n" ); exit ( -1 ); } else if ( classlist[0] == "*" ) { map forbidden_classes; for ( size_t k = 1 ; k < classlist.size() ; k++ ) if ( classlist[k].substr ( 0, 1 ) == "-" ) { // refactor-nice.pl: check this substitution // old: string f_class = classlist[k].substr(1); std::string f_class = classlist[k].substr ( 1 ); #if defined DEBUG_ClassNames fprintf ( stderr, "ClassNames: class %s excluded !\n", f_class.c_str() ); #endif forbidden_classes[ f_class ] = true; } else { fprintf ( stderr, "FATAL ERROR: wrong format for classselection: *,-class0,class1,...\n" ); exit ( -1 ); } int classno_seq = 0; for ( map::const_iterator i = tbl_code_text.begin(); i != tbl_code_text.end(); i++, classno_seq++ ) { const std::string & classname = i->second; if ( forbidden_classes.find ( classname ) != forbidden_classes.end() ) continue; // refactor-nice.pl: check this substitution // old: string code = tbl_text_code [ i->second ]; std::string code = tbl_text_code [ i->second ]; int classno; classno = classno_seq; tbl_classno_code[classno] = code; tbl_code_classno[code] = classno; if ( classno > maxClassNo ) maxClassNo = classno; #if defined DEBUG_ClassNames fprintf ( stderr, "classno %d class code %s class text %s\n", classno, code.c_str(), classname.c_str() ); #endif } } else { #if defined DEBUG_ClassNames cerr << "list : " << classlist.size() << endl; #endif for ( size_t classno_seq = 0 ; classno_seq < classlist.size() ; classno_seq++ ) { std::string classname = classlist[classno_seq]; if ( tbl_text_code.find ( classname ) != tbl_text_code.end() ) { std::string code = tbl_text_code [ classname ]; int classno; classno = classno_seq; tbl_classno_code[classno] = code; tbl_code_classno[code] = classno; if ( classno > maxClassNo ) maxClassNo = classno; #if defined DEBUG_ClassNames fprintf ( stderr, "classno %d class code %s class text %s\n", ( int ) classno, code.c_str(), classname.c_str() ); #endif } else { fprintf ( stderr, "ClassNames::ClassNames: FATAL ERROR class >%s< not found in data set\n", classname.c_str() ); exit ( -1 ); } } } /****** after all, try to read color coding *******/ map list; datasetconf.getAllS ( "colors", list ); if ( list.size() > 0 ) { for ( map::const_iterator i = list.begin(); i != list.end(); i++ ) { std::string value = i->second; std::string classname = i->first; int _classno = classno ( classname ); vector submatches; if ( StringTools::regexMatch ( value, "^ *([[:digit:]]+) *: *([[:digit:]]+) *: *([[:digit:]]+) *$", submatches ) && ( submatches.size() == 4 ) ) { int r = StringTools::convert ( submatches[1] ); int g = StringTools::convert ( submatches[2] ); int b = StringTools::convert ( submatches[3] ); long index = 256 * ( 256 * r + g ) + b; tbl_color_classno[index] = _classno; tbl_classno_color[_classno] = index; } else { fprintf ( stderr, "LabeledFileList: parse error colors >%s<\n", value.c_str() ); exit ( -1 ); } } } return true; } int ClassNames::getMaxClassno () const { return maxClassNo; } void ClassNames::getRGBColor ( int classno, int & r, int & g, int & b ) const { map::const_iterator i = tbl_classno_color.find ( classno ); if ( i == tbl_classno_color.end() ) { fprintf ( stderr, "ClassNames: no color setting found for class %d\n", classno ); getchar(); double x = classno / ( double ) numClasses(); double rd, gd, bd; convertToPseudoColor ( x, rd, gd, bd ); r = ( int ) ( 255 * rd ); g = ( int ) ( 255 * gd ); b = ( int ) ( 255 * bd ); } else { long color = i->second; b = color % 256; color /= 256; g = color % 256; color /= 256; r = color % 256; } } void ClassNames::getClassnoFromColor ( int & classno, int r, int g, int b ) const { long color = 256 * ( 256 * r + g ) + b; #if defined WIN32 && defined NICE_USELIB_BOOST boost::unordered_map::const_iterator i = tbl_color_classno.find ( color ); #else // __gnu_cxx::hash_map::const_iterator i = tbl_color_classno.find ( color ); #ifdef __clang__ std::unordered_map::const_iterator i = tbl_color_classno.find(color); #else std::tr1::unordered_map::const_iterator i = tbl_color_classno.find ( color ); #endif #endif if ( i == tbl_color_classno.end() ) { classno = -1; } else { classno = i->second; } } void ClassNames::labelToRGB ( const NICE::Image & img, NICE::ColorImage & rgb ) const { int red, green, blue; rgb.resize ( img.width(), img.height() ); for ( int y = 0 ; y < img.height(); y++ ) for ( int x = 0 ; x < img.width(); x++ ) { int label = img.getPixel ( x, y ); getRGBColor ( label, red, green, blue ); rgb.setPixel ( x, y, 0, red ); rgb.setPixel ( x, y, 1, green ); rgb.setPixel ( x, y, 2, blue ); } } int ClassNames::getBackgroundClass () const { if ( existsClassCode ( "various" ) ) return classno ( "various" ); else if ( existsClassCode ( "background" ) ) return classno ( "background" ); else if ( existsClassCode ( "clutter" ) ) return classno ( "clutter" ); else return 0; } void ClassNames::restore ( istream & is, int format ) { this->maxClassNo = -1; if ( is.good() ) { std::string tmp; is >> tmp; //class name bool b_endOfBlock ( false ) ; while ( !b_endOfBlock ) { is >> tmp; // start of block if ( this->isEndTag( tmp, "ClassNames" ) ) { b_endOfBlock = true; continue; } tmp = this->removeStartTag ( tmp ); if ( tmp.compare("content") == 0 ) { is >> tmp; // size: int mySize ( 0 ); is >> mySize; this->tbl_code_text.clear(); this->tbl_text_code.clear(); this->tbl_classno_code.clear(); this->tbl_code_classno.clear(); for ( int i = 0; i < mySize; i++ ) { std::string mytext; is >> mytext; std::string mycode; is >> mycode; int myclassno; is >> myclassno; this->tbl_code_text.insert ( std::pair ( mycode, mytext ) ); this->tbl_text_code.insert ( std::pair ( mytext, mycode ) ); this->tbl_classno_code.insert ( std::pair ( myclassno, mycode ) ); this->tbl_code_classno.insert ( std::pair ( mycode, myclassno ) ); if ( myclassno > this->maxClassNo ) this->maxClassNo = myclassno; } is >> tmp; // end of block tmp = this->removeEndTag ( tmp ); } else { std::cerr << "WARNING -- unexpected ClassNames object -- " << tmp << " -- for restoration... aborting" << std::endl; throw; } } } else { std::cerr << "ClassNames::restore -- InStream not initialized - restoring not possible!" << std::endl; throw; } } void ClassNames::store ( ostream & os, int format ) const { assert ( tbl_classno_code.size() == tbl_code_classno.size() ); if (os.good()) { // show starting point os << this->createStartTag( "ClassNames" ) << std::endl; os.precision (numeric_limits::digits10 + 1); os << this->createStartTag( "content" ) << std::endl; os << "size: " << this->tbl_classno_code.size() << std::endl; for ( std::map< int, std::string >::const_iterator iIt = this->tbl_classno_code.begin(); iIt != this->tbl_classno_code.end(); iIt++ ) { int myclassno = iIt->first; std::string mycode = iIt->second; std::string mytext = text ( myclassno ); os << mytext << " " << mycode << " " << myclassno << endl; } os << this->createEndTag( "content" ) << std::endl; // done os << this->createEndTag( "ClassNames" ) << std::endl; } else { std::cerr << "OutStream not initialized - storing not possible!" << std::endl; } } void ClassNames::clear () { tbl_code_text.clear(); tbl_text_code.clear(); tbl_classno_code.clear(); tbl_code_classno.clear(); tbl_color_classno.clear(); tbl_classno_color.clear(); }