bsq.h 8.45 KB
#ifndef STIM_BSQ_H
#define STIM_BSQ_H

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

namespace rts{

template <typename T>

class bsq: public binary<T> {

protected:
	
	//envi_header header;

	std::vector<double> w;	//band wavelengths
	unsigned int offset;

public:

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

	//open a file, given the file name and dimensions
	bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int B, unsigned int header_offset, std::vector<double> wavelengths){

		//copy the wavelengths to the BSQ file structure
		w = wavelengths;
		//copy the wavelengths to the structure
		offset = header_offset;

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

		return false;
		
	}

	//retrieve one band (specified by the band index)
	bool band_index( T * p, unsigned int page){

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

		getSlice(p, 2, page);
		return true;
	}

	//retrieve one band (specified by the wavelength)
	bool band( T * p, double wavelength){

		unsigned int XY = R[0] * R[1];	//calculate the number of pixels in 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]) {
				getSlice(p, 2, R[2]-1);
				return true;
			}
		}
		if ( wavelength < w[page] )
		{
			p1=(T*)malloc( XY * sizeof(T));                     //memory allocation
			p2=(T*)malloc( XY * sizeof(T));
			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
		{
			getSlice(p, 2, page);
		}

		return true;
	}

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

		unsigned int i;

		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;
			return false;
		}

		file.seekg((x + y * R[0]) * sizeof(T), std::ios::beg);           //point to the certain sample and line
		for (i = 0; i < R[3]; i++)
		{
			file.read((char *)(p + i), sizeof(T));
			file.seekg((R[1] * R[0] - 1) * sizeof(T), std::ios::cur);    //go to the next band
		}

		return true;	
	}

	//baseline correction and save it into file
	
	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 B = R[2];		//calculate the number of bands
		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

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

		T * a;					//pointers to the high and low band images
		T * b;
		T * c;				//pointer to the current image

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

		if (a == NULL || b == NULL || c == NULL){
			std::cout<<"ERROR: error allocating memory";
			exit(1);
		}


		//initialize lownum, highnum, low, high		
		ai=w[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, S);
		}
		//else get the low band
		else{
			control += 1;
			band(a, ai);
			bi = wls[control];
		}
		//get the high band
		band(b, bi);

		//correct every band 
		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];
					band(b, 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, S);	//clear the high band

					ai = bi;
					bi = w[B - 1];
				}
			}

			//get the current band
			band_index(c, cii);
			ci = w[cii];
			
			//perform the baseline correction
			for(unsigned i=0; i < XY; i++){
				double r = (double) (ci - ai) / (double) (bi - ai);
				c[i] =(T) ( c[i] - (b[i] - a[i]) * r - a[i] );
			}
			
			target.write(reinterpret_cast<const char*>(c), S);   //write the corrected data into destination
		
		}	

		//header.save(headername);         //save the new header file
		
		free(a);
		free(b);
		free(c);
		target.close();
		return true;
	}

	// normalize the BSQ file
	bool normalize(std::string outname, double w)
	{
		unsigned int B = R[2];		//calculate the number of bands
		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

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

		T * b;					//pointers to the certain wavelength band
		T * c;				//pointer to the current image

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

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

		for(unsigned j = 0; j < B; j++)
		{
			band_index(c, j);                     //get the current band into memory
			for(unsigned i = 0; i < XY; i++)
			{
				c[i] = c[i] / b[i];
			}
			target.write(reinterpret_cast<const char*>(c), S);   //write normalized data into destination
		}

		//header.save(headername);         //save the new header file
		
		free(b);
		free(c);
		target.close();
		return true;
	}
	
	//convert BSQ file to BIP file and save it
	bool bip(std::string outname)
	{
		std::string temp = outname + "_temp";
		std::string headtemp = temp + ".hdr";
		//first creat a temporary bil file and convert bsq file to bil file
		bil(temp);

		rts::bil<T> n;
		if(n.open(temp, R[0], R[1], R[2], offset, w)==false){        //open infile
			std::cout<<"ERROR: unable to open input file"<<std::endl;
			exit(1);
		}
		//then convert bil file to bip file
		n.bip(outname);
		n.close();
		remove(temp.c_str());
		remove(headtemp.c_str());
		return true;
	}

	//convert BSQ file to BIL file and save it
	bool bil(std::string outname)
	{
		//simplify image resolution
		unsigned int L = R[0] * R[2] * sizeof(T);		//calculate the number of bytes of a ZX slice
		unsigned int jump = (R[1] - 1) * R[0] * sizeof(T);
		
		std::ofstream target(outname.c_str(), std::ios::binary);
		std::string headername = outname + ".hdr";
		
		T * p;			//pointer to the current spectrum
		p = (T*)malloc(L);
		
		for ( unsigned i = 0; i < R[1]; i++)
		{
			file.seekg(R[0] * i * sizeof(T), std::ios::beg);
			for ( unsigned j = 0; j < R[2]; j++ )
			{
				file.read((char *)(p + j * R[0]), sizeof(T) * R[0]);
				file.seekg(jump, std::ios::cur);    //go to the next band	
			}					
			target.write(reinterpret_cast<const char*>(p), L);   //write XZ slice data into target file	
		}
		//header.interleave = rts::envi_header::BIL;  //change the type of file in header file
		//header.save(headername);
		
		free(p);
		target.close();
		return true;
	}
	
	//create mask file
	bool mask(unsigned char* p, double mask_band, double threshold){

		T* temp = (T*)malloc(R[0] * R[1] * sizeof(T));		//allocate memory for the certain band
		band(temp, mask_band);

		for (unsigned int i = 0; i < R[0] * R[1]; i++) {
				if (temp[i] < threshold)
					p[i] = 0;
				else
					p[i] = 255;
		}

		return true;

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

	};
}

#endif