Share

CIMG Code - Image Analysis Program

C++ source code icon main.cpp — C++ source code, 10 KB (10769 bytes)

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;
}