image_stack.h 3.76 KB
#ifndef STIM_IMAGE_STACK_H
#define STIM_IMAGE_STACK_H

#include "../parser/wildcards.h"
#include "../parser/filename.h"
#include "../grids/grid.h"
#include "../image/image.h"

namespace stim{

/**This class is used to load 3D grid data from stacks of images
	The class uses a 4D grid object, where the first dimension is a color value.
**/
template<typename T>
class image_stack : public virtual stim::grid<T, 4>{

	enum image_type {stimAuto, stimMono, stimRGB, stimRGBA};

protected:
	using stim::grid<T, 4>::S;
	using stim::grid<T, 4>::R;
	using stim::grid<T, 4>::ptr;
	using stim::grid<T, 4>::samples;
	using stim::grid<T, 4>::read;

public:

	///Load an image stack based on a file mask. Images are loaded in alphanumeric order.

	/// @param file_mask is the mask describing images to be loaded
	void load_images(std::string file_mask){

		stim::filename file_path(file_mask);

		//if the file path is relative, update it with the current working directory
		if(file_path.is_relative()){
			stim::filename wd = stim::filename::cwd();
			file_path = wd.get_relative(file_mask);
		}

		//get the list of files
		std::vector<stim::filename> file_list = file_path.get_list();

		//if there are no matching files, exit
		if(file_list.size() == 0){
			std::cout<<"STIM ERROR (image_stack): No matching files for loading a stack."<<std::endl;
			exit(1);
		}

		//load the first image and set all of the image_stack properties
		std::cout<<"File to Load: "<<file_list[0].str()<<std::endl;
		stim::image<T> I(file_list[0].str());

		//set the image resolution and number of channels
		R.push(I.channels());
		R.push(I.width());
		R.push(I.height());
		R.push(file_list.size());

		//allocate storage space
		ptr = (T*)malloc(sizeof(T) * samples());

		//load and copy each image into the grid
		for(unsigned int i = 0; i<R[3]; i++){

			std::cout<<"File to Load: "<<file_list[i].str()<<std::endl;
			//load the image
			stim::image<T> I(file_list[i].str());

			//retrieve the interlaced data from the image - store it in the grid
			I.get_interleaved_rgb(&ptr[ i * R[0] * R[1] * R[2] ]);
			
		}
	}

	///Saves a single page to an image file

	/// @param file_name is the name of the image file to be created
	/// @param i is the page to be saved
	void save_image(std::string file_name, unsigned int i){

		//create an image
		stim::image<T> I;

		//retrieve the interlaced data from the image - store it in the grid
		I.set_interleaved(&ptr[ i * R[0] * R[1] * R[2] ], R[1], R[2], R[0]);

		I.save(file_name);
	}
	///Sets the dimensions of the image in each direction
	///Voxel-size.
	/// @param x size in the x direction
	/// @param y size in the y direction
	/// @param z size in the z direction
	void
	set_dim(float x, float y, float z)
	{
		S[0] = 1;
		S[1] = x;
		S[2] = y;
		S[3] = z;
	}
	///Saves the entire stack to a set of images

	/// @param file_mask is the mask describing how the file names will be saved (ex. image????.bmp)
	void save_images(std::string file_mask){

		stim::filename file_path(file_mask);

		//if the file path is relative, update it with the current working directory
		if(file_path.is_relative()){
			stim::filename wd = stim::filename::cwd();
			file_path = wd.get_relative(file_mask);
		}

		//create a list of file names
		std::vector<std::string> file_list = stim::wildcards::increment(file_path.str(), 0, R[3]-1, 1);

		for(int i=0; i<R[3]; i++)
			save_image(file_list[i], i);
	}

	/// Returns the pixel at the specified point
	T get(unsigned int x, unsigned int y, unsigned int z, unsigned int c = 0){
		return ptr[z * R[0] * R[1] * R[2] + y * R[0] * R[1] + x * R[0] + c];
	}

	void read(std::string file, unsigned int X, unsigned int Y, unsigned int Z, unsigned int C = 1, unsigned int header = 0){
		read(file, stim::vec<unsigned long>(C, X, Y, Z), header);
	}

	T* data(){
		return ptr;
	}

};


}

#endif