#ifndef STIM_HSI_H #define STIM_HSI_H #include "../envi/envi_header.h" #include "../envi/binary.h" #include #include namespace stim{ /** The BIL class represents a 3-dimensional binary file stored using band interleaved by line (BIL) image encoding. The binary file is stored such that X-Z "frames" are stored sequentially to form an image stack along the y-axis. When accessing the data sequentially on disk, the dimensions read, from fastest to slowest, are X, Z, Y. This class is optimized for data streaming, and therefore supports extremely large (terabyte-scale) files. Data is loaded from disk on request. Functions used to access data are written to support efficient reading. */ template class hsi: public binary { protected: unsigned char O[3]; //order of dimensions (orientation on disk) //[X Y B]: [0 1 2] = bsq, [0 2 1] = bil, [1 2 0] = bip std::vector w; //band wavelengths unsigned long long X(){ return R[O[0]]; } unsigned long long Y(){ return R[O[1]]; } unsigned long long Z(){ return R[O[2]]; } /// Initialize axis orders based on common interleave formats void init_bsq(){ O[0] = 0; O[1] = 1; O[2] = 2; } void init_bil(){ O[0] = 0; O[1] = 2; O[2] = 1; } void init_bip(){ O[0] = 1; O[1] = 2; O[2] = 0; } /// Calculate the number of masked pixels in a given mask unsigned long long nnz(unsigned char* mask){ unsigned long long XY = X() * Y(); //calculate the total number of pixels in the HSI if(mask == NULL) return XY; //if the mask is null, assume that all of the pixels are masked unsigned long long n = 0; //initialize the number of masked pixels to zero (0) for(unsigned long long xy = 0; xy < XY; xy++) //for each pixel in the HSI if(mask[xy]) n++; //if the mask value is nonzero, increment the number of masked pixels return n; //return the number of masked pixels } T lerp(double w, T low_v, double low_w, T high_v, double high_w){ if(low_w == high_w) return low_v; //if the interval is of zero length, just return one of the bounds double alpha = (w - low_w) / (high_w - low_w); //calculate the interpolation factor return (T)((1.0 - alpha) * low_v + alpha * high_v); //interpolate } /// Gets the two band indices surrounding a given wavelength void band_bounds(double wavelength, unsigned long long& low, unsigned long long& high){ unsigned long long B = Z(); for(high = 0; high < B; high++){ if(w[high] > wavelength) break; } low = 0; if(high > 0) low = high-1; } /// Get the list of band numbers that bound a list of wavelengths void band_bounds(std::vector wavelengths, std::vector& low_bands, std::vector& high_bands){ unsigned long long W = w.size(); //get the number of wavelengths in the list low_bands.resize(W); //pre-allocate space for the band lists high_bands.resize(W); for(unsigned long long wl = 0; wl < W; wl++){ //for each wavelength band_bounds(wavelengths[wl], low_bands[wl], high_bands[wl]); //find the low and high bands } } /// Returns the interpolated in the given spectrum based on the given wavelength /// @param s is the spectrum in main memory of length Z() /// @param wavelength is the wavelength value to interpolate out T interp_spectrum(T* s, double wavelength){ unsigned long long low, high; //indices for the bands surrounding wavelength band_bounds(wavelength, low, high); //get the surrounding band indices if(high == w.size()) return s[w.size()-1]; //if the high band is above the wavelength range, return the highest wavelength value return lerp(wavelength, s[low], w[low], s[high], w[high]); } /// Returns the interpolated value corresponding to the given list of wavelengths std::vector interp_spectrum(T* s, std::vector wavelengths){ unsigned long long N = wavelengths.size(); //get the number of wavelength measurements std::vector v; //allocate space for the resulting values v.resize(wavelengths.size()); for(unsigned long long n = 0; n < N; n++){ //for each measurement v[n] = interp_spectrum(s, wavelengths[n]); //interpolate the measurement } return v; } /// Returns the 1D on-disk index of a specified pixel location and band size_t idx(size_t x, size_t y, size_t b){ size_t c[3]; //generate a coefficient list c[O[0]] = x; //assign the coordinates based on the coefficient order c[O[1]] = y; c[O[2]] = b; return c[2] * R[0] * R[1] + c[1] * R[0] + c[0]; //calculate and return the index (trust me this works) } }; } //end namespace STIM #endif