#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"<*)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"<*)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"<*)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