#ifndef RTS_ENVI_H #define RTS_ENVI_H #include #include #include #include /* This is a class for reading and writing ENVI binary files. This class will be updated as needed. What this class CAN currently do: *) Write band images to a BSQ file. *) Append band images to a BSQ file. */ //information from an ENVI header file //A good resource can be found here: http://www.exelisvis.com/docs/enviheaderfiles.html struct EnviHeader { std::string name; std::string description; unsigned int samples; //x-axis unsigned int lines; //y-axis unsigned int bands; //spectral axis unsigned int header_offset; //header offset for binary file (in bytes) std::string file_type; //should be "ENVI Standard" unsigned int data_type; //data representation; common value is 4 (32-bit float) enum interleaveType {BIP, BIL, BSQ}; //bip = Z,X,Y; bil = X,Z,Y; bsq = X,Y,Z interleaveType interleave; std::string sensor_type; //not really used enum endianType {endianLittle, endianBig}; endianType byte_order; //little = least significant bit first (most systems) double x_start, y_start; //coordinates of the upper-left corner of the image std::string wavelength_units; //stored wavelength units std::string z_plot_titles[2]; double pixel_size[2]; //pixel size along X and Y std::vector band_names; //name for each band in the image std::vector wavelength; //wavelength for each band EnviHeader() { name = ""; //specify default values for a new or empty ENVI file samples = 0; lines = 0; bands = 0; header_offset = 0; data_type = 4; interleave = BSQ; byte_order = endianLittle; x_start = y_start = 0; pixel_size[0] = pixel_size[1] = 1; //strings file_type = "ENVI Standard"; sensor_type = "Unknown"; wavelength_units = "Unknown"; z_plot_titles[0] = z_plot_titles[1] = "Unknown"; } std::string trim(std::string line) { //trims whitespace from the beginning and end of line int start_i, end_i; for(start_i=0; start_i < line.length(); start_i++) if(line[start_i] != 32) { break; } for(end_i = line.length()-1; end_i >= start_i; end_i--) if(line[end_i] != ' ') { break; } return line.substr(start_i, end_i - start_i+1); } std::string get_token(std::string line) { //returns a variable name; in this case we look for the '=' sign size_t i = line.find_first_of('='); std::string result; if(i != std::string::npos) result = trim(line.substr(0, i-1)); return result; } std::string get_data_str(std::string line) { size_t i = line.find_first_of('='); std::string result; if(i != std::string::npos) result = trim(line.substr(i+1)); else { std::cout<<"ENVI Header error - data not found for token: "< get_string_seq(std::string token, std::string sequence) { //this function returns a sequence of comma-delimited strings std::vector result; std::string entry; size_t i; do { i = sequence.find_first_of(','); entry = sequence.substr(0, i); sequence = sequence.substr(i+1); result.push_back(trim(entry)); }while(i != std::string::npos); return result; } std::vector get_double_seq(std::string token, std::string sequence) { //this function returns a sequence of comma-delimited strings std::vector result; std::string entry; size_t i; do { i = sequence.find_first_of(','); entry = sequence.substr(0, i); sequence = sequence.substr(i+1); result.push_back(atof(entry.c_str())); }while(i != std::string::npos); return result; } void load(std::string filename, std::string mode = "r") { name = filename; //open the header file std::ifstream file(name.c_str()); if(!file) { //if we are in read mode, throw an exception if(mode == "r") { std::cout<<"ENVI header file not found: "< pxsize = get_double_seq(token, string_sequence); pixel_size[0] = pxsize[0]; pixel_size[1] = pxsize[1]; } else if(token == "z plot titles") { std::string string_sequence = get_brace_str(token, line, file); std::vector titles = get_string_seq(token, string_sequence); z_plot_titles[0] = titles[0]; z_plot_titles[1] = titles[1]; } else if(token == "samples") samples = atoi(get_data_str(line).c_str()); else if(token == "lines") { lines = atoi(get_data_str(line).c_str()); std::cout<<"Number of lines loaded: "< 0) { outfile<<"band names = {"<0) return true; else return false; } public: EnviFile() { init(); } EnviFile(std::string filename, std::string file_mode = "r") { init(); open(filename, filename + ".hdr", file_mode); } void open(std::string file_name, std::string header_name, std::string file_mode = "r") { mode = file_mode; header.name = header_name; //lock the file if we are loading or appending if(mode == "r" || mode == "a" || mode == "r+" || mode == "a+") { //load the ENVI header - failure will cause an exit set_header(load_header(header_name, file_mode)); if(mode == "r" || test_exist(file_name)) { locked = true; } } else { header.name = header_name; } //open the data file data = fopen(file_name.c_str(), (mode + "b").c_str()); } void setDescription(std::string desc) { readonly(); //if the file is read-only, throw an exception header.description = desc; } void setZPlotTitles(std::string spectrum, std::string value) { readonly(); //if the file is read-only, throw an exception header.z_plot_titles[0] = spectrum; header.z_plot_titles[1] = value; } void setPixelSize(double sx, double sy) { readonly(); //if the file is read-only, throw an exception header.pixel_size[0] = sx; header.pixel_size[1] = sy; } void setWavelengthUnits(std::string units) { readonly(); //if the file is read-only, throw an exception header.wavelength_units = units; } void setCoordinates(double x, double y) { readonly(); //if the file is read-only, throw an exception header.x_start = x; header.y_start = y; } //FUNCTIONS THAT MAY BE DISALLOWED IN A LOCKED FILE void setSamples(unsigned int samples) { EnviHeader newHeader = header; newHeader.samples = samples; set_header(newHeader); } void setLines(unsigned int lines) { EnviHeader newHeader = header; newHeader.lines = lines; set_header(newHeader); } void setBands(unsigned int bands) { EnviHeader newHeader = header; newHeader.bands = bands; set_header(newHeader); } //DATA MANIPULATION void addBand(void* band, unsigned int samples, unsigned int lines, double wavelength, std::string band_name ="") { //add a band to the file EnviHeader newHeader = header; newHeader.bands++; newHeader.samples = samples; newHeader.lines = lines; newHeader.wavelength.push_back(wavelength); if(band_name != "") newHeader.band_names.push_back(band_name); set_header(newHeader); //copy the data to the file fwrite(band, header.valsize(), samples * lines, data); //since data was written, the file must be locked locked = true; } //close file void close() { //std::cout<<"ENVI File Mode: "<