/** * @file LocalizationResult.cpp * @brief Localization result, what else? * @author Erik Rodner * @date 02/13/2008 */ #include #include #include #include "vislearning/cbaselib/LocalizationResult.h" #include "core/basics/StringTools.h" using namespace OBJREC; using namespace std; using namespace NICE; /******** SingleLocalizationResult ********/ SingleLocalizationResult::SingleLocalizationResult ( ClassificationResult *_r, const NICE::Region & _reg, int _controlPoints ) : controlPoints(_controlPoints), hasRegionInformation_bool(true), reg(_reg), r(_r) { 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) { // reg.add (xi,yi,xa,ya); // this might lead to problems...in general the current Region representation is awful ! } double SingleLocalizationResult::getBBOverlapMeasureMin ( const SingleLocalizationResult & y ) const { double measure = 0.0; int xxi, xyi, xxa, xya; int yxi, yyi, yxa, yya; getBoundingBox ( xxi, xyi, xxa, xya ); y.getBoundingBox ( yxi, yyi, yxa, yya ); int mxi = ( xxi > yxi ) ? xxi : yxi; int myi = ( xyi > yyi ) ? xyi : yyi; int mxa = ( xxa < yxa ) ? xxa : yxa; int mya = ( xya < yya ) ? xya : yya; int iw = mxa - mxi + 1; int ih = mya - myi + 1; if ( (iw > 0) && (ih > 0) ) { // if iw>0 & ih>0 double A = (xxa - xxi + 1)*(xya - xyi + 1); double B = (yxa - yxi + 1)*(yya - yyi + 1); double overlap = A < B ? A : B; measure = iw*ih / overlap; } return measure; } double SingleLocalizationResult::getBBOverlapMeasure ( const SingleLocalizationResult & y ) const { double measure = 0.0; int xxi, xyi, xxa, xya; int yxi, yyi, yxa, yya; getBoundingBox ( xxi, xyi, xxa, xya ); y.getBoundingBox ( yxi, yyi, yxa, yya ); int mxi = ( xxi > yxi ) ? xxi : yxi; int myi = ( xyi > yyi ) ? xyi : yyi; int mxa = ( xxa < yxa ) ? xxa : yxa; int mya = ( xya < yya ) ? xya : yya; int iw = mxa - mxi + 1; int ih = mya - myi + 1; if ( (iw > 0) && (ih > 0) ) { // if iw>0 & ih>0 double overlap = (xxa - xxi + 1)*(xya - xyi + 1) + (yxa - yxi + 1)*(yya - yyi + 1) - iw*ih; measure = iw*ih / overlap; } return measure; } void SingleLocalizationResult::getBoundingBox ( int & _xi, int & _yi, int & _xa, int & _ya ) const { _xi = xi; _yi = yi; _xa = xa; _ya = ya; } void SingleLocalizationResult::getBoundingBox ( RectT & rectangle ) const { rectangle = RectT ( CoordT ( xi, yi ), CoordT ( xa, ya ) ); } void SingleLocalizationResult::getCentroid ( double & x, double & y ) const { reg.getCentroid ( x, y ); } SingleLocalizationResult::~SingleLocalizationResult () { if ( r != NULL ) delete r; } /******** LocalizationResult *********/ LocalizationResult::LocalizationResult ( int xsize, int ysize ) : cn(NULL) { hasLabeledImage = false; this->xsize = xsize; this->ysize = ysize; } LocalizationResult::LocalizationResult ( const ClassNames *_cn, int xsize, int ysize ) : cn(_cn) { hasLabeledImage = false; this->xsize = xsize; this->ysize = ysize; } LocalizationResult::~LocalizationResult () { for ( iterator k = begin(); k != end() ; k++ ) { SingleLocalizationResult *slr = *k; delete slr; } } #undef DEBUG_LOCALIZATIONREAD LocalizationResult::LocalizationResult ( const ClassNames *_cn, const NICE::Image & img, int classno ) : cn(_cn) { const int t = 200; // FIXME NICE::Region reg; #ifdef DEBUG_LOCALIZATIONREAD NICE::Image imgo (img); imgo.set(0); #endif this->xsize = img.width(); this->ysize = img.height(); for ( int y = 0 ; y < img.height(); y++ ) for ( int x = 0 ; x < img.width(); x++ ) { // refactor-nice.pl: check this substitution // old: if ( GetVal(img, x, y) < t ) if ( img.getPixel(x,y) < t ) { #ifdef DEBUG_LOCALIZATIONREAD imgo.setPixel(x,y,1); #endif reg.add ( x, y ); } } #ifdef DEBUG_LOCALIZATIONREAD NICE::showImageOverlay ( imgo, imgo ); #endif ClassificationResult *r = new ClassificationResult (classno, 1.0, _cn->getMaxClassno()); push_back ( new SingleLocalizationResult ( r, reg ) ); hasLabeledImage = false; } LocalizationResult::LocalizationResult ( const ClassNames *_cn, const NICE::ColorImage & img) : cn(_cn) { map regions; xsize = img.width(); ysize = img.height(); #ifdef DEBUG_LOCALIZATIONREAD NICE::showImage ( img ); NICE::Image imgo (xsize,ysize); imgo.set(0); #endif for ( int y = 0 ; y < ysize ; y++ ) for ( int x = 0 ; x < xsize ; x++ ) { int r = img.getPixel(x,y,0); int g = img.getPixel(x,y,1); int b = img.getPixel(x,y,2); int classno; _cn->getClassnoFromColor ( classno, r, g, b ); if ( classno >= 0 ) regions[classno].add(x,y); #ifdef DEBUG_LOCALIZATIONREAD imgo.setPixel(x,y,classno); #endif } for ( map::const_iterator j = regions.begin(); j != regions.end(); j++ ) { int classno = j->first; ClassificationResult *r = new ClassificationResult (classno, 1.0, _cn->getMaxClassno()); push_back ( new SingleLocalizationResult ( r, j->second ) ); } hasLabeledImage = false; } void LocalizationResult::restore (istream & is, int format) { if ( format == FILEFORMAT_PASCAL2006_RESULT ) { while ( ! is.eof() ) { double score; int xi, yi, xa, ya; // refactor-nice.pl: check this substitution // old: string classname; std::string classname; if ( ! (is >> classname) ) break; if ( ! (is >> score) ) break; if ( ! (is >> xi) ) break; if ( ! (is >> yi) ) break; if ( ! (is >> xa) ) break; if ( ! (is >> ya) ) break; ClassificationResult *r = new ClassificationResult ( cn->classno(classname), score, cn->getMaxClassno() ); SingleLocalizationResult *sr = new SingleLocalizationResult ( r, xi, yi, xa, ya ); push_back ( sr ); } } else if ( format == FILEFORMAT_PASCAL2006_GROUNDTRUTH ) { #if 0 /* # Details for object 1 ("PAScat") Original label for object 1 "PAScat" : "PAScat" Bounding box for object 1 "PAScat" (Xmin, Ymin) - (Xmax, Ymax) : (11, 135) - (333, 410) */ // refactor-nice.pl: check this substitution // old: string word; std::string word; while ( ! is.eof() ) { if ( ! (is >> word) ) break; if ( word != "Bounding" ) continue; char line[1024]; is.getline (line, 1024); vector submatches; bool result = StringTools::regexMatch ( line, "box for object ([:digit]+) \"([:alpha:]+)\" (Xmin, Ymin) - (Xmax, Ymax) : (([:digit:]+) *, *([:digit:]+)) *: *(([:digit:]+) *, *([:digit:]+))", submatches ); cerr << "string: " << line << endl; for ( vector::const_iterator i = submatches.begin(); i != submatches.end(); i++ ) cerr << "submatch " << *i << endl; exit(-1); } #endif } else if ( format == FILEFORMAT_POLYGON ) { // This is limited to bounding boxes ...sorry while (! is.eof()) { #define USE_CALTECH101_POLYGON_FORMAT #ifdef USE_CALTECH101_POLYGON_FORMAT std::string filename; if ( !(is >> filename) ) break; #endif std::string classname; if ( !(is >> classname) ) break; const double score = 1.0; int classno = cn->classnoFromText(classname); uint polygon_points; if ( !(is >> polygon_points) ) break; int xi = std::numeric_limits::max(); int xa = - std::numeric_limits::max(); int yi = std::numeric_limits::max(); int ya = - std::numeric_limits::max(); for ( uint i = 0 ; i < polygon_points ; i++ ) { double x,y; if ( !(is >> x) ) break; if ( !(is >> y) ) break; if ( x < xi ) xi = x; if ( x > xa ) xa = x; if ( y < yi ) yi = y; if ( y > ya ) ya = y; } if ( classno >= 0 ) { ClassificationResult *r = new ClassificationResult ( classno, score, cn->getMaxClassno() ); SingleLocalizationResult *sr = new SingleLocalizationResult ( r, xi, yi, xa, ya ); push_back ( sr ); } } //sortEmpricalDepth(); } else { fthrow(IOException, "LocalizationResult::restore: file format not yet supported !"); } } void LocalizationResult::store (ostream & os, int format) const { if ( format == FILEFORMAT_PASCAL2006_RESULT ) { for ( const_iterator i = begin(); i != end(); i++ ) { const SingleLocalizationResult *sr = *i; const ClassificationResult *r = sr->r; int classno = r->classno; double score = r->scores.get(classno); int xi, yi, xa, ya; sr->getBoundingBox ( xi, yi, xa, ya ); os << cn->text(r->classno) << " " << score << " " << xi << " " << yi << " " << xa << " " << ya << " " << endl; } } else { fprintf (stderr, "LocalizationResult::store: file format not yet supported !\n"); exit(-1); } } void LocalizationResult::clear () { for ( iterator k = begin(); k != end() ; k++ ) { SingleLocalizationResult *slr = *k; delete slr; } vector::clear(); hasLabeledImage = false; } /** returns whether the depth of x is smaller than that of y !!! no transitivity !!! */ bool depthCompare ( const SingleLocalizationResult *x, const SingleLocalizationResult *y ) { /** According to the LabelMe paper of Torralba et al., Murphy */ const NICE::Region & rx = x->getRegion(); const NICE::Region & ry = y->getRegion(); NICE::Region intersect; intersect.setIntersection ( rx, ry ); int ax = rx.size(); int ay = ry.size(); int is = intersect.size(); if ( is == 0 ) { int nx = x->getControlPoints(); int ny = y->getControlPoints(); return ( nx > ny ); } else { double ratx = (double)is / ax; double raty = (double)is / ay; return ( ratx > raty ); } } bool confidenceCompare ( const SingleLocalizationResult *x, const SingleLocalizationResult *y ) { return ( x->r->confidence() > y->r->confidence() ); } void LocalizationResult::sortDescendingConfidence() { sort ( begin(), end(), confidenceCompare ); } void LocalizationResult::sortEmpricalDepth() { sort ( begin(), end(), depthCompare ); } void LocalizationResult::calcLabeledImage ( NICE::Image & mark, int backgroundClassNo ) const { mark.set(backgroundClassNo); fprintf (stderr, "LocalizationResult: calcLabeledImage %zd\n", size() ); for ( int y = 0 ; y < mark.height(); y++ ) for ( int x = 0 ; x < mark.width(); x++ ) { for ( LocalizationResult::const_iterator k = begin(); k != end() ; k++ ) { SingleLocalizationResult *slr = *k; const NICE::Region & r = slr->getRegion(); if ( r.inside(x,y) ) { mark.setPixel(x,y,slr->r->classno); break; } } } } void LocalizationResult::getLabeledImageCache ( NICE::Image & mark ) const { assert ( hasLabeledImage ); labeledImage->copyFrom ( mark ); } void LocalizationResult::setMap ( const NICE::Image & _labeledImage ) { labeledImage = new Image( _labeledImage ); hasLabeledImage = true; } void drawOrthoLine ( NICE::ColorImage & img, int x1, int y1, int x2, int y2, int width, int sign, int r, int g, int b ) { int xi = x1; int yi = y1; int xa = x2; int ya = y2; for ( int i = 0 ; i < width; i++ ) { if ( yi == ya ) { yi = yi + sign; ya = ya + sign; } else if ( xi == xa ) { xi = xi + sign; xa = xa + sign; } else { assert ( 0 == 1 ); } if ( (xi>=0) && (yi>=0) && (xa<=img.width()) && (ya<=img.height()) ) { NICE::Line l ( Coord(xi, yi), Coord(xa, ya) ); img.draw( l, NICE::Color(r, g, b) ); } } } void LocalizationResult::displayBoxes ( NICE::ColorImage & img, const ClassNames *cn, bool display_confidence, bool invert, int width ) const { for ( LocalizationResult::const_iterator k = begin(); k != end() ; k++ ) { SingleLocalizationResult *slr = *k; int xi, yi, xa, ya; slr->getBoundingBox ( xi, yi, xa, ya ); int classno = (slr->r == NULL ) ? 0 : slr->r->classno; int r,g,b; if ( cn != NULL ) { cn->getRGBColor ( classno, r, g, b ); } else { r = 255; g = 0; b = 0; } if ( invert ) { r = 255 - r; g = 255 - g; b = 255 - b; } if ( display_confidence && (cn != NULL)) { std::string name = cn->text(classno); char caption[1024]; sprintf ( caption, "%3.2lf %s", slr->r->confidence(), name.c_str() ); // refactor-nice.pl: check this substitution // old: Text(caption, xi, yi, r, 0, img.RedImage()); // REFACTOR-FIXME Unable to map this statement // refactor-nice.pl: check this substitution // old: Text(caption, xi, yi, g, 0, img.GreenImage()); // REFACTOR-FIXME Unable to map this statement // refactor-nice.pl: check this substitution // old: Text(caption, xi, yi, b, 0, img.BlueImage()); // REFACTOR-FIXME Unable to map this statement } drawOrthoLine ( img, xi-width, yi, xa+width, yi, width, -1, r, g, b ); drawOrthoLine ( img, xa, yi, xa, ya, width, +1, r, g, b ); drawOrthoLine ( img, xa+width, ya, xi-width, ya, width, +1, r, g, b ); drawOrthoLine ( img, xi, ya, xi, yi, width, -1, r, g, b ); } }