#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 "../math/fd_coefficients.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) std::string fname; //file name used for repeated opening and closing //allocate sufficient space for a spectrum based on the data type and number of bands void* alloc_array(size_t len){ switch(header.data_type){ case envi_header::int8: return malloc(len); case envi_header::int16: case envi_header::uint16: return malloc(2 * len); case envi_header::int32: case envi_header::uint32: case envi_header::float32: return malloc(4 * len); case envi_header::int64: case envi_header::uint64: case envi_header::float64: case envi_header::complex32: return malloc(8 * len); case envi_header::complex64: return malloc(16 * len); default: std::cout<<"ERROR stim::envi data type not recognized for spectral allocation"< inline void cast(DST* dst, SRC* src){ (*dst) = (DST)(*src); } //cast an array from type SRC to type DEST template inline void cast(DST* dst, SRC* src, size_t len){ for(size_t i = 0; i < len; i++) cast(&dst[i], &src[i]); } public: /// Default constructor envi(){ file = NULL; //set the file pointer to NULL } envi_header header; void* malloc_spectrum(){ return alloc_array(header.bands); } void* malloc_band(){ return alloc_array(header.samples * header.lines); } /// Returns the size of the data type in bytes unsigned int type_size(){ if(header.data_type == envi_header::float32) return 4; if(header.data_type == envi_header::float64) return 8; exit(1); } /// Returns the progress of the current processing operation as a percentage void reset_progress(){ if(header.interleave == envi_header::BSQ){ //if the infile is bsq file if(header.data_type ==envi_header::float32) ((bsq*)file)->reset_progress(); else if(header.data_type == envi_header::float64) ((bsq*)file)->reset_progress(); else std::cout<<"ERROR: unidentified data type"<*)file)->reset_progress(); else if(header.data_type == envi_header::float64) ((bil*)file)->reset_progress(); else std::cout<<"ERROR: unidentified data type"<*)file)->reset_progress(); else if(header.data_type == envi_header::float64) ((bip*)file)->reset_progress(); else std::cout<<"ERROR: unidentified data type"<*)file)->get_progress(); else if(header.data_type == envi_header::float64) return ((bsq*)file)->get_progress(); else std::cout<<"ERROR: unidentified data type"<*)file)->get_progress(); else if(header.data_type == envi_header::float64) return ((bil*)file)->get_progress(); else std::cout<<"ERROR: unidentified data type"<*)file)->get_progress(); else if(header.data_type == envi_header::float64) return ((bip*)file)->get_progress(); else std::cout<<"ERROR: unidentified data type"<(); else if(header.data_type == envi_header::float64) file = new bsq(); } else if(header.interleave == envi_header::BIP){ if(header.data_type ==envi_header::float32) file = new bip(); else if(header.data_type == envi_header::float64) file = new bip(); } else if(header.interleave == envi_header::BIL){ if(header.data_type ==envi_header::float32) file = new bil(); else if(header.data_type == envi_header::float64) file = new bil(); } } /// Open a previously opened ENVI file bool open(){ //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(fname, header.samples, header.lines, header.bands, header.header_offset, header.wavelength); } else if(header.data_type == envi_header::float64) { return ((bsq*)file)->open(fname, 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(fname, header.samples, header.lines, header.bands, header.header_offset, header.wavelength); } else if(header.data_type == envi_header::float64) { return ((bil*)file)->open(fname, 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(fname, header.samples, header.lines, header.bands, header.header_offset, header.wavelength); } else if(header.data_type == envi_header::float64) { return ((bip*)file)->open(fname, header.samples, header.lines, header.bands, header.header_offset, header.wavelength); } else return false; } return true; } /// Open an existing ENVI file given the filename and a header structure /// @param filename is the name of the ENVI binary file /// @param header is an ENVI header structure bool open(std::string filename, stim::envi_header h){ header = h; //store the header fname = filename; //save the filename allocate(); return open(); //open the ENVI file; } /// 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(); stim::envi_header h; h.load(headername); //load the header //header.load(headername); return open(filename, h); } /// Normalize a hyperspectral ENVI file given a band number and threshold. /// @param outfile is the name of the normalized file to be output /// @param band is the band label to be output /// @param threshold is a threshold value specified such that normalization will only be done to values in the band > threshold (preventing division by small numbers) bool ratio(std::string outfile, double band, unsigned char* mask = NULL, bool PROGRESS = false){ header.save(outfile + ".hdr"); if(header.interleave == envi_header::BSQ){ //if the infile is bsq file if(header.data_type ==envi_header::float32) return ((bsq*)file)->ratio(outfile, band, mask, PROGRESS); else if(header.data_type == envi_header::float64) return ((bsq*)file)->ratio(outfile,band, mask, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->ratio(outfile, band, mask, PROGRESS); else if(header.data_type == envi_header::float64) return ((bil*)file)->ratio(outfile,band, mask, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->ratio(outfile, band, mask, PROGRESS); else if(header.data_type == envi_header::float64) return ((bip*)file)->ratio(outfile,band, mask, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->normalize(outfile, mask, PROGRESS); else if(header.data_type == envi_header::float64) ((bsq*)file)->normalize(outfile, mask, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->normalize(outfile, mask, PROGRESS); else if(header.data_type == envi_header::float64) ((bil*)file)->normalize(outfile, mask, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->normalize(outfile, mask, PROGRESS); else if(header.data_type == envi_header::float64) ((bip*)file)->normalize(outfile, mask, PROGRESS); else std::cout<<"ERROR: unidentified data type"< w, unsigned char* mask = NULL, bool PROGRESS = false){ header.save(outfile + ".hdr"); 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, mask, PROGRESS); else if(header.data_type == envi_header::float64) return ((bsq*)file)->baseline(outfile,w, mask, PROGRESS); else{ std::cout<<"ERROR: unidentified data type"<*)file)->baseline(outfile, w, mask, PROGRESS); else if(header.data_type == envi_header::float64) return ((bil*)file)->baseline(outfile, w, mask, PROGRESS); else{ std::cout<<"ERROR: unidentified data type"<*)file)->baseline(outfile, w, mask, PROGRESS); else if(header.data_type == envi_header::float64) return ((bip*)file)->baseline(outfile, w, mask, PROGRESS); else{ std::cout<<"ERROR: unidentified data type"<*)file)->project(outfile, center, basis, M, mask, PROGRESS); else if(header.data_type == envi_header::float64) ((bip*)file)->project(outfile, center, basis, M, mask, PROGRESS); else{ std::cout<<"ERROR: unidentified data type"<*)file)->inverse(outfile, center, basis, B, C, PROGRESS); else if(header.data_type == envi_header::float64) ((bip*)file)->inverse(outfile, center, basis, B, C, PROGRESS); else{ std::cout<<"ERROR: unidentified data type"< BIL ((bsq*)file)->bil(outfile, PROGRESS); else if(interleave == envi_header::BIP){ //ERROR std::cout<<"ERROR: conversion from BSQ to BIP isn't practical; use BSQ->BIL->BIP instead"<*)file)->bip(outfile, PROGRESS); exit(1); } } else if(header.data_type == envi_header::float64){ //if the data type is float if(interleave == envi_header::BSQ){ //ERROR std::cout<<"ERROR: is already BSQ file"< BIL ((bsq*)file)->bil(outfile, PROGRESS); else if(interleave == envi_header::BIP){ //ERROR std::cout<<"ERROR: conversion from BSQ to BIP isn't practical; use BSQ->BIL->BIP instead"<*)file)->bip(outfile, PROGRESS); exit(1); } } else{ std::cout<<"ERROR: unidentified data type"< BSQ ((bil*)file)->bsq(outfile, PROGRESS); else if(interleave == envi_header::BIP) //BIL -> BIP ((bil*)file)->bip(outfile, PROGRESS); } else if(header.data_type == envi_header::float64){ if(interleave == envi_header::BIL){ //ERROR std::cout<<"ERROR: is already BIL file"< BSQ ((bil*)file)->bsq(outfile, PROGRESS); else if(interleave == envi_header::BIP) //BIL -> BIP ((bil*)file)->bip(outfile, PROGRESS); } else{ std::cout<<"ERROR: unidentified data type"< BIL ((bip*)file)->bil(outfile, PROGRESS); else if(interleave == envi_header::BSQ){ //ERROR std::cout<<"ERROR: conversion from BIP to BSQ isn't practical; use BIP->BIL->BSQ instead"<*)file)->bip(outfile, PROGRESS); exit(1); } } else if(header.data_type == envi_header::float64){ if(interleave == envi_header::BIP){ //ERROR std::cout<<"ERROR: is already BIP file"< BIL ((bip*)file)->bil(outfile, PROGRESS); else if(interleave == envi_header::BSQ){ //ERROR std::cout<<"ERROR: conversion from BIP to BSQ isn't practical; use BIP->BIL->BSQ instead"<*)file)->bip(outfile, PROGRESS); exit(1); } } else{ std::cout<<"ERROR: unidentified data type"<*)file)->build_mask(mask, mask_band, threshold, PROGRESS); else if(header.data_type == envi_header::float64) return ((bsq*)file)->build_mask(mask, mask_band, threshold, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->build_mask(mask, mask_band, threshold, PROGRESS); else if(header.data_type == envi_header::float64) return ((bil*)file)->build_mask(mask, mask_band, threshold, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->build_mask(mask, mask_band, threshold, PROGRESS); else if(header.data_type == envi_header::float64) return ((bip*)file)->build_mask(mask, mask_band, threshold, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->mask_finite(mask, PROGRESS); else if(header.data_type == envi_header::float64) ((bsq*)file)->mask_finite(mask, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->mask_finite(mask, PROGRESS); else if(header.data_type == envi_header::float64) ((bil*)file)->mask_finite(mask, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->mask_finite(mask, PROGRESS); else if(header.data_type == envi_header::float64) ((bip*)file)->mask_finite(mask, PROGRESS); else std::cout<<"ERROR: unidentified data type"<*)file)->apply_mask(outfile, p, PROGRESS); else if (header.data_type == envi_header::float64) ((bsq*)file)->apply_mask(outfile, p, PROGRESS); 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) ((bil*)file)->apply_mask(outfile, p, PROGRESS); else if (header.data_type == envi_header::float64) ((bil*)file)->apply_mask(outfile, p, PROGRESS); 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) ((bip*)file)->apply_mask(outfile, p, PROGRESS); else if (header.data_type == envi_header::float64) ((bip*)file)->apply_mask(outfile, p, PROGRESS); else std::cout << "ERROR: unidentified data type" << std::endl; } else{ std::cout << "ERROR: unidentified file type" << std::endl; exit(1); } header.save(outfile + ".hdr"); } /// Copies all spectra corresponding to nonzero values of a mask into a pre-allocated matrix of size (P x B) /// where P is the number of masked pixels and B is the number of bands. The allocated memory can be accessed /// using the following indexing: i = b*P + p /// @param matrix is the destination for the pixel data /// @param p is the mask bool sift(void* matrix, unsigned char* p = NULL, bool PROGRESS = false){ if (header.interleave == envi_header::BSQ){ //if the infile is bsq file if (header.data_type == envi_header::float32) return ((bsq*)file)->sift((float*)matrix, p, PROGRESS); else if (header.data_type == envi_header::float64) return ((bsq*)file)->sift((double*)matrix, p, PROGRESS); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } if (header.interleave == envi_header::BIP){ if (header.data_type == envi_header::float32) return ((bip*)file)->sift((float*)matrix, p, PROGRESS); else if (header.data_type == envi_header::float64) return ((bip*)file)->sift((double*)matrix, p, PROGRESS); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } if (header.interleave == envi_header::BIL){ if (header.data_type == envi_header::float32) return ((bil*)file)->sift((float*)matrix, p, PROGRESS); else if (header.data_type == envi_header::float64) return ((bil*)file)->sift((double*)matrix, p, PROGRESS); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } return false; } /// Saves in an array only those spectra corresponding to nonzero values of the mask. /// @param outfile is the name of the sifted output file /// @param p is the mask bool sift(std::string outfile, unsigned char* p, bool PROGRESS = false) { //calculate the number of non-zero values in the mask unsigned long long nnz = 0; unsigned long long npixels = header.lines * header.samples; for(unsigned long long i = 0; i < npixels; i++) if( p[i] > 0 ) nnz++; //create a new header envi_header new_header = header; //if a BIL file is sifted, it's saved as a BIP if(header.interleave == envi_header::BIL) new_header.interleave = envi_header::BIP; //set the number of lines to 1 (this is a matrix with 1 line and N samples) new_header.lines = 1; new_header.samples = nnz; new_header.save(outfile + ".hdr"); if (header.interleave == envi_header::BSQ){ //if the infile is bsq file if (header.data_type == envi_header::float32) return ((bsq*)file)->sift(outfile, p, PROGRESS); else if (header.data_type == envi_header::float64) return ((bsq*)file)->sift(outfile, p, PROGRESS); 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(outfile, p, PROGRESS); else if (header.data_type == envi_header::float64) return ((bil*)file)->sift(outfile, p, PROGRESS); 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(outfile, p, PROGRESS); else if (header.data_type == envi_header::float64) return ((bip*)file)->sift(outfile, p, PROGRESS); else std::cout << "ERROR: unidentified data type" << std::endl; } else{ std::cout << "ERROR: unidentified file type" << std::endl; exit(1); } return false; } bool unsift(std::string outfile, unsigned char* mask, unsigned long long samples, unsigned long long lines, bool PROGRESS = false){ //create a new header envi_header new_header = header; //set the number of lines and samples in the output file (that's all that changes) new_header.lines = lines; new_header.samples = samples; new_header.save(outfile + ".hdr"); if (header.interleave == envi_header::BSQ){ //if the infile is bsq file if (header.data_type == envi_header::float32) return ((bsq*)file)->unsift(outfile, mask, samples, lines, PROGRESS); else if (header.data_type == envi_header::float64) return ((bsq*)file)->unsift(outfile, mask, samples, lines, PROGRESS); else std::cout << "ERROR: unidentified data type" << std::endl; } else if (header.interleave == envi_header::BIL){ //if the infile is bil file std::cout << "ERROR in stim::envi::unsift - BIL files aren't supported yet" << 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)->unsift(outfile, mask, samples, lines, PROGRESS); else if (header.data_type == envi_header::float64) return ((bip*)file)->unsift(outfile, mask, samples, lines, PROGRESS); else std::cout << "ERROR: unidentified data type" << std::endl; } else{ std::cout << "ERROR: unidentified file type" << std::endl; } return 0; } /// 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(void * result, double lb1, double rb1, double pos1, double lb2, double rb2, double pos2, unsigned char* mask){ 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((float*)result, lb1, rb1, pos1, lb2, rb2, pos2, mask); else if(header.data_type == envi_header::float64) return ((bsq*)file)->ph_to_ph((double*)result, lb1, rb1, pos1, lb2, rb2, pos2, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->ph_to_ph((float*)result, lb1, rb1, pos1, lb2, rb2, pos2, mask); else if(header.data_type == envi_header::float64) return ((bil*)file)->ph_to_ph((double*)result, lb1, rb1, pos1, lb2, rb2, pos2, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->ph_to_ph((float*)result, lb1, rb1, pos1, lb2, rb2, pos2, mask); else if(header.data_type == envi_header::float64) return ((bip*)file)->ph_to_ph((double*)result, lb1, rb1, pos1, lb2, rb2, pos2, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_ph((float*)result, lb1, rb1, lab1, rab1, lb2, rb2, pos, mask); else if(header.data_type == envi_header::float64) return ((bsq*)file)->pa_to_ph((double*)result, lb1, rb1, lab1, rab1, lb2, rb2, pos, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_ph((float*)result, lb1, rb1, lab1, rab1, lb2, rb2, pos, mask); else if(header.data_type == envi_header::float64) return ((bil*)file)->pa_to_ph((double*)result, lb1, rb1, lab1, rab1, lb2, rb2, pos, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_ph((float*)result, lb1, rb1, lab1, rab1, lb2, rb2, pos, mask); else if(header.data_type == envi_header::float64) return ((bip*)file)->pa_to_ph((double*)result, lb1, rb1, lab1, rab1, lb2, rb2, pos, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_pa((float*)result, lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, mask); else if(header.data_type == envi_header::float64) return ((bsq*)file)->pa_to_pa((double*)result, lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_pa((float*)result, lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, mask); else if(header.data_type == envi_header::float64) return ((bil*)file)->pa_to_pa((double*)result, lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->pa_to_pa((float*)result, lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, mask); else if(header.data_type == envi_header::float64) return ((bip*)file)->pa_to_pa((double*)result, lb1, rb1, lab1, rab1, lb2, rb2, lab2, rab2, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->centroid((float*)result, lb1, rb1, lab1, rab1, mask); else if(header.data_type == envi_header::float64) return ((bsq*)file)->centroid((double*)result, lb1, rb1, lab1, rab1, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->centroid((float*)result, lb1, rb1, lab1, rab1, mask); else if(header.data_type == envi_header::float64) return ((bil*)file)->centroid((double*)result, lb1, rb1, lab1, rab1, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->centroid((float*)result, lb1, rb1, lab1, rab1, mask); else if(header.data_type == envi_header::float64) return ((bip*)file)->centroid((double*)result, lb1, rb1, lab1, rab1, mask); else std::cout<<"ERROR: unidentified data type"<*)file)->close(); else if(header.data_type == envi_header::float64) ((bsq*)file)->close(); else{ std::cout<<"ERROR: unidentified data type"<*)file)->close(); else if(header.data_type == envi_header::float64) ((bil*)file)->close(); else{ std::cout<<"ERROR: unidentified data type"<*)file)->close(); else if(header.data_type == envi_header::float64) ((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, PROGRESS); else if (header.data_type == envi_header::float64) return ((bsq*)file)->band((double*)ptr, wavelength, PROGRESS); 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, PROGRESS); else if (header.data_type == envi_header::float64) return ((bil*)file)->band((double*)ptr, wavelength, PROGRESS); 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, PROGRESS); else if (header.data_type == envi_header::float64) return ((bip*)file)->band((double*)ptr, wavelength, PROGRESS); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } return false; } /// Retrieve a spectrum from the specified location /// @param ptr is a pointer to pre-allocated memory of size B*sizeof(T) /// @param x is the x-coordinate of the spectrum /// @param y is the y-coordinate of the spectrum /*bool spectrum(void* ptr, unsigned long long x, unsigned long long y, bool PROGRESS = false){ if(header.interleave == envi_header::BSQ){ //if the infile is bsq file if(header.data_type ==envi_header::float32) return ((bsq*)file)->spectrum((float*)ptr, x, y, PROGRESS); else if (header.data_type == envi_header::float64) return ((bsq*)file)->spectrum((double*)ptr, x, y, PROGRESS); 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)->spectrum((float*)ptr, x, y, PROGRESS); else if (header.data_type == envi_header::float64) return ((bil*)file)->spectrum((double*)ptr, x, y, PROGRESS); 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)->spectrum((float*)ptr, x, y, PROGRESS); else if (header.data_type == envi_header::float64) return ((bip*)file)->spectrum((double*)ptr, x, y, PROGRESS); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } return false; }*/ // Retrieve a spectrum at the specified 1D location /// @param ptr is a pointer to pre-allocated memory of size B*sizeof(T) /// @param x is the 1D coordinate of the spectrum template void spectrum(T* ptr, size_t n, bool PROGRESS = false){ void* temp = alloc_array(header.bands); //allocate space for the output array if(header.interleave == envi_header::BSQ){ //if the infile is bsq file if(header.data_type ==envi_header::float32){ ((bsq*)file)->spectrum((float*)temp, n, PROGRESS); cast(ptr, (float*)temp, header.bands); } else if (header.data_type == envi_header::float64){ ((bsq*)file)->spectrum((double*)temp, n, PROGRESS); cast(ptr, (double*)temp, header.bands); } 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){ ((bil*)file)->spectrum((float*)temp, n, PROGRESS); cast(ptr, (float*)temp, header.bands); } else if (header.data_type == envi_header::float64){ ((bil*)file)->spectrum((double*)temp, n, PROGRESS); cast(ptr, (double*)temp, header.bands); } 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){ ((bip*)file)->spectrum((float*)temp, n, PROGRESS); float test = ((float*)temp)[0]; cast(ptr, (float*)temp, header.bands); } else if (header.data_type == envi_header::float64){ ((bip*)file)->spectrum((double*)temp, n, PROGRESS); cast(ptr, (double*)temp, header.bands); } else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } } /// Retrieve a spectrum from the specified (x, y) location /// @param ptr is a pointer to pre-allocated memory of size B*sizeof(T) /// @param x is the x-coordinate of the spectrum /// @param y is the y-coordinate of the spectrum template void spectrum(T* ptr, size_t x, size_t y, bool PROGRESS = false){ spectrum(ptr, y * header.samples + x, PROGRESS); /*void* temp = alloc_array(header.bands); //allocate space for the output array if(header.interleave == envi_header::BSQ){ //if the infile is bsq file if(header.data_type ==envi_header::float32){ ((bsq*)file)->spectrum((float*)temp, x, y, PROGRESS); cast(ptr, temp, header.bands); } else if (header.data_type == envi_header::float64){ ((bsq*)file)->spectrum((double*)temp, x, y, PROGRESS); cast(ptr, temp, header.bands); } 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){ ((bil*)file)->spectrum((float*)temp, x, y, PROGRESS); cast(ptr, temp, header.bands); } else if (header.data_type == envi_header::float64){ ((bil*)file)->spectrum((double*)temp, x, y, PROGRESS); cast(ptr, temp, header.bands); } 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){ ((bip*)file)->spectrum((float*)temp, x, y, PROGRESS); cast(ptr, temp, header.bands); } else if (header.data_type == envi_header::float64){ ((bip*)file)->spectrum((double*)temp, x, y, PROGRESS); cast(ptr, temp, header.bands); } else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } }*/ } /// 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 long long 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; } /// 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(double * p, unsigned char* mask, bool PROGRESS = false){ if (header.interleave == envi_header::BSQ){ if (header.data_type == envi_header::float32) return ((bsq*)file)->avg_band(p, mask, PROGRESS); else if (header.data_type == envi_header::float64) return ((bsq*)file)->avg_band(p, mask, PROGRESS); 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(p, mask, PROGRESS); else if (header.data_type == envi_header::float64) return ((bil*)file)->avg_band(p, mask, PROGRESS); 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(p, mask, PROGRESS); else if (header.data_type == envi_header::float64) return ((bip*)file)->avg_band(p, mask, PROGRESS); 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(double* co, double* avg, unsigned char* mask, bool PROGRESS = false){ if (header.interleave == envi_header::BSQ){ std::cout<<"ERROR: calculating the covariance matrix for a BSQ file is impractical; convert to BIL or BIP first"<*)file)->co_matrix(co, avg, mask, PROGRESS); else if (header.data_type == envi_header::float64) return ((bsq*)file)->co_matrix(co, avg, mask, PROGRESS); 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(co, avg, mask, PROGRESS); else if (header.data_type == envi_header::float64) return ((bil*)file)->co_matrix(co, avg, mask, PROGRESS); 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(co, avg, mask, PROGRESS); else if (header.data_type == envi_header::float64) return ((bip*)file)->co_matrix(co, avg, mask, PROGRESS); 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 long long x0, unsigned long long y0, unsigned long long x1, unsigned long long y1, unsigned long long b0, unsigned long long b1, bool PROGRESS = false){ //save the header for the cropped file stim::envi_header new_header = header; new_header.samples = x1 - x0; new_header.lines = y1 - y0; new_header.bands = b1 - b0; std::vector::const_iterator first = new_header.wavelength.begin() + b0; std::vector::const_iterator last = new_header.wavelength.begin() + b1; new_header.wavelength = std::vector(first, last); new_header.save(outfile + ".hdr"); if (header.interleave == envi_header::BSQ){ if (header.data_type == envi_header::float32) return ((bsq*)file)->crop(outfile, x0, y0, x1, y1, b0, b1, PROGRESS); else if (header.data_type == envi_header::float64) return ((bsq*)file)->crop(outfile, x0, y0, x1, y1, b0, b1, PROGRESS); 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, b0, b1, PROGRESS); else if (header.data_type == envi_header::float64) return ((bil*)file)->crop(outfile, x0, y0, x1, y1, b0, b1, PROGRESS); 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, b0, b1, PROGRESS); else if (header.data_type == envi_header::float64) return ((bip*)file)->crop(outfile, x0, y0, x1, y1, b0, b1, PROGRESS); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } return false; } /// Remove a list of bands from the ENVI file /// @param outfile is the file name for the output hyperspectral image (with trimmed bands) /// @param b is an array of bands to be eliminated void trim(std::string outfile, std::vector trimmed, bool PROGRESS = false){ envi_header h = header; h.bands = header.bands - trimmed.size(); //calculate the new number of bands if(header.wavelength.size() != 0) h.wavelength.resize(h.bands); if(header.band_names.size() != 0) h.band_names.resize(h.bands); size_t it = 0; //allocate an index into the trimmed bands array size_t i = 0; for(size_t b = 0; b < header.bands; b++){ //for each band if(b != trimmed[it]){ if(h.wavelength.size()) h.wavelength[i] = header.wavelength[b]; if(h.band_names.size()) h.band_names[i] = header.band_names[i]; i++; } else it++; } h.save(outfile + ".hdr"); if (header.interleave == envi_header::BSQ){ if (header.data_type == envi_header::float32) return ((bsq*)file)->trim(outfile, trimmed, PROGRESS); else if (header.data_type == envi_header::float64) return ((bsq*)file)->trim(outfile, trimmed, PROGRESS); 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)->trim(outfile, trimmed, PROGRESS); else if (header.data_type == envi_header::float64) return ((bil*)file)->trim(outfile, trimmed, PROGRESS); 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)->trim(outfile, trimmed, PROGRESS); else if (header.data_type == envi_header::float64) return ((bip*)file)->trim(outfile, trimmed, PROGRESS); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } } /// Combine two ENVI images along the Y axis /// @param outfile is the combined file to be output /// @param C is the ENVI object for the image to be combined void combine(std::string outfile, envi C, long long x, long long y, bool PROGRESS = false){ envi_header h = header; long long left = std::min(0, x); //calculate the left edge of the final image long long right = std::max((long long)header.samples, C.header.samples + x); //calculate the right edge of the final image long long top = std::min(0, y); //calculate the top edge of the final image long long bottom = std::max((long long)header.lines, C.header.lines + y); //calculate the bottom edge of the final image h.samples = right - left; h.lines = bottom - top; h.save(outfile + ".hdr"); if (header.interleave == envi_header::BSQ){ if (header.data_type == envi_header::float32) ((bsq*)file)->combine(outfile, (bsq*)C.file, x, y, PROGRESS); else if (header.data_type == envi_header::float64) ((bsq*)file)->combine(outfile, (bsq*)C.file, x, y, PROGRESS); 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) ((bil*)file)->combine(outfile, (bil*)C.file, x, y, PROGRESS); else if (header.data_type == envi_header::float64) ((bil*)file)->combine(outfile, (bil*)C.file, x, y, PROGRESS); 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) ((bip*)file)->combine(outfile, (bip*)C.file, x, y, PROGRESS); else if (header.data_type == envi_header::float64) ((bip*)file)->combine(outfile, (bip*)C.file, x, y, PROGRESS); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } } /// Convolve the given band range with a kernel specified by a vector of coefficients. /// @param outfile is the combined file to be output /// @param c is an array of coefficients /// @param start is the band to start processing (the first coefficient starts here) /// @param nbands is the number of bands to process /// @param center is the index for the center coefficient for the kernel (used to set the wavelengths in the output file) void convolve(std::string outfile, std::vector C, size_t start, size_t end, size_t center = 0, unsigned char* mask = NULL, bool PROGRESS = false){ size_t nbands = end - start + 1; envi_header h = header; //copy the current header h.bands = nbands; //set the number of new bands if(header.wavelength.size() != 0){ h.wavelength.resize(nbands); //set the number of wavelengths to the number of bands for(size_t b = 0; b < nbands; b++) h.wavelength[b] = header.wavelength[b+center]; } if(header.band_names.size() != 0){ h.band_names.resize(nbands); for(size_t b = 0; b < nbands; b++) h.band_names[b] = header.band_names[b+center]; } h.save(outfile + ".hdr"); //save the new header if (header.interleave == envi_header::BSQ){ if (header.data_type == envi_header::float32) ((bsq*)file)->convolve(outfile, C, start, end, mask, PROGRESS); else if (header.data_type == envi_header::float64) ((bsq*)file)->convolve(outfile, C, start, end, mask, PROGRESS); 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) ((bil*)file)->convolve(outfile, C, start, end, mask, PROGRESS); else if (header.data_type == envi_header::float64) ((bil*)file)->convolve(outfile, C, start, end, mask, PROGRESS); 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) ((bip*)file)->convolve(outfile, C, start, end, mask, PROGRESS); else if (header.data_type == envi_header::float64) ((bip*)file)->convolve(outfile, C, start, end, mask, PROGRESS); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } } /// Approximates the nth derivative of the spectra to the specified order /// @param outfile is the file where the derivative approximation will be saved /// @n is the derivative to be calculated /// @order is the order of the error (must be even) void deriv(std::string outfile, size_t d, size_t order, unsigned char* mask = NULL, bool PROGRESS = false){ header.save(outfile + ".hdr"); if (header.interleave == envi_header::BSQ){ if (header.data_type == envi_header::float32) ((bsq*)file)->deriv(outfile, d, order, header.wavelength, mask, PROGRESS); else if (header.data_type == envi_header::float64) ((bsq*)file)->deriv(outfile, d, order, header.wavelength, mask, PROGRESS); 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) ((bil*)file)->deriv(outfile, d, order, header.wavelength, mask, PROGRESS); else if (header.data_type == envi_header::float64) ((bil*)file)->deriv(outfile, d, order, header.wavelength, mask, PROGRESS); 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) ((bip*)file)->deriv(outfile, d, order, header.wavelength, mask, PROGRESS); else if (header.data_type == envi_header::float64) ((bip*)file)->deriv(outfile, d, order, header.wavelength, mask, PROGRESS); else{ std::cout << "ERROR: unidentified data type" << std::endl; exit(1); } } exit(1); } }; } //end namespace rts #endif