/** * @file SemSegCsurka2.cpp * @brief semantic segmentation using the method from Csurka08 * @author Björn Fröhlich * @date 04/24/2009 */ #include #include "SemSegCsurka2.h" #include "objrec/fourier/FourierLibrary.h" #include "objrec/baselib/ICETools.h" #include using namespace std; using namespace NICE; using namespace OBJREC; #undef DEBUG_CSURK void readFeats(VVector &features, VVector &positions, string file, string posfile) { ifstream fin (file.c_str()); int nb; int dim; fin >> nb; fin >> dim; for(int i = 0; i < nb; i++) { int l; Vector vec(dim); fin >> l; for(int d = 0; d < dim; d++) { fin >> vec[d]; } features.push_back(vec); assert(vec.size() == features[0].size()); } fin.close(); ifstream posin(posfile.c_str()); posin >> nb; posin >> dim; for(int i = 0; i < nb; i++) { Vector vec(dim); for(int d = 0; d < dim; d++) { posin >> vec[d]; } positions.push_back(vec); assert(vec.size() == positions[0].size()); } posin.close(); cout << "positions: " << positions.size() << " feats.size: " << features.size() << endl; } void readex(string file, Examples &examples) { ifstream fin (file.c_str()); int nb; int dim; fin >> nb; fin >> dim; for(int i = 0; i < nb; i++) { int l; Vector *vec = new Vector(dim); fin >> l; for(int d = 0; d < dim; d++) { fin >> (*vec)[d]; } Example ex; ex.vec = vec; ex.svec = NULL; ex.ce = NULL; examples.push_back(pair ( l, ex)); //assert(vec.size() == (examples[0].second.vec->size()); } fin.close(); } SemSegCsurka2::SemSegCsurka2 ( const Config *conf, const MultiDataset *md ) : SemanticSegmentation ( conf, & ( md->getClassNames ( "train" ) ) ) { this->conf = conf; save_cache = conf->gB ( "FPCPixel", "save_cache", true ); read_cache = conf->gB ( "FPCPixel", "read_cache", false ); cache = conf->gS ( "cache", "root", "" ); sigmaweight = conf->gD ( "SemSegCsurka", "sigmaweight", 0.6 ); dim = conf->gI ( "SemSegCsurka", "pcadim", 50 ); usepca = conf->gB ( "SemSegCsurka", "usepca", true ); calcpca = conf->gB ( "SemSegCsurka", "calcpca", false ); usegmm = conf->gB ( "SemSegCsurka", "usegmm", false ); norm = conf->gB ( "SemSegCsurka", "normalize", false ); usefisher = conf->gB ( "SemSegCsurka", "usefisher", false ); dogmm = conf->gB ( "SemSegCsurka", "dogmm", false ); gaussians = conf->gI ( "SemSegCsurka", "gaussians", 50 ); usekmeans = conf->gB ( "SemSegCsurka", "usekmeans", false ); kmeansfeat = conf->gI ( "SemSegCsurka", "kmeansfeat", 50 ); kmeanshard = conf->gB ( "SemSegCsurka", "kmeanshard", false ); cname = conf->gS ( "SemSegCsurka", "classifier", "RandomForests" ); anteil = conf->gD ( "SemSegCsurka", "anteil", 1.0 ); userellocprior = conf->gB ( "SemSegCsurka", "rellocfeat", false ); bool usesrg = conf->gB ( "SemSegCsurka", "usesrg", false ); useregions = conf->gB ( "SemSegCsurka", "useregions", true ); savesteps = conf->gB ( "SemSegCsurka", "savesteps", true ); bool usegcopt = conf->gB ( "SemSegCsurka", "usegcopt", false ); bestclasses = conf->gI ( "SemSegCsurka", "bestclasses", 0 ); smoothhl = conf->gB ( "SemSegCsurka", "smoothhl", false ); smoothfactor = conf->gD ( "SemSegCsurka", "smoothfactor", 1.0 ); usecolorfeats = conf->gB("SemSegCsurka", "usecolorfeats", false); if ( !useregions && ( userellocprior || usesrg ) ) { cerr << "relative location priors and super region growing are just supported in combination with useregions" << endl; exit ( 1 ); } if ( usepca ) pca = PCA ( dim ); RegionSegmentationMethod * tmpseg = new RSMeanShift ( conf ); seg = new RSCache ( conf, tmpseg ); if ( userellocprior ) relloc = new RelativeLocationPrior ( conf ); else relloc = NULL; if ( usesrg ) srg = new PPSuperregion ( conf ); else srg = NULL; if ( usegcopt ) gcopt = new PPGraphCut ( conf ); else gcopt = NULL; classifier = NULL; vclassifier = NULL; if ( cname == "RandomForests" ) classifier = new FPCRandomForests ( conf, "ClassifierForest" ); else if ( cname == "SMLR" ) classifier = new FPCSMLR ( conf, "ClassifierSMLR" ); else vclassifier = CSGeneric::selectVecClassifier ( conf, "main" ); //classifier = new FPCSparseMultinomialLogisticRegression(conf, "ClassifierSMLR"); if(classifier != NULL) classifier->setMaxClassNo ( classNames->getMaxClassno() ); else vclassifier->setMaxClassNo ( classNames->getMaxClassno() ); cn = md->getClassNames ( "train" ); if ( read_cache ) { fprintf ( stderr, "SemSegCsurka2:: Reading classifier data from %s\n", ( cache+"/fpcrf.data" ).c_str() ); if(classifier != NULL) classifier->read ( cache+"/fpcrf.data" ); else vclassifier->read ( cache+"/veccl.data" ); if ( usepca ) { std::string filename = cache + "/pca"; pca.read ( filename ); } if ( usegmm ) { g = new GMM ( conf, gaussians ); if ( !g->loadData ( cache+"/gmm" ) ) { cerr << "SemSegCsurka2:: no gmm file found" << endl; exit ( -1 ); } } if ( usekmeans ) { k = new KMeansOnline ( gaussians ); } fprintf ( stderr, "SemSegCsurka2:: successfully read\n" ); std::string filename = cache + "/rlp"; FILE *value; value = fopen ( filename.c_str(),"r" ); if ( value==NULL ) { trainpostprocess ( md ); } else { if ( userellocprior ) { relloc->read ( filename ); } } filename = cache + "/srg"; value = fopen ( filename.c_str(),"r" ); if ( value==NULL ) { trainpostprocess ( md ); } else { if ( srg != NULL ) { srg->read ( filename ); } } } else { train ( md ); } } SemSegCsurka2::~SemSegCsurka2() { // clean-up if ( classifier != NULL ) delete classifier; if( vclassifier !=NULL) delete vclassifier; if ( seg != NULL ) delete seg; if ( g != NULL ) delete g; } void SemSegCsurka2::normalize(Examples &ex) { assert(ex.size() > 0); if(vecmin.size() == 0) { for(int j = 0; j < (int)ex[0].second.vec->size(); j++) { double maxv = -numeric_limits::max(); double minv = numeric_limits::max(); for(int i = 0; i < (int)ex.size(); i++) { maxv = std::max(maxv,(*ex[i].second.vec)[j]); minv = std::min(minv,(*ex[i].second.vec)[j]); } vecmin.push_back(minv); vecmax.push_back(maxv); } } for(int i = 0; i < (int)ex.size(); i++) { for(int j = 0; j < (int)ex[i].second.vec->size(); j++) { (*ex[i].second.vec)[j] = ((*ex[i].second.vec)[j]-vecmin[j])/(vecmax[j]-vecmin[j]); } } return; } void SemSegCsurka2::convertLowToHigh ( Examples &ex, double reduce ) { cout << "converting low-level features to high-level features" << endl; if ( reduce >= 1.0 ) { for ( int i = 0; i < ( int ) ex.size(); i++ ) { SparseVector *f = new SparseVector(); if ( usekmeans ) k->getDist ( *ex[i].second.vec, *f, kmeansfeat, kmeanshard ); else { if ( usefisher ) g->getFisher ( *ex[i].second.vec, *f ); else g->getProbs ( *ex[i].second.vec, *f ); } delete ex[i].second.vec; ex[i].second.vec = NULL; ex[i].second.svec = f; } } else { srand ( time ( NULL ) ); vector del; cout << "Example size old " << ex.size() << endl; for ( int i = 0; i < ( int ) ex.size(); i++ ) { double rval = ( double ) rand() / ( double ) RAND_MAX; if ( rval < reduce ) { SparseVector *f = new SparseVector(); if ( usekmeans ) k->getDist ( *ex[i].second.vec, *f, kmeansfeat, kmeanshard ); else { if ( usefisher ) g->getFisher ( *ex[i].second.vec, *f ); else g->getProbs ( *ex[i].second.vec, *f ); } delete ex[i].second.vec; ex[i].second.vec = NULL; ex[i].second.svec = f; } else { del.push_back ( i ); } } for ( int i = ( int ) del.size() - 1; i >= 0; i-- ) { ex.erase ( ex.begin() +del[i] ); } cerr << "Example size new " << ex.size() << endl; } cerr << "converting low-level features to high-level features finished" << endl; } void SemSegCsurka2::smoothHL ( Examples ex ) { if ( !smoothhl ) return; assert ( ex.size() > 1 ); long long int minx = numeric_limits::max(); long long int miny = numeric_limits::max(); long long int maxx = -numeric_limits::max(); long long int maxy = -numeric_limits::max(); long long int distx = numeric_limits::max(); long long int disty = numeric_limits::max(); set scales; for ( int i = 0; i < (int)ex.size(); i++ ) { scales.insert ( ex[i].second.scale ); } map scalepos; int it = 0; for ( set::const_iterator iter = scales.begin(); iter != scales.end(); ++iter, ++it ) { scalepos.insert(make_pair(*iter, it)); } for ( int i = 0; i < (int)ex.size(); i++ ) { if ( minx < numeric_limits::max() && ex[i].second.x - minx > 0 ) distx = std::min ( distx, ex[i].second.x - minx ); if ( miny < numeric_limits::max() && ex[i].second.y - miny > 0 ) disty = std::min ( disty, ex[i].second.y - miny ); minx = std::min ( ex[i].second.x, minx ); maxx = std::max ( ex[i].second.x, maxx ); miny = std::min ( ex[i].second.y, miny ); maxy = std::max ( ex[i].second.y, maxy ); } distx = abs ( distx ); int xsize = ( maxx - minx ) /distx +1; int ysize = ( maxy - miny ) /disty +1; double valx = ( ( double ) xsize-1 ) / ( double ) ( maxx - minx ); double valy = ( ( double ) ysize-1 ) / ( double ) ( maxy - miny ); //double sigma = smoothfactor; double sigma = std::max(xsize,ysize) * smoothfactor; //double sigma = 0.2; cout << "sigma1: " << sigma << endl; vector imgv; vector gaussImgv; for(int i = 0; i < (int)scalepos.size(); i++) { NICE::FloatImage img( xsize, ysize); NICE::FloatImage gaussImg( xsize, ysize); imgv.push_back(img); gaussImgv.push_back(gaussImg); } for ( int d = 0; d < ex[0].second.svec->getDim(); d++ ) { //TODO: max und min dynamisches bestimmen for(int i = 0; i < (int)scalepos.size(); i++) { imgv[i].set(0.0); gaussImgv[i].set(0.0); } for ( int i = 0; i < (int)ex.size(); i++ ) { int xpos = ( ex[i].second.x - minx ) *valx; int ypos = ( ex[i].second.y - miny ) *valy; double val = ex[i].second.svec->get ( d ); // refactor-nice.pl: check this substitution // old: PutValD ( imgv[scalepos[ex[i].second.scale]],xpos,ypos,val); imgv[scalepos[ex[i].second.scale]].setPixel(xpos,ypos,val); } /* for(int y = 0; y < ysize; y++) { for(int x = 0; x < xsize; x++) { // refactor-nice.pl: check this substitution // old: double val = GetValD(img,x,y); double val = img.getPixel(x,y); double c = 0.0; if(val == 0.0) { if(x > 0) { // refactor-nice.pl: check this substitution // old: val+=GetValD(img,x-1,y); val+=img.getPixel(x-1,y); c+=1.0; } if(y > 0) { // refactor-nice.pl: check this substitution // old: val+=GetValD(img,x,y-1); val+=img.getPixel(x,y-1); c+=1.0; } if(x < xsize-1) { // refactor-nice.pl: check this substitution // old: val+=GetValD(img,x+1,y); val+=img.getPixel(x+1,y); c+=1.0; } if(y < ysize-1) { // refactor-nice.pl: check this substitution // old: val+=GetValD(img,x,y+1); val+=img.getPixel(x,y+1); c+=1.0; } // refactor-nice.pl: check this substitution // old: PutValD(img,x,y,val/c); img.setPixel(x,y,val/c); } } }*/ for(int i = 0; i < (int)imgv.size(); i++) FourierLibrary::gaussFilterD ( imgv[i], gaussImgv[i], sigma ); for ( int i = 0; i < (int)ex.size(); i++ ) { int xpos = ( ex[i].second.x - minx ) *valx; int ypos = ( ex[i].second.y - miny ) *valy; // refactor-nice.pl: check this substitution // old: double val = GetValD ( gaussImgv[scalepos[ex[i].second.scale]], xpos, ypos ); double val = gaussImgv[scalepos[ex[i].second.scale]].getPixel(xpos,ypos); if ( fabs ( val ) < 1e-7 ) { if ( ex[i].second.svec->get ( d ) != 0.0 ) { ex[i].second.svec->erase ( d ); } } else { ( *ex[i].second.svec ) [d] = val; } } } } void SemSegCsurka2::initializePCA ( Examples &ex ) { #ifdef DEBUG cerr << "start computing pca" << endl; #endif std::string filename = cache + "/pca"; FILE *value; value = fopen ( filename.c_str(),"r" ); if ( value==NULL || calcpca ) { srand ( time ( NULL ) ); int featsize = ( int ) ex.size(); int maxfeatures = dim*10; int olddim = ex[0].second.vec->size(); maxfeatures = std::min ( maxfeatures, featsize ); NICE::Matrix features ( maxfeatures, olddim ); for ( int i = 0; i < maxfeatures; i++ ) { int k = rand() % featsize; int vsize = (int)ex[k].second.vec->size(); for(int j = 0; j < vsize; j++) { features(i,j) = (*( ex[k].second.vec))[j]; } } pca.calculateBasis ( features, dim, 1 ); if ( save_cache ) pca.save ( filename ); } else { cout << "readpca: " << filename << endl; pca.read ( filename ); cout << "end" << endl; } #ifdef DEBUG cerr << "finished computing pca" << endl; #endif } void SemSegCsurka2::doPCA ( Examples &ex ) { cout << "converting features using pca starts" << endl; std::string savedir = cname = conf->gS ( "cache", "root", "/dev/null/" ); std::string shortf = ex.filename; if ( string::npos != ex.filename.rfind ( "/" ) ) shortf = ex.filename.substr ( ex.filename.rfind ( "/" ) ); std::string filename = savedir+"/pcasave/"+shortf; std::string syscall = "mkdir "+savedir+"/pcasave"; system ( syscall.c_str() ); cout << "filename: " << filename << endl; if ( !FileMgt::fileExists(filename) || calcpca ) { ofstream ofStream; //Opens the file binary ofStream.open ( filename.c_str(),fstream::out | fstream::binary ); for ( int k = 0; k < ( int ) ex.size(); k++ ) { NICE::Vector tmp = pca.getFeatureVector ( * ( ex[k].second.vec ), true ); delete ex[k].second.vec; for ( int d = 0; d < (int)tmp.size(); d++ ) ofStream.write ( ( char* ) &tmp[d], sizeof ( double ) ); ex[k].second.vec = new NICE::Vector ( tmp ); } ofStream.close(); cout << endl; } else { ifstream ifStream; ifStream.open ( filename.c_str(),std::fstream::in | std::fstream::binary ); for ( int k = 0; k < ( int ) ex.size(); k++ ) { NICE::Vector tmp = NICE::Vector ( dim ); delete ex[k].second.vec; for ( int d = 0; d < dim; d++ ) ifStream.read ( ( char* ) &tmp[d], sizeof ( double ) ); ex[k].second.vec = new NICE::Vector ( tmp ); } ifStream.close(); } cout << "converting features using pca finished" << endl; } void SemSegCsurka2::train ( const MultiDataset *md ) { /*die einzelnen Trainingsschritte 1. auf allen Trainingsbilder SIFT Merkmale an den Gitterpunkten bei allen Auflösungen bestimmen 2. PCA anwenden 3. aus diesen ein GMM erstellen 4. für jedes SIFT-Merkmal einen Vektor erstellen, der an der Stelle i die Wahrscheinlichkeit enthällt zur Verteilung i des GMM, Zur Zeit mit BoV-Alternative durch Moosman06 erledigt 5. diese Vektoren in einem diskriminitativen Klassifikator ( z.B. SLR oder Randomized Forests) zusammen mit ihrer Klassenzugehörigkeit anlernen */ #ifdef DEBUG cerr << "SemSegCsurka2:: training starts" << endl; #endif Examples examples; examples.filename = "training"; // the used features LocalFeatureRepresentation *cSIFT = new LFColorSande ( conf, "LFColorSandeTrain" ); // write the features to a file, if there isn't any to read LocalFeatureRepresentation *writeFeats = new LFWriteCache ( conf, cSIFT ); // read the features from a file LocalFeatureRepresentation *getFeats = new LFReadCache ( conf, writeFeats,-1 ); cout << 4 << endl; // additional Colorfeatures LFColorWeijer lcw(conf); int lfdimension = -1; const LabeledSet train = * ( *md ) ["train"]; const LabeledSet *trainp = &train; //////////////////////// // Merkmale berechnen // //////////////////////// set forbidden_classes; std::string forbidden_classes_s = conf->gS ( "analysis", "donttrain", "" ); if ( forbidden_classes_s == "" ) { forbidden_classes_s = conf->gS ( "analysis", "forbidden_classes", "" ); } cn.getSelection ( forbidden_classes_s, forbidden_classes ); cerr << "forbidden: " << forbidden_classes_s << endl; ProgressBar pb ( "Local Feature Extraction" ); pb.show(); int imgnb = 0; #if 0 LOOP_ALL_S ( *trainp ) { //EACH_S(classno, currentFile); EACH_INFO ( classno,info ); pb.update ( trainp->count() ); NICE::Image img; std::string currentFile = info.img(); CachedExample *ce = new CachedExample ( currentFile ); const LocalizationResult *locResult = info.localization(); if ( locResult->size() <= 0 ) { fprintf ( stderr, "WARNING: NO ground truth polygons found for %s !\n", currentFile.c_str() ); continue; } fprintf ( stderr, "SemSegCsurka2: Collecting pixel examples from localization info: %s\n", currentFile.c_str() ); int xsize, ysize; ce->getImageSize ( xsize, ysize ); NICE::Image pixelLabels (xsize, ysize); pixelLabels.set(0); locResult->calcLabeledImage ( pixelLabels, ( *classNames ).getBackgroundClass() ); try { img = Preprocess::ReadImgAdv ( currentFile.c_str() ); } catch (Exception) { cerr << "SemSegCsurka2: error opening image file <" << currentFile << ">" << endl; continue; } Globals::setCurrentImgFN ( currentFile ); VVector features; VVector cfeatures; VVector positions; NICE::ColorImage cimg(currentFile); getFeats->extractFeatures ( img, features, positions ); if(usecolorfeats) lcw.getDescriptors(cimg, cfeatures, positions); int j = 0; for ( VVector::const_iterator i = features.begin(); i != features.end(); i++,j++ ) { const NICE::Vector & x = *i; classno = pixelLabels.getPixel(( int )positions[j][0], ( int )positions[j][1] ); if ( forbidden_classes.find ( classno ) != forbidden_classes.end() ) continue; if ( lfdimension < 0 ) lfdimension = ( int ) x.size(); else assert ( lfdimension == ( int ) x.size() ); NICE::Vector *v = new NICE::Vector ( x ); if(usecolorfeats && !usepca) v->append(cfeatures[j]); Example example ( v ); example.position = imgnb; examples.push_back ( pair ( classno, example ) ); } features.clear(); positions.clear(); delete ce; imgnb++; } pb.hide(); #endif examples.clear(); readex("/home/staff/froehlich/fernerkundung/irene/sattrain.feats", examples); lfdimension = (int)examples[0].second.vec->size(); ////////////////// // PCA anwenden // ////////////////// if ( usepca ) { if ( !read_cache ) { initializePCA ( examples ); } doPCA ( examples ); lfdimension = dim; } ///////////////////////////////////////////////////// // Low-Level Features in High-Level transformieren // ///////////////////////////////////////////////////// int hlfdimension = lfdimension; if(norm) normalize(examples); if ( usegmm ) { if(!usepca && !norm) normalize(examples); g = new GMM ( conf,gaussians ); if ( dogmm || !g->loadData ( cache+"/gmm" ) ) { g->computeMixture ( examples ); if ( save_cache ) g->saveData ( cache+"/gmm" ); } hlfdimension = gaussians; if ( usefisher ) hlfdimension = gaussians*2*dim; } if ( usekmeans ) { if(!usepca || norm) normalize(examples); k = new KMeansOnline ( gaussians ); k->cluster ( examples ); hlfdimension = gaussians; } if ( usekmeans || usegmm ) { examples.clear(); pb.reset("Local Feature Extraction"); lfdimension = -1; pb.update ( trainp->count() ); LOOP_ALL_S ( *trainp ) { EACH_INFO ( classno,info ); pb.update ( trainp->count() ); NICE::Image img; std::string currentFile = info.img(); CachedExample *ce = new CachedExample ( currentFile ); const LocalizationResult *locResult = info.localization(); if ( locResult->size() <= 0 ) { fprintf ( stderr, "WARNING: NO ground truth polygons found for %s !\n", currentFile.c_str() ); continue; } fprintf ( stderr, "SemSegCsurka2: Collecting pixel examples from localization info: %s\n", currentFile.c_str() ); int xsize, ysize; ce->getImageSize ( xsize, ysize ); NICE::Image pixelLabels (xsize, ysize); pixelLabels.set(0); locResult->calcLabeledImage ( pixelLabels, ( *classNames ).getBackgroundClass() ); try{ img = Preprocess::ReadImgAdv ( currentFile.c_str() ); } catch (Exception){ cerr << "SemSegCsurka2: error opening image file <" << currentFile << ">" << endl; continue; } Globals::setCurrentImgFN ( currentFile ); VVector features; VVector cfeatures; VVector positions; NICE::ColorImage cimg(currentFile); getFeats->extractFeatures ( img, features, positions ); if(usecolorfeats) lcw.getDescriptors(cimg, cfeatures, positions); int j = 0; Examples tmpex; for ( VVector::const_iterator i = features.begin(); i != features.end(); i++,j++ ) { const NICE::Vector & x = *i; classno = pixelLabels.getPixel(( int )positions[j][0], ( int )positions[j][1] ); if ( forbidden_classes.find ( classno ) != forbidden_classes.end() ) continue; if ( lfdimension < 0 ) lfdimension = ( int ) x.size(); else assert ( lfdimension == ( int ) x.size() ); NICE::Vector *v = new NICE::Vector ( x ); if(usecolorfeats) v->append(cfeatures[j]); Example example ( v ); example.position = imgnb; example.x = ( int ) positions[j][0]; example.y = ( int )positions[j][1]; example.scale = positions[j][2]; tmpex.push_back ( pair ( classno, example ) ); } tmpex.filename = currentFile; if ( usepca ) { doPCA ( tmpex ); } convertLowToHigh ( tmpex, anteil ); smoothHL ( tmpex ); for ( int i = 0; i < (int)tmpex.size(); i++ ) { examples.push_back ( pair ( tmpex[i].first, tmpex[i].second ) ); } tmpex.clear(); features.clear(); positions.clear(); delete ce; imgnb++; } pb.hide(); } //////////////////////////// // Klassifikator anlernen // //////////////////////////// FeaturePool fp; Feature *f; if ( usegmm || usekmeans ) f = new SparseVectorFeature ( hlfdimension ); else f = new VectorFeature ( hlfdimension ); f->explode ( fp ); delete f; if(usecolorfeats && !( usekmeans || usegmm )) { int dimension = hlfdimension+11; for ( int i = hlfdimension ; i < dimension ; i++ ) { VectorFeature *f = new VectorFeature ( dimension ); f->feature_index = i; fp.addFeature(f, 1.0 / dimension); } } /* cout << "train classifier" << endl; fp.store(cout); getchar(); for(int z = 0; z < examples.size(); z++) { cout << "examples.size() " << examples.size() << endl; cout << "class: " << examples[z].first << endl; cout << *examples[z].second.vec << endl; getchar(); }*/ if(classifier != NULL) classifier->train ( fp, examples ); else { LabeledSetVector lvec; convertExamplesToLSet(examples, lvec); vclassifier->teach(lvec); if(usegmm) convertLSetToSparseExamples(examples, lvec); else convertLSetToExamples(examples, lvec); vclassifier->finishTeaching(); } fp.destroy(); if ( save_cache ) { if(classifier != NULL) classifier->save ( cache+"/fpcrf.data" ); else vclassifier->save ( cache+"/veccl.data" ); } //////////// //clean up// //////////// for ( int i = 0; i < ( int ) examples.size(); i++ ) { examples[i].second.clean(); } examples.clear(); delete cSIFT; delete writeFeats; delete getFeats; trainpostprocess ( md ); cerr << "SemSeg training finished" << endl; } void SemSegCsurka2::trainpostprocess ( const MultiDataset *md ) { cout<< "start postprocess" << endl; //////////////////////////// // Postprocess trainieren // //////////////////////////// const LabeledSet train = * ( *md ) ["train"]; const LabeledSet *trainp = &train; if ( userellocprior || srg != NULL || gcopt !=NULL ) { if ( userellocprior ) relloc->setClassNo ( cn.numClasses() ); if ( gcopt !=NULL ) { gcopt->setClassNo ( cn.numClasses() ); } ProgressBar pb ( "learn relative location prior maps" ); pb.show(); LOOP_ALL_S ( *trainp ) // für alle Bilder den ersten Klassifikationsschritt durchführen um den zweiten Klassifikator anzutrainieren { EACH_INFO ( classno,info ); pb.update ( trainp->count() ); NICE::Image img; std::string currentFile = info.img(); Globals::setCurrentImgFN ( currentFile ); CachedExample *ce = new CachedExample ( currentFile ); const LocalizationResult *locResult = info.localization(); if ( locResult->size() <= 0 ) { fprintf ( stderr, "WARNING: NO ground truth polygons found for %s !\n", currentFile.c_str() ); continue; } fprintf ( stderr, "SemSegCsurka2: Collecting pixel examples from localization info: %s\n", currentFile.c_str() ); int xsize, ysize; ce->getImageSize ( xsize, ysize ); NICE::Image pixelLabels (xsize, ysize); pixelLabels.set(0); locResult->calcLabeledImage ( pixelLabels, ( *classNames ).getBackgroundClass() ); try{ img = Preprocess::ReadImgAdv ( currentFile.c_str() ); } catch(Exception) { cerr << "SemSegCsurka2: error opening image file <" << currentFile << ">" << endl; continue; } //Regionen ermitteln NICE::Matrix mask; int regionsize = seg->segRegions ( img,mask ); Examples regions; vector > hists; for ( int i = 0; i < regionsize; i++ ) { Example tmp; regions.push_back ( pair ( 0, tmp ) ); vector hist ( cn.numClasses(), 0 ); hists.push_back ( hist ); } for ( int x = 0; x < xsize; x++ ) { for ( int y = 0; y < ysize; y++ ) { int numb = mask(x,y); regions[numb].second.x += x; regions[numb].second.y += y; regions[numb].second.weight += 1.0; hists[numb][pixelLabels.getPixel(x,y)]++; } } for ( int i = 0; i < regionsize; i++ ) { regions[i].second.x /= ( int ) regions[i].second.weight; regions[i].second.y /= ( int ) regions[i].second.weight; int maxval = -numeric_limits::max(); int maxpos = -1; int secondpos = -1; for ( int k = 0; k < ( int ) hists[i].size(); k++ ) { if ( maxval trainPriorsMaps ( regions, xsize, ysize ); if ( srg != NULL ) srg->trainShape ( regions, mask ); if ( gcopt !=NULL ) gcopt->trainImage ( regions, mask ); delete ce; } pb.hide(); if ( userellocprior ) relloc->finishPriorsMaps ( cn ); if ( srg != NULL ) srg->finishShape ( cn ); if ( gcopt != NULL ) gcopt->finishPP ( cn ); } if ( userellocprior ) { ProgressBar pb ( "learn relative location classifier" ); pb.show(); int nummer = 0; LOOP_ALL_S ( *trainp ) // für alle Bilder den ersten Klassifikationsschritt durchführen um den zweiten Klassifikator anzutrainieren { //EACH_S(classno, currentFile); EACH_INFO ( classno,info ); nummer++; pb.update ( trainp->count() ); NICE::Image img; std::string currentFile = info.img(); CachedExample *ce = new CachedExample ( currentFile ); const LocalizationResult *locResult = info.localization(); if ( locResult->size() <= 0 ) { fprintf ( stderr, "WARNING: NO ground truth polygons found for %s !\n", currentFile.c_str() ); continue; } fprintf ( stderr, "SemSegCsurka2: Collecting pixel examples from localization info: %s\n", currentFile.c_str() ); int xsize, ysize; ce->getImageSize ( xsize, ysize ); NICE::Image pixelLabels (xsize, ysize); pixelLabels.set(0); locResult->calcLabeledImage ( pixelLabels, ( *classNames ).getBackgroundClass() ); try{ img = Preprocess::ReadImgAdv ( currentFile.c_str() ); } catch(Exception) { cerr << "SemSegCsurka2: error opening image file <" << currentFile << ">" << endl; continue; } Globals::setCurrentImgFN ( currentFile ); NICE::Image segresult; GenericImage probabilities ( xsize,ysize,classno,true ); Examples regions; NICE::Matrix mask; if ( savesteps ) { std::ostringstream s1; s1 << cache << "/rlpsave/" << nummer; std::string filename = s1.str(); s1 << ".probs"; std::string fn2 = s1.str(); FILE *file; file = fopen ( filename.c_str(),"r" ); if ( file==NULL ) { //berechnen classifyregions ( ce, segresult, probabilities, regions, mask ); //schreiben ofstream fout ( filename.c_str(), ios::app ); fout << regions.size() << endl; for ( int i = 0; i < ( int ) regions.size(); i++ ) { regions[i].second.store ( fout ); fout << regions[i].first << endl; } fout.close(); probabilities.store ( fn2 ); } else { //lesen ifstream fin ( filename.c_str() ); int size; fin >> size; for ( int i = 0; i < size; i++ ) { Example ex; ex.restore ( fin ); int tmp; fin >> tmp; regions.push_back ( pair ( tmp, ex ) ); } fin.close(); probabilities.restore ( fn2 ); } } else { classifyregions ( ce, segresult, probabilities, regions, mask ); } relloc->trainClassifier ( regions, probabilities ); delete ce; } relloc->finishClassifier(); pb.hide(); relloc->save ( cache+"/rlp" ); } cout << "finished postprocess" << endl; } void SemSegCsurka2::classifyregions ( CachedExample *ce, NICE::Image & segresult, GenericImage & probabilities, Examples &Regionen, NICE::Matrix & mask ) { /* die einzelnen Testschritte: 1.x auf dem Testbild alle SIFT Merkmale an den Gitterpunkten bei allen Auflösungen bestimmen 2.x für jedes SIFT-Merkmal einen Vektor erstellen, der an der Stelle i die Wahrscheinlichkeit enthällt zur Verteilung i des GMM 3.x diese Vektoren klassifizieren, so dass für jede Klasse die Wahrscheinlichkeit gespeichert wird 4.x für jeden Pixel die Wahrscheinlichkeiten mitteln aus allen Patches, in denen der Pixel vorkommt 5.x das Originalbild in homogene Bereiche segmentieren 6.x die homogenen Bereiche bekommen die gemittelten Wahrscheinlichkeiten ihrer Pixel 7. (einzelne Klassen mit einem globalen Klassifikator ausschließen) 8.x jeder Pixel bekommt die Klasse seiner Region zugeordnet */ int xsize, ysize; ce->getImageSize ( xsize, ysize ); probabilities.reInit ( xsize, ysize, classNames->getMaxClassno() +1, true/*allocMem*/ ); segresult.resize(xsize, ysize); Examples pce; // the features to use LocalFeatureRepresentation *cSIFT = new LFColorSande ( conf, "LFColorSandeTest" ); // write the features to a file, if there isn't any to read LocalFeatureRepresentation *writeFeats = new LFWriteCache ( conf, cSIFT ); // read the features from a file LocalFeatureRepresentation *getFeats = new LFReadCache ( conf, writeFeats,-1 ); // additional Colorfeatures LFColorWeijer lcw(conf); NICE::Image img; std::string currentFile = Globals::getCurrentImgFN(); try { img = Preprocess::ReadImgAdv ( currentFile.c_str() ); } catch(Exception) { cerr << "SemSegCsurka2: error opening image file <" << currentFile << ">" << endl; } VVector features; VVector cfeatures; VVector positions; NICE::ColorImage cimg(currentFile); //getFeats->extractFeatures ( img, features, positions ); readFeats(features,positions,"/home/staff/froehlich/fernerkundung/irene/sattest.feats","/home/staff/froehlich/fernerkundung/irene/sattest.coords"); if(usecolorfeats) lcw.getDescriptors(cimg, cfeatures, positions); set scales; int j = 0; int lfdimension = -1; for ( VVector::const_iterator i = features.begin(); i != features.end(); i++,j++ ) { const NICE::Vector & x = *i; if ( lfdimension < 0 ) lfdimension = ( int ) x.size(); else assert ( lfdimension == ( int ) x.size() ); NICE::Vector *v = new NICE::Vector ( x ); if(usecolorfeats) v->append(cfeatures[j]); Example tmp = Example ( v ); tmp.x = ( int )positions[j][0]; tmp.y = ( int ) positions[j][1]; tmp.width = ( int ) ( 16.0*positions[j][2] ); tmp.height = tmp.width; tmp.scale = positions[j][2]; scales.insert ( positions[j][2] ); pce.push_back ( pair ( 0, tmp ) ); } ////////////////// // PCA anwenden // ////////////////// pce.filename = currentFile; if ( usepca ) { doPCA ( pce ); lfdimension = dim; } ////////////////// // BoV anwenden // ////////////////// if(norm) normalize(pce); if ( usegmm || usekmeans ) { if(!usepca && !norm) normalize(pce); convertLowToHigh ( pce ); smoothHL ( pce ); lfdimension = gaussians; } ///////////////////////////////////////// // Wahrscheinlichkeitskarten erstellen // ///////////////////////////////////////// int klassen = probabilities.numChannels; GenericImage preMap ( xsize,ysize,klassen*scales.size(),true ); long int offset = 0; // initialisieren for ( int y = 0 ; y < ysize ; y++ ) for ( int x = 0 ; x < xsize ; x++,offset++ ) { // alles zum Hintergrund machen segresult.setPixel(x,y,0); // Die Wahrscheinlichkeitsmaps auf 0 initialisieren for ( int i = 0 ; i < ( int ) probabilities.numChannels; i++ ) { probabilities.data[i][offset] = 0.0; } for ( int j = 0; j < ( int ) preMap.numChannels; j++ ) { preMap.data[j][offset]=0.0; } } // Die Wahrscheinlichkeitsmaps mit den einzelnen Wahrscheinlichkeiten je Skalierung füllen int scalesize = scales.size(); // Globale Häufigkeiten akkumulieren FullVector fV ( ( int ) probabilities.numChannels ); for ( int i = 0; i < fV.size(); i++ ) fV[i] = 0.0; if(classifier != NULL) { #pragma omp parallel for for ( int s = 0; s < scalesize; s++ ) { #pragma omp parallel for for ( int i = s; i < ( int ) pce.size(); i+=scalesize ) { ClassificationResult r = classifier->classify ( pce[i].second ); for ( int j = 0 ; j < ( int ) probabilities.numChannels; j++ ) { fV[j] += r.scores[j]; preMap.set ( pce[i].second.x,pce[i].second.y,r.scores[j],j+s*klassen ); } } } } else { #pragma omp parallel for for ( int s = 0; s < scalesize; s++ ) { #pragma omp parallel for for ( int i = s; i < ( int ) pce.size(); i+=scalesize ) { ClassificationResult r = vclassifier->classify ( *(pce[i].second.vec) ); for ( int j = 0 ; j < ( int ) probabilities.numChannels; j++ ) { fV[j] += r.scores[j]; preMap.set ( pce[i].second.x,pce[i].second.y,r.scores[j],j+s*klassen ); } } } } vector scalesVec; for ( set::const_iterator iter = scales.begin(); iter != scales.end(); ++iter ) { scalesVec.push_back ( *iter ); } // Gaußfiltern for ( int s = 0; s < scalesize; s++ ) { double sigma = sigmaweight*16.0*scalesVec[s]; cerr << "sigma: " << sigma << endl; #pragma omp parallel for for ( int i = 0; i < klassen; i++ ) { int pos = i+s*klassen; double maxval = preMap.data[pos][0]; double minval = preMap.data[pos][0]; for ( int z = 1; z < xsize*ysize; z++ ) { maxval = std::max ( maxval, preMap.data[pos][z] ); minval = std::min ( minval, preMap.data[pos][z] ); } NICE::FloatImage dblImg( xsize, ysize); NICE::FloatImage gaussImg( xsize, ysize); long int offset2 = 0; for ( int y = 0; y < ysize; y++ ) { for ( int x = 0; x < xsize; x++, offset2++ ) { dblImg.setPixel(x,y,preMap.data[pos][offset2]); } } FourierLibrary::gaussFilterD ( dblImg, gaussImg, sigma ); offset2 = 0; for ( int y = 0; y < ysize; y++ ) { for ( int x = 0; x < xsize; x++, offset2++ ) { preMap.data[pos][offset2]=gaussImg.getPixel(x,y); } } } } // Zusammenfassen und auswerten #pragma omp parallel for for ( int x = 0; x < xsize; x++ ) { for ( int y = 0; y < ysize; y++ ) { for ( int j = 0 ; j < ( int ) probabilities.numChannels; j++ ) { double prob = 0.0; for ( int s = 0; s < ( int ) scalesize; s++ ) { prob+=preMap.get ( x,y,j+s*klassen ); } double val = prob / ( double ) ( scalesize ); probabilities.set ( x,y,val, j ); } } } #undef VISSEMSEG #ifdef VISSEMSEG // showImage(img); for ( int j = 0 ; j < ( int ) probabilities.numChannels; j++ ) { cout << "klasse: " << j << endl;//" " << cn.text ( j ) << endl; NICE::Matrix tmp ( probabilities.ysize, probabilities.xsize ); double maxval = 0.0; for ( int y = 0; y < probabilities.ysize; y++ ) for ( int x = 0; x < probabilities.xsize; x++ ) { double val = probabilities.get ( x,y,j ); tmp(y, x) = val; maxval = std::max ( val, maxval ); } NICE::ColorImage imgrgb (probabilities.xsize, probabilities.ysize); ICETools::convertToRGB ( tmp, imgrgb ); cout << "maxval = " << maxval << " for class " << j << endl; //cn.text ( j ) << endl; //Show ( ON, imgrgb, cn.text ( j ) ); showImage(imgrgb, "Ergebnis"); //imgrgb.Write ( "tmp.ppm" ); //getchar(); } #endif if ( useregions ) { if ( bestclasses > 0 ) { PSSImageLevelPrior pss ( 0, bestclasses, 0.2 ); pss.setPrior ( fV ); pss.postprocess ( segresult, probabilities ); } //Regionen ermitteln int regionsize = seg->segRegions ( img, mask); Regionen.clear(); vector > regionprob; // Wahrscheinlichkeiten für jede Region initialisieren for ( int i = 0; i < regionsize; i++ ) { vector tmp; for ( int j = 0; j < ( int ) probabilities.numChannels; j++ ) { tmp.push_back ( 0.0 ); } regionprob.push_back ( tmp ); Regionen.push_back ( pair ( 0, Example() ) ); } // Wahrscheinlichkeiten für Regionen bestimmen for ( int x = 0; x < xsize; x++ ) { for ( int y = 0; y < ysize; y++ ) { for ( int j = 0 ; j < ( int ) probabilities.numChannels; j++ ) { double val = probabilities.get ( x,y,j ); int pos = mask(x,y); Regionen[pos].second.weight+=1.0; Regionen[pos].second.x += x; Regionen[pos].second.y += y; regionprob[pos][j] += val; } } } /* cout << "regions: " << regionsize << endl; cout << "outfeats: " << endl; for(int j = 0; j < regionprob.size(); j++) { for(int i = 0; i < regionprob[j].size(); i++) { cout << regionprob[j][i] << " "; } cout << endl; } cout << endl; getchar();*/ // beste Wahrscheinlichkeit je Region wählen for ( int i = 0; i < regionsize; i++ ) { Regionen[i].second.x /= ( int ) Regionen[i].second.weight; Regionen[i].second.y /= ( int ) Regionen[i].second.weight; double maxval = 0.0; int maxpos = 0; for ( int j = 0 ; j < ( int ) regionprob[i].size(); j++ ) { regionprob[i][j] /= Regionen[i].second.weight; if ( maxval < regionprob[i][j] ) { maxval = regionprob[i][j]; maxpos = j; } probabilities.set (Regionen[i].second.x,Regionen[i].second.y,regionprob[i][j], j ); } Regionen[i].first = maxpos; } // Pixel jeder Region labeln for ( int y = 0; y < (int)mask.cols(); y++ ) { for ( int x = 0; x < (int)mask.rows(); x++ ) { int pos = mask(x,y); segresult.setPixel(x,y,Regionen[pos].first); } } } else { PSSImageLevelPrior pss ( 1, 4, 0.2 ); pss.setPrior ( fV ); pss.postprocess ( segresult, probabilities ); } // Saubermachen: for ( int i = 0; i < ( int ) pce.size(); i++ ) { pce[i].second.clean(); } pce.clear(); delete getFeats; delete writeFeats; delete cSIFT; } void SemSegCsurka2::semanticseg ( CachedExample *ce, NICE::Image & segresult, GenericImage & probabilities ) { Examples regions; NICE::Matrix regionmask; classifyregions ( ce, segresult, probabilities, regions, regionmask ); if ( userellocprior || srg != NULL || gcopt !=NULL ) { if ( userellocprior ) relloc->postprocess ( regions, probabilities ); if ( srg != NULL ) srg->optimizeShape ( regions, regionmask, probabilities ); if ( gcopt != NULL ) gcopt->optimizeImage ( regions, regionmask, probabilities ); // Pixel jeder Region labeln for ( int y = 0; y < (int)regionmask.cols(); y++ ) { for ( int x = 0; x < (int)regionmask.rows(); x++ ) { int pos = regionmask(x,y); segresult.setPixel(x,y,regions[pos].first); } } } #ifndef NOVISUAL #undef VISSEMSEG #ifdef VISSEMSEG // showImage(img); for ( int j = 0 ; j < ( int ) probabilities.numChannels; j++ ) { cout << "klasse: " << j << " " << cn.text ( j ) << endl; NICE::Matrix tmp ( probabilities.ysize, probabilities.xsize ); double maxval = 0.0; for ( int y = 0; y < probabilities.ysize; y++ ) for ( int x = 0; x < probabilities.xsize; x++ ) { double val = probabilities.get ( x,y,j ); tmp(y, x) = val; maxval = std::max ( val, maxval ); } NICE::ColorImage imgrgb (probabilities.xsize, probabilities.ysize); ICETools::convertToRGB ( tmp, imgrgb ); cout << "maxval = " << maxval << " for class " << cn.text ( j ) << endl; Show ( ON, imgrgb, cn.text ( j ) ); imgrgb.Write ( "tmp.ppm" ); getchar(); } #endif #endif }