#ifndef STIM_ENVI_H #define STIM_ENVI_H #include "../envi/envi_header.h" #include "../envi/bsq.h" #include "../envi/bip.h" #include "../envi/bil.h" #include #include "../image/image.h" namespace stim{ /** This class implements reading of ENVI hyperspectral files. These files can be stored in multiple orientations (including BSQ, BIP, and BIL) in order to optimize streaming speed depending on applications. Basic ENVI files are stored on disk as a large binary file with a corresponding header. Code for reading and processing ENVI header files is in the envi_header class. */ class envi{ void* file; //void pointer to the relevant file reader (bip, bsq, or bil - with appropriate data type) public: envi_header header; /// Allocate memory for a new ENVI file based on the current interleave format (BIP, BIL, BSQ) and data type. bool allocate(){ file = NULL; //set file to a NULL pointer if(header.interleave == envi_header::BSQ){ if(header.data_type ==envi_header::float32) return(file = new bsq()); else if(header.data_type == envi_header::float64) return(file = new bsq()); } else if(header.interleave == envi_header::BIP){ if(header.data_type ==envi_header::float32) return(file = new bip()); else if(header.data_type == envi_header::float64) return(file = new bip()); } else if(header.interleave == envi_header::BIL){ if(header.data_type ==envi_header::float32) return(file = new bil()); else if(header.data_type == envi_header::float64) return(file = new bil()); } exit(1); //if the function hasn't already returned, we don't handle this state } /// Open an existing ENVI file given the file and header names. /// @param filename is the name of the ENVI binary file /// @param headername is the name of the ENVI header file bool open(std::string filename, std::string headername){ //allocate memory allocate(); //load the header header.load(headername); //load the file if(header.interleave == envi_header::BSQ) { //if the infile is bsq file if(header.data_type == envi_header::float32) { return ((bsq*)file)->open(filename, header.samples, header.lines, header.bands, header.header_offset, header.wavelength); } else if(header.data_type == envi_header::float64) { return ((bsq*)file)->open(filename, header.samples, header.lines, header.bands, header.header_offset, header.wavelength); } else return false; } else if(header.interleave == envi_header::BIL) { //if the infile is bil file if(header.data_type == envi_header::float32) { return ((bil*)file)->open(filename, header.samples, header.lines, header.bands, header.header_offset, header.wavelength); } else if(header.data_type == envi_header::float64) { return ((bil*)file)->open(filename, header.samples, header.lines, header.bands, header.header_offset, header.wavelength); } else return false; } else if(header.interleave == envi_header::BIP) { //if the infile is bip file if(header.data_type == envi_header::float32) { return ((bip*)file)->open(filename, header.samples, header.lines, header.bands, header.header_offset, header.wavelength); } else if(header.data_type == envi_header::float64) { return ((bip*)file)->open(filename, header.samples, header.lines, header.bands, header.header_offset, header.wavelength); } else return false; } else{ std::cout<<"ERROR: unidentified type file "< threshold (preventing division by small numbers) bool normalize(std::string outfile, double band, double threshold = 0.0){ if(header.interleave == envi_header::BSQ){ //if the infile is bsq file if(header.data_type ==envi_header::float32) return ((bsq*)file)->normalize(outfile, band, threshold); else if(header.data_type == envi_header::float64) return ((bsq*)file)->normalize(outfile,band, threshold); else std::cout<<"ERROR: unidentified data type"<*)file)->normalize(outfile, band); else if(header.data_type == envi_header::float64) return ((bil*)file)->normalize(outfile,band); else std::cout<<"ERROR: unidentified data type"<*)file)->normalize(outfile, band); else if(header.data_type == envi_header::float64) return ((bip*)file)->normalize(outfile,band); else std::cout<<"ERROR: unidentified data type"< w){ if(header.interleave == envi_header::BSQ){ //if the infile is bsq file if(header.data_type ==envi_header::float32) return ((bsq*)file)->baseline(outfile, w); else if(header.data_type == envi_header::float64) return ((bsq*)file)->baseline(outfile,w); else{ std::cout<<"ERROR: unidentified data type"<*)file)->baseline(outfile, w); else if(header.data_type == envi_header::float64) return ((bil*)file)->baseline(outfile, w); else{ std::cout<<"ERROR: unidentified data type"<*)file)->baseline(outfile, w); else if(header.data_type == envi_header::float64) return ((bip*)file)->baseline(outfile, w); else{ std::cout<<"ERROR: unidentified data type"<*)file)->bil(outfile); else if(interleave == envi_header::BIP) //if the target file is bip file return ((bsq*)file)->bip(outfile); } else if(header.data_type == envi_header::float64){ //if the data type is float if(interleave == envi_header::BSQ){ std::cout<<"ERROR: is already BSQ file"<*)file)->bil(outfile); else if(interleave == envi_header::BIP) return ((bsq*)file)->bip(outfile); } else{ std::cout<<"ERROR: unidentified data type"<*)file)->bsq(outfile); else if(interleave == envi_header::BIP) //if the target file is bip file return ((bil*)file)->bip(outfile); } else if(header.data_type == envi_header::float64){ //if the data type is float if(interleave == envi_header::BIL){ std::cout<<"ERROR: is already BIL file"<*)file)->bsq(outfile); else if(interleave == envi_header::BIP) return ((bil*)file)->bip(outfile); } else{ std::cout<<"ERROR: unidentified data type"<*)file)->bil(outfile); else if(interleave == envi_header::BSQ) //if the target file is bsq file return ((bip*)file)->bsq(outfile); } else if(header.data_type == envi_header::float64){ //if the data type is float if(interleave == envi_header::BIP){ std::cout<<"ERROR: is already BIP file"<*)file)->bil(outfile); else if(interleave == envi_header::BSQ) //if the target file is bsq file return ((bip*)file)->bsq(outfile); } else{ std::cout<<"ERROR: unidentified data type"<*)file)->build_mask(mask_band, threshold, p); else if(header.data_type == envi_header::float64) return ((bsq*)file)->build_mask(mask_band, threshold, p); else std::cout<<"ERROR: unidentified data type"<*)file)->build_mask(mask_band, threshold, p); else if(header.data_type == envi_header::float64) return ((bil*)file)->build_mask(mask_band, threshold, p); else std::cout<<"ERROR: unidentified data type"<*)file)->build_mask(mask_band, threshold, p); else if(header.data_type == envi_header::float64) return ((bip*)file)->build_mask(mask_band, threshold, p); else std::cout<<"ERROR: unidentified data type"<*)file)->apply_mask(outfile, p); else if (header.data_type == envi_header::float64) return ((bsq*)file)->apply_mask(outfile, p); else std::cout << "ERROR: unidentified data type" << std::endl; } else if (header.interleave == envi_header::BIL){ //if the infile is bil file if (header.data_type == envi_header::float32) return ((bil*)file)->apply_mask(outfile, p); else if (header.data_type == envi_header::float64) return ((bil*)file)->apply_mask(outfile, p); else std::cout << "ERROR: unidentified data type" << std::endl; } else if (header.interleave == envi_header::BIP){ //if the infile is bip file if (header.data_type == envi_header::float32) return ((bip*)file)->apply_mask(outfile, p); else if (header.data_type == envi_header::float64) return ((bip*)file)->apply_mask(outfile, p); else std::cout << "ERROR: unidentified data type" << std::endl; } else{ std::cout << "ERROR: unidentified file type" << std::endl; exit(1); } return false; } /// sift-mask saves in an array only those spectra corresponding to nonzero values of the mask. bool sift_mask(std::string outfile, unsigned char* p) { if (header.interleave == envi_header::BSQ){ //if the infile is bsq file if (header.data_type == envi_header::float32) return ((bsq*)file)->sift_mask(outfile, p); else if (header.data_type == envi_header::float64) return ((bsq*)file)->sift_mask(outfile, p); else std::cout << "ERROR: unidentified data type" << std::endl; } else if (header.interleave == envi_header::BIL){ //if the infile is bil file if (header.data_type == envi_header::float32) return ((bil*)file)->sift_mask(outfile, p); else if (header.data_type == envi_header::float64) return ((bil*)file)->sift_mask(outfile, p); else std::cout << "ERROR: unidentified data type" << std::endl; } else if (header.interleave == envi_header::BIP){ //if the infile is bip file if (header.data_type == envi_header::float32) return ((bip*)file)->sift_mask(outfile, p); else if (header.data_type == envi_header::float64) return ((bip*)file)->sift_mask(outfile, p); else std::cout << "ERROR: unidentified data type" << std::endl; } else{ std::cout << "ERROR: unidentified file type" << std::endl; exit(1); } ///make new header and save here return false; } /// Compute the ratio of two baseline-corrected peaks. The result is stored in a pre-allocated array. /// @param lb1 is the label value for the left baseline point for the first peak (numerator) /// @param rb1 is the label value for the right baseline point for the first peak (numerator) /// @param pos1 is the label value for the first peak (numerator) position /// @param lb2 is the label value for the left baseline point for the second peak (denominator) /// @param rb2 is the label value for the right baseline point for the second peak (denominator) /// @param pos2 is the label value for the second peak (denominator) position /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size bool ph_to_ph(double lb1, double rb1, double pos1, double lb2, double rb2, double pos2, void * result){ if(header.interleave == envi_header::BSQ){ //if the infile is bsq file if(header.data_type ==envi_header::float32) return ((bsq*)file)->ph_to_ph(lb1, rb1, pos1, lb2, rb2, pos2, (float*)result); else if(header.data_type == envi_header::float64) return ((bsq*)file)->ph_to_ph(lb1, rb1, pos1, lb2, rb2, pos2, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->ph_to_ph(lb1, rb1, pos1, lb2, rb2, pos2, (float*)result); else if(header.data_type == envi_header::float64) return ((bil*)file)->ph_to_ph(lb1, rb1, pos1, lb2, rb2, pos2, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->ph_to_ph(lb1, rb1, pos1, lb2, rb2, pos2, (float*)result); else if(header.data_type == envi_header::float64) return ((bip*)file)->ph_to_ph(lb1, rb1, pos1, lb2, rb2, pos2, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_ph(lb1, rb1, lab1, rab1, lb2, rb2, pos, (float*)result); else if(header.data_type == envi_header::float64) return ((bsq*)file)->pa_to_ph(lb1, rb1, lab1, rab1, lb2, rb2, pos, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_ph(lb1, rb1, lab1, rab1, lb2, rb2, pos, (float*)result); else if(header.data_type == envi_header::float64) return ((bil*)file)->pa_to_ph(lb1, rb1, lab1, rab1, lb2, rb2, pos, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_ph(lb1, rb1, lab1, rab1, lb2, rb2, pos, (float*)result); else if(header.data_type == envi_header::float64) return ((bip*)file)->pa_to_ph(lb1, rb1, lab1, rab1, lb2, rb2, pos, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_pa(lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, (float*)result); else if(header.data_type == envi_header::float64) return ((bsq*)file)->pa_to_pa(lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_pa(lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, (float*)result); else if(header.data_type == envi_header::float64) return ((bil*)file)->pa_to_pa(lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_pa(lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, (float*)result); else if(header.data_type == envi_header::float64) return ((bip*)file)->pa_to_pa(lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->cpoint(lb1, rb1, lab1, rab1, (float*)result); else if(header.data_type == envi_header::float64) return ((bsq*)file)->cpoint(lb1, rb1, lab1, rab1, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->cpoint(lb1, rb1, lab1, rab1, (float*)result); else if(header.data_type == envi_header::float64) return ((bil*)file)->cpoint(lb1, rb1, lab1, rab1, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->cpoint(lb1, rb1, lab1, rab1,(float*)result); else if(header.data_type == envi_header::float64) return ((bip*)file)->cpoint(lb1, rb1, lab1, rab1, (double*)result); else std::cout<<"ERROR: unidentified data type"<*)file)->close(); else if(header.data_type == envi_header::float64) return ((bsq*)file)->close(); else{ std::cout<<"ERROR: unidentified data type"<*)file)->close(); else if(header.data_type == envi_header::float64) return ((bil*)file)->close(); else{ std::cout<<"ERROR: unidentified data type"<*)file)->close(); else if(header.data_type == envi_header::float64) return ((bip*)file)->close(); else{ std::cout<<"ERROR: unidentified data type"<*)file)->pixel((float*)p, n); else if(header.data_type == envi_header::float64) return ((bsq*)file)->pixel((double*)p, n); else{ std::cout<<"ERROR: unidentified data type"<*)file)->pixel((float*)p, n); else if(header.data_type == envi_header::float64) return ((bil*)file)->pixel((double*)p, n); else{ std::cout<<"ERROR: unidentified data type"<*)file)->pixel((float*)p, n); else if(header.data_type == envi_header::float64) return ((bip*)file)->pixel((double*)p, n); else{ std::cout<<"ERROR: unidentified data type"<*)file)->band((float*)ptr, wavelength); else if (header.data_type == envi_header::float64) return ((bsq*)file)->band((double*)ptr, wavelength); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } else if (header.interleave == envi_header::BIL){ if (header.data_type == envi_header::float32) return ((bil*)file)->band((float*)ptr, wavelength); else if (header.data_type == envi_header::float64) return ((bil*)file)->band((double*)ptr, wavelength); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } else if (header.interleave == envi_header::BIP){ if (header.data_type == envi_header::float32) return ((bip*)file)->band((float*)ptr, wavelength); else if (header.data_type == envi_header::float64) return ((bip*)file)->band((double*)ptr, wavelength); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } return false; } /// Retrieve a single band (based on index) and stores it in pre-allocated memory. /// @param p is a pointer to an allocated region of memory at least X * Y * sizeof(T) in size. /// @param page <= B is the integer number of the band to be copied. bool band_index(void* ptr, unsigned int b){ if (header.interleave == envi_header::BSQ){ //if the infile is bsq file if (header.data_type == envi_header::float32) return ((bsq*)file)->band_index((float*)ptr, b); else if (header.data_type == envi_header::float64) return ((bsq*)file)->band_index((double*)ptr, b); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } else if (header.interleave == envi_header::BIL){ if (header.data_type == envi_header::float32) return ((bil*)file)->band_index((float*)ptr, b); else if (header.data_type == envi_header::float64) return ((bil*)file)->band_index((double*)ptr, b); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } else if (header.interleave == envi_header::BIP){ if (header.data_type == envi_header::float32) return ((bip*)file)->band_index((float*)ptr, b); else if (header.data_type == envi_header::float64) return ((bip*)file)->band_index((double*)ptr, b); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } return false; } /// Helper function that loads a mask into memory given a filename. /// @param mask is a pointer to pre-allocated memory of size X*Y /// @param maskname is the file name for the image that will serve as the mask bool load_mask(unsigned char * mask, std::string maskname){ //open the mask file stim::image mask_image(maskname); mask_image.data_noninterleaved(mask); //save mask file into memory //memcpy(mask, mask_image.data_noninterleaved(), mask_image.size()); //mask_image.clear(); return true; } //p:start positon; N: number of pixels saved in X; bool feature_matrix(void * X, unsigned char * mask, unsigned start, unsigned N) { //save pixels in X as floating numbers: float * p float * p = (float*)malloc(header.bands * sizeof(float)); //save pixel information unsigned pixels = header.samples * header.lines; //calculate pixel numbers in a band unsigned count = 0; //for counting use unsigned j = 0; //memory the pointer location in X //create two indices into the mask (mask index and pixel index) unsigned mi = 0; //valid pixel index unsigned pi = 0; //actual pixel in the mask //find the actual pixel index for the mask index "start" while(mi < start){ if(mask[pi]) mi++; pi++; } for(unsigned i = pi; i < pixels; i++){ if(mask[i] != 0){ pixel(p, i); //copy p to X for(unsigned k = 0; k < header.bands; k++){ ((float *)X)[j] = p[k]; j++; } count++; if(count == N) break; } else continue; } if(count < N){ std::cout << "number of valid pixels in the mask : " << count <<"is less than N: "<< N; exit(1); } free(p); return true; } /// Calculate the mean value for all masked (or valid) pixels in a band and returns the average spectrum /// @param p is a pointer to pre-allocated memory of size [B * sizeof(T)] that stores the mean spectrum /// @param mask is a pointer to memory of size [X * Y] that stores the mask value at each pixel location bool avg_band(void * p, unsigned char* mask){ if (header.interleave == envi_header::BSQ){ if (header.data_type == envi_header::float32) return ((bsq*)file)->avg_band((float*)p, mask); else if (header.data_type == envi_header::float64) return ((bsq*)file)->avg_band((double*)p, mask); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } else if (header.interleave == envi_header::BIL){ if (header.data_type == envi_header::float32) return ((bil*)file)->avg_band((float*)p, mask); else if (header.data_type == envi_header::float64) return ((bil*)file)->avg_band((double*)p, mask); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } else if (header.interleave == envi_header::BIP){ if (header.data_type == envi_header::float32) return ((bip*)file)->avg_band((float*)p, mask); else if (header.data_type == envi_header::float64) return ((bip*)file)->avg_band((double*)p, mask); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } return false; } /// Calculate the covariance matrix for all masked pixels in the image. /// @param co is a pointer to pre-allocated memory of size [B * B] that stores the resulting covariance matrix /// @param avg is a pointer to memory of size B that stores the average spectrum /// @param mask is a pointer to memory of size [X * Y] that stores the mask value at each pixel location bool co_matrix(void* co, void* avg, unsigned char* mask){ if (header.interleave == envi_header::BSQ){ if (header.data_type == envi_header::float32) return ((bsq*)file)->co_matrix((float*)co, (float*)avg, mask); else if (header.data_type == envi_header::float64) return ((bsq*)file)->co_matrix((double*)co, (double*)avg, mask); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } else if (header.interleave == envi_header::BIL){ if (header.data_type == envi_header::float32) return ((bil*)file)->co_matrix((float*)co, (float*)avg, mask); else if (header.data_type == envi_header::float64) return ((bil*)file)->co_matrix((double*)co, (double*)avg, mask); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } else if (header.interleave == envi_header::BIP){ if (header.data_type == envi_header::float32) return ((bip*)file)->co_matrix((float*)co, (float*)avg, mask); else if (header.data_type == envi_header::float64) return ((bip*)file)->co_matrix((double*)co, (double*)avg, mask); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } return false; } /// Crop a region of the image and save it to a new file. /// @param outfile is the file name for the new cropped image /// @param x0 is the lower-left x pixel coordinate to be included in the cropped image /// @param y0 is the lower-left y pixel coordinate to be included in the cropped image /// @param x1 is the upper-right x pixel coordinate to be included in the cropped image /// @param y1 is the upper-right y pixel coordinate to be included in the cropped image bool crop(std::string outfile,unsigned x0, unsigned y0, unsigned x1, unsigned y1){ if (header.interleave == envi_header::BSQ){ if (header.data_type == envi_header::float32) return ((bsq*)file)->crop(outfile, x0, y0, x1, y1); else if (header.data_type == envi_header::float64) return ((bsq*)file)->crop(outfile, x0, y0, x1, y1); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } else if (header.interleave == envi_header::BIL){ if (header.data_type == envi_header::float32) return ((bil*)file)->crop(outfile, x0, y0, x1, y1); else if (header.data_type == envi_header::float64) return ((bil*)file)->crop(outfile, x0, y0, x1, y1); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } else if (header.interleave == envi_header::BIP){ if (header.data_type == envi_header::float32) return ((bip*)file)->crop(outfile, x0, y0, x1, y1); else if (header.data_type == envi_header::float64) return ((bip*)file)->crop(outfile, x0, y0, x1, y1); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } return false; } }; } //end namespace rts #endif