main.cpp — 10.5 KB
File contents
#include <CImg.h> #include <stdlib.h> #include <iostream> #include <map> #include <string> #include <fstream> #include <time.h> #define pow2(X) ((X)*(X)) using namespace cimg_library; int main(unsigned int argc, char **argv) { unsigned int exitCode(0); try{ //=====get commandline parameters ==== cimg_usage("Create background mask for scanned images"); cimg_help("Usage: setBGmask [OPTIONS] IMAGEFILE \nReport bugs to <jap441@psu.edu>.\n"); //set parameters double glimax = cimg_option("-txg",600,"Max intensity for green leaves"); double glimin = cimg_option("-tmg",150,"Min intensity for green leaves"); double glrgmax = cimg_option("-trg", 1.0,"Max red/green ratio for green leaves"); double plimax = cimg_option("-txp",600,"Max intensity for purple leaves"); double plimin = cimg_option("-tmp",200,"Min intensity for purple leaves"); double plgbmax = cimg_option("-tgbp",1.1,"Max green/blue ratio for purple leaves"); double resimin = cimg_option("-tri",360,"Min intensity for residue"); double resrmin = cimg_option("-trr",155,"Min red for residue"); double soilimax = cimg_option("-tsi",360,"Max intensity for soil"); double soilrmax = cimg_option("-tsr",155,"Max red for soil"); double bline = cimg_option("-bl",2,"Percentage range for border-line pixels "); //unsigned int denoise = cimg_option("-nbg",7,"Noise reduction size in pixels (large values maybe slow)"); bool show = cimg_option("-s",false,"Show image"); bool header = cimg_option("-header",true,"Include header in textfile"); bool textfile = cimg_option("-tf",false,"Data to textfile"); //create file names for output masks // the "X" is added onto the filenames of the masks so they can easily be deleted later w/o deleting the images or evaluation images std::string filename(argv[argc-1]); if (filename=="-h" || filename=="--help") filename=""; std::string ext=cimg_option("-ext",".jpg","Output extension"); std::string leafsfilename(filename.substr(0,filename.size()-4)+"_lfsX"+ext); std::string residuefilename(filename.substr(0,filename.size()-4)+"_resX"+ext); std::string soilfilename(filename.substr(0,filename.size()-4)+"_soilX"+ext); std::string blfilename(filename.substr(0,filename.size()-4)+"_xblX"+ext); std::string evaluationfilename(filename.substr(0,filename.size()-4)+"_eval"+ext); std::string textfilename(filename.substr(0,filename.size()-4)+"dat.txt"); bool verbose = cimg_option("-v",false,"Be verbose"); bool sverbose = cimg_option("-V",false,"Be super verbose"); if(sverbose) verbose=true; //instantiate image if(filename=="") return 0; if(verbose) std::cout<<"Processing image "<<filename<<"\n"; CImg<unsigned char> image(filename.c_str()); //===========Create Leaf Mask================== //includes both green and purple colored leaves //purple leaves would not be found if the threshold were made very small if(sverbose) std::cout<<"Creating leaf mask\n"; CImg<unsigned char> glmask,blmask; glmask.assign(image.dimx(),image.dimy(),1,1,0); // create the glmask image blmask.assign(image.dimx(),image.dimy(),1,1,0); // create the blmask image - borderline pixels unsigned int blcount(0); // borderline pixel counter unsigned int glcount(0); // leaf pixel counter unsigned int intensity(0); double glibl((glimax-glimin)*(bline/100)); // green leaf intensity borderline ((max-min)*%) double plibl((plimax-plimin)*(bline/100)); // purple leaf intensity borderline ((max-min)*%) double glrgbl(glrgmax*bline/100); //green leaf red:green borderline double plgbbl(plgbmax*bline/100); //purple leaf green:blue borderline double redgreenratio(0),greenblueratio(0); cimg_forXY(image,x,y) { intensity=image(x,y,0)+image(x,y,1)+image(x,y,2); // (x,y,0) refers to the red channel, (x,y,1) to the green, and (x,y,2) to the blue redgreenratio=(double)image(x,y,0)/((double)image(x,y,1)+0.1); greenblueratio=(double)image(x,y,1)/((double)image(x,y,2)+0.1); if((intensity<glimax && intensity>glimin && redgreenratio<glrgmax)|| (intensity<plimax && intensity>plimin && greenblueratio<plgbmax) ){ glmask(x,y,0)=255; ++glcount; // >>> count glmask pixels } // count borderline pixels for green leaves if((intensity<glimax+glibl && intensity>glimin-glibl && redgreenratio<glrgmax+glrgbl && redgreenratio>glrgmax-glrgbl) || //r:g border for green leaves (redgreenratio<glrgmax-glrgbl && //r:g right, test max and min bands ((intensity>glimax-glibl && intensity<glimax+glibl) || //max band (intensity>glimin-glibl && intensity<glimin+glibl))) ){ //min band blmask(x,y,0)=255; ++blcount; // count borderline pixels for green leaves } // count borderline pixels for purple leaves if((intensity<plimax+plibl && intensity>plimin-plibl && greenblueratio<plgbmax+plgbbl && greenblueratio>plgbmax-plgbbl) || //g:b border for purple leaves (greenblueratio<plgbmax-plgbbl && //g:b right, test max and min bands ((intensity>plimax-plibl && intensity<plimax+plibl) || //max band (intensity>plimin-plibl && intensity<plimin+plibl))) ){ //min band blmask(x,y,0)=255; ++blcount; // count borderline pixels for purple leaves } }; //============Create Residue Mask===================== CImg<unsigned char> resmask; if(sverbose) std::cout<<"Creating residue mask\n"; resmask.assign(image.dimx(),image.dimy(),1,1,0); unsigned int rescount(0); double resrbl(resrmin*bline/100); // residue red borderline double resibl(resimin*bline/100); // residue intensity borderline cimg_forXY(image,x,y) { if (glmask(x,y,0)!=255){ intensity=image(x,y,0)+image(x,y,1)+image(x,y,2); if(intensity>resimin && image(x,y,0)>resrmin) {//intensity rule true & red rule true resmask(x,y,0)=255; ++rescount; //increment residue counter }; // count borderline pixels if ((image(x,y,0)>resrmin-resrbl && image(x,y,0)<resrmin+resrbl && intensity>resimin-resibl) || // red borderline (intensity>resimin-resibl && intensity<resimin+resibl && image(x,y,0)>resrmin+resrbl)){ // intensity borderline blmask(x,y,0)=255; ++blcount; } //count borderline pixels }; }; //===========Create Soil Mask==================== //everything that is not leaves, ambiguous or residue CImg<unsigned char> soilmask; if(sverbose) std::cout<<"Creating soil mask\n"; soilmask.assign(image.dimx(),image.dimy(),1,1,0); unsigned int slcount(0); // soil pixel counter double soilrbl(soilrmax*bline/100); // soil red borderline double soilibl(soilimax*bline/100); // soil intensity borderline cimg_forXY(image,x,y) { if (glmask(x,y,0)!=255 && resmask(x,y,0)!=255){ intensity=image(x,y,0)+image(x,y,1)+image(x,y,2); if(intensity<soilimax && image(x,y,0)<soilrmax) {//intensity rule true & red rule true soilmask(x,y,0)=255; ++slcount; //increment residue counter }; // >>> count pixels near boundary if ((image(x,y,0)>soilrmax-soilrbl && image(x,y,0)<soilrmax+soilrbl && intensity<soilimax+soilibl) || // red borderline (intensity>soilimax-soilibl && intensity<soilimax+soilibl && image(x,y,0)<soilrmax-soilibl)){ // intensity borderline blmask(x,y,0)=255; ++blcount; } //count borderline pixels }; }; //===========Create Ambiguous Mask==================== //everything that is not leaves, residue, or soil CImg<unsigned char> ambmask; if(sverbose) std::cout<<"Creating ambiguous mask\n"; ambmask.assign(image.dimx(),image.dimy(),1,1,0); unsigned int ambcount(0); cimg_forXY(image,x,y) { if (glmask(x,y,0)!=255 && resmask(x,y,0)!=255 && soilmask(x,y,0)!=255){ ambmask(x,y,0)=255; ++ambcount; //increment ambiguous counter }; }; double totpix((double)glcount + (double)rescount + (double)slcount + (double)ambcount); double check(image.dimx()*image.dimy()); if(totpix!=check) std::cerr<<"Total number of classified pixels is different from total number of pixels in image. Classified="<<totpix<<" Image=" <<check<<std::endl; if(verbose)std::cout<<"Leaves = "<<(double)glcount/totpix<<" *100%\n"; if(verbose)std::cout<<"Residue = "<<(double)rescount/totpix<<" *100%\n"; if(verbose)std::cout<<"Soil = "<<(double)slcount/totpix<<" *100%\n"; if(verbose)std::cout<<"Ambiguous residue or soil = "<<(double)ambcount/totpix<<" *100%\n"; if(verbose)std::cout<<"Borderline pixels = "<<(double)blcount/totpix<<" *100%\n"; //===========Create Evaluation Image=============== CImg<unsigned char> imageCopy; imageCopy.assign(image); cimg_forXY(imageCopy,x,y) { if (glmask(x,y,0)==255){ imageCopy(x,y,0)/=2; // divide red and blue by 2 //imageCopy(x,y,1)=255; imageCopy(x,y,2)/=2; }; if(resmask(x,y,0)==255){ imageCopy(x,y,0)/=2; imageCopy(x,y,1)/=2; //divide red and green by 2 //imageCopy(x,y,2)=255; }; if(ambmask(x,y,0)==255){ imageCopy(x,y,0)=200; imageCopy(x,y,1)=150; imageCopy(x,y,2)=0; }; if(soilmask(x,y,0)==255){ //imageCopy(x,y,0)*=2; imageCopy(x,y,1)/=2; imageCopy(x,y,2)/=2; }; }; //===============Output============================ //textfile output if(textfile){ std::ofstream textfile; textfile.open(textfilename.c_str()); char del('\t'); //time time_t rawtime; time ( &rawtime ); struct tm * timeinfo(localtime ( &rawtime )); char date [80]; strftime (date,80,"%x",timeinfo); //header if(header) textfile << "Filename" << del << "Date" << del << "%Leaves" << del << "%Residue" << del << "%Soil" << del << "%Ambiguous" << del << "%Borderline" << del << "ClassifiedPixels" << del << "TotalPixels" << std::endl; textfile << filename.substr(0,filename.size()-4) << del << date << del << (double)glcount/totpix << del << (double)rescount/totpix << del << (double)slcount/totpix << del << (double)ambcount/totpix << del << (double)blcount/totpix << del << totpix << del << check << std::endl; }; //image output if(show){ //open displays showing images CImgDisplay main_disp(image,"Original"), mask_disp(glmask,"Leafs mask"), rmask_disp(resmask,"Residue mask"), smask_disp(soilmask,"Soil mask"), nmask_disp(imageCopy,"Evaluation mask"); while (!main_disp.is_closed) main_disp.wait(); }else{ //write mask images to file glmask.save(leafsfilename.c_str()); resmask.save(residuefilename.c_str()); soilmask.save(soilfilename.c_str()); blmask.save(blfilename.c_str()); imageCopy.save(evaluationfilename.c_str()); }; //============catch errors========================= } catch (std::exception& error){ std::cout << error.what() ; exitCode=1; }; return exitCode; }