bil.h 9.79 KB
#ifndef STIM_BIL_H
#define STIM_BIL_H

#include "../envi/envi_header.h"
#include "../envi/binary.h"
#include <cstring>
#include <utility>

namespace rts{

template <typename T>

class bil: public binary<T> {

protected:
	
	std::vector<double> w;		//band wavelength

public:

	using binary<T>::open;
	using binary<T>::file;
	using binary<T>::R;

	//open a file, given the file and its header's names
	bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int B, unsigned int header_offset, std::vector<double> wavelengths){

		w = wavelengths;

		return open(filename, vec<unsigned int>(X, Y, B), header_offset);

		return false;
		
	}

	//save one band of the file into the memory, and return the pointer
	bool band_index( T * p, unsigned int page){

		unsigned int L = R[0] * sizeof(T);		//caculate the number of bytes in a sample line
		unsigned int jump = R[0] * (R[2] - 1) * sizeof(T);

		if (page >= R[2]){										//make sure the bank number is right
			std::cout<<"ERROR: page out of range"<<std::endl;
			return false;
		}

		file.seekg(R[0] * page * sizeof(T), std::ios::beg);
		for (unsigned i = 0; i < R[1]; i++)
		{
			file.read((char *)(p + i * R[0]), L);
			file.seekg( jump, std::ios::cur);
		}

		return true;
	}

	bool getBand( T * p, double wavelength){

		unsigned int XY = R[0] * R[1];	//calculate the number of pixels in a band
		unsigned int S = XY * sizeof(T);		//calculate the number of bytes of a band

		unsigned page=0;                      //bands around the wavelength
		T * p1;
		T * p2;

		//get the bands numbers around the wavelength

		//if wavelength is smaller than the first one in header file
		if ( w[page] > wavelength ){
			band_index(p, page);
			return true;
		}

		while( w[page] < wavelength )
		{
			page++;
			//if wavelength is larger than the last wavelength in header file
			if (page == R[2]) {
				band_index(p, R[2]-1);
				return true;
			}
		}
		if ( wavelength < w[page] )
		{
			p1=(T*)malloc(S);                     //memory allocation
			p2=(T*)malloc(S);
			band_index(p1, page - 1);
			band_index(p2, page );
			for(unsigned i=0; i < XY; i++){
				double r = (double) (wavelength - w[page-1]) / (double) (w[page] - w[page-1]);
				p[i] = (p2[i] - p1[i]) * r + p1[i];
			}
		}
		else                           //if the wavelength is equal to a wavelength in header file
		{
			band_index(p, page);
		}

		return true;
	}

	//get YZ line from the a Y slice, Y slice data should be already IN the MEMORY
	bool getYZ(T* p, T* c, double wavelength)
	{
		unsigned int X = R[0];	//calculate the number of pixels in a sample
		unsigned int B = R[2];
		unsigned int L = X * sizeof(T);

		unsigned page=0;                      //samples around the wavelength
		T * p1;
		T * p2;

		//get the bands numbers around the wavelength

		//if wavelength is smaller than the first one in header file
		if ( w[page] > wavelength ){
			memcpy(p, c, L);	
			return true;
		}

		while( w[page] < wavelength )
		{
			page++;
			//if wavelength is larger than the last wavelength in header file
			if (page == B) {
				memcpy(p, c + (B - 1) * X, L);
				return true;
			}
		}
		if ( wavelength < w[page] )
		{
			p1=(T*)malloc( L );                     //memory allocation
			p2=(T*)malloc( L );

			memcpy(p1, c + (page - 1) * X, L);
			memcpy(p2, c + page * X, L);
			
			for(unsigned i=0; i < X; i++){
				double r = (double) (wavelength - w[page-1]) / (double) (w[page] - w[page-1]);
				p[i] = (p2[i] - p1[i]) * r + p1[i];
			}
		}
		else                           //if the wavelength is equal to a wavelength in header file		
			memcpy(p, c + page * X, L);
		
		return true;		
	}

	//save one pixel of the BIP file into the memory, and return the pointer
	bool getSpectrum(T * p, unsigned x, unsigned y){

		if ( x >= R[0] || y >= R[1]){							//make sure the sample and line number is right
			std::cout<<"ERROR: sample or line out of range"<<std::endl;
			exit(1);
		}

		unsigned jump = (R[0] - 1) * sizeof(T);

		file.seekg((y * R[0] * R[2] + x) * sizeof(T), std::ios::beg);

		for(unsigned i = 0; i < R[2]; i++)
		{         //point to the certain sample and line		
			file.read((char *)(p + i), sizeof(T));
			file.seekg(jump, std::ios::cur);  
		}	

		return true;	
	}
	
	//given a Y ,return a XZ slice
	bool getY(T * p, unsigned y)
	{
		if ( y >= R[1]){							//make sure the line number is right
			std::cout<<"ERROR: line out of range"<<std::endl;
			exit(1);
		}	
		
		file.seekg(y * R[2] * R[0] * sizeof(T), std::ios::beg);
		file.read((char *)p, sizeof(T) * R[2] * R[0]);
		
		return true;
		
	}
		
	//(BIL) baseline correction
	bool baseline(std::string outname, std::vector<double> wls){
	
		unsigned N = wls.size();			//get the number of baseline points
		
		std::ofstream target(outname.c_str(), std::ios::binary);	//open the target binary file
		std::string headername = outname + ".hdr";              //the header file name		
		
		//simplify image resolution
		unsigned int ZX = R[2] * R[0];		//calculate the number of points in a Y slice
		unsigned int L = ZX * sizeof(T);			//calculate the number of bytes of a Y slice
		unsigned int B = R[2];
		unsigned int X = R[0];
		
		T* c;			//pointer to the current Y slice
		c = (T*)malloc(L);  //memory allocation
		
		T* a;			//pointer to the two YZ lines surrounding the current YZ line
		T* b;
		
		a = (T*)malloc(X * sizeof(T));
		b = (T*)malloc(X * sizeof(T));


		double ai, bi;	//stores the two baseline points wavelength surrounding the current band
		double ci;		//stores the current band's wavelength
		unsigned control;

		if (a == NULL || b == NULL || c == NULL){
			std::cout<<"ERROR: error allocating memory";
			exit(1);
		}
	//	loop start	correct every y slice
		
		for (unsigned k =0; k < R[1]; k++)
		{
			//get the current y slice
			getY(c, k);
		
			//initialize lownum, highnum, low, high		
			ai = w[0];
			control=0;
			//if no baseline point is specified at band 0,
			//set the baseline point at band 0 to 0
			if(wls[0] != w[0]){
				bi = wls[control];			
				memset(a, (char)0, X * sizeof(T) );
			}
			//else get the low band
			else{
				control++;
				getYZ(a, c, ai);
				bi = wls[control];
			}
			//get the high band
			getYZ(b, c, bi);
		
			//correct every YZ line
			
			for(unsigned cii = 0; cii < B; cii++){

				//update baseline points, if necessary
				if( w[cii] >= bi && cii != B - 1) {
					//if the high band is now on the last BL point
					if (control != N-1) {
	
						control++;		//increment the index
	
						std::swap(a, b);	//swap the baseline band pointers
	
						ai = bi;
						bi = wls[control];
						getYZ(b, c, bi);
	
					}
					//if the last BL point on the last band of the file?
					else if ( wls[control] < w[B - 1]) {
	
						std::swap(a, b);	//swap the baseline band pointers
	
						memset(b, (char)0, X * sizeof(T) );	//clear the high band
	
						ai = bi;
						bi = w[B - 1];
					}
				}
			
				ci = w[cii];
				
				unsigned jump = cii * X;
				//perform the baseline correction
				for(unsigned i=0; i < X; i++)
				{
					double r = (double) (ci - ai) / (double) (bi - ai);
					c[i + jump] =(T) ( c[i + jump] - (b[i] - a[i]) * r - a[i] );
				}
				
			}//loop for YZ line end  
			target.write(reinterpret_cast<const char*>(c), L);   //write the corrected data into destination	
		}//loop for Y slice end		
		
		free(a);
		free(b);
		free(c);
		target.close();
		return true;	
		
	}
		
	// normalize the BIL file
	bool normalize(std::string outname, double band)
	{
		unsigned int B = R[2];		//calculate the number of bands
		unsigned int Y = R[1];
		unsigned int X = R[0];
		unsigned int ZX = R[2] * R[0];
		unsigned int XY = R[0] * R[1];	//calculate the number of pixels in a band
		unsigned int S = XY * sizeof(T);		//calculate the number of bytes in a band		
		unsigned int L = ZX * sizeof(T);

		std::ofstream target(outname.c_str(), std::ios::binary);	//open the target binary file
		std::string headername = outname + ".hdr";              //the header file name

		T * c;				//pointer to the current ZX slice
		T * b;				//pointer to the standard band

		b = (T*)malloc( S );     //memory allocation
		c = (T*)malloc( L ); 

		getBand(b, band);             //get the certain band into memory

		for(unsigned j = 0; j < Y; j++)
		{
			getY(c, j);
			for(unsigned i = 0; i < B; i++)
			{
				for(unsigned m = 0; m < X; m++)
				{
					c[m + i * X] = c[m + i * X] / b[m + j * X];
				}								
			}
			target.write(reinterpret_cast<const char*>(c), L);   //write normalized data into destination
		}
		
		free(b);
		free(c);
		target.close();
		return true;
	}
	
	//convert BIL file to BSQ file and save it
	bool bsq(std::string outname)
	{
		unsigned int S = R[0] * R[1] * sizeof(T);		//calculate the number of bytes in a band
		
		std::ofstream target(outname.c_str(), std::ios::binary);
		std::string headername = outname + ".hdr";
		
		T * p;			//pointer to the current band
		p = (T*)malloc(S);
		
		for ( unsigned i = 0; i < R[2]; i++)
		{			
				band_index(p, i);
				target.write(reinterpret_cast<const char*>(p), S);   //write a band data into target file	
		}

		free(p);
		target.close();
		return true;
	}

	//convert bil file to bip file and save it
	bool bip(std::string outname)
	{
		unsigned int S = R[0] * R[2] * sizeof(T);		//calculate the number of bytes in a ZX slice
		
		std::ofstream target(outname.c_str(), std::ios::binary);
		std::string headername = outname + ".hdr";
		
		T * p;			//pointer to the current XZ slice for bil file
		p = (T*)malloc(S);
		T * q;			//pointer to the current ZX slice for bip file
		q = (T*)malloc(S);
		
		for ( unsigned i = 0; i < R[1]; i++)
		{			
			getY(p, i);
			for ( unsigned k = 0; k < R[2]; k++)
			{
				unsigned ks = k * R[0];
				for ( unsigned j = 0; j < R[0]; j++)
					q[k + j * R[2]] = p[ks + j];
			}
			
			target.write(reinterpret_cast<const char*>(q), S);   //write a band data into target file	
		}


		free(p);
		free(q);
		target.close();
		return true;
	}

	//close the file
	bool close(){
		file.close();
		return true;
	}

	};
}

#endif