image.h 5.76 KB
#ifndef STIM_IMAGE_H
#define STIM_IMAGE_H
#ifdef JPEG_FOUND
	#define cimg_use_jpeg         //necessary for JPG files
#endif
#include "CImg.h"

#include <vector>
#include <iostream>

namespace stim{
//This static class provides the STIM interface for loading images
//	Use this interface for all image management - that way the actual library can be changed without problems

//currently this interface uses CImg
//	T = data type (usually unsigned char)
template <class T>
class image{

	cimg_library::CImg<T> img;

public:

	//default constructor
	image(){
	}

	//constructor (load an image file)
	image(std::string filename){
		img.load(filename.c_str());
	}

	/// Constructor initializes an image to a given size
	/*image(unsigned int x, unsigned int y = 1, unsigned int z = 1){
		img = cimg_library::CImg<T>(x, y, z);
	}*/

	image(unsigned int x, unsigned int y = 1, unsigned int z = 1, unsigned int c = 1){
		img = cimg_library::CImg<T>(x, y, z, c);
	}

	//Load an image from a file
	void load(std::string filename){
		img.load(filename.c_str());
	}

	//save a file
	void save(std::string filename){
		img.save(filename.c_str());
	}

	//create an image from an interleaved buffer
	void set_interleaved(T* buffer, unsigned int width, unsigned int height, unsigned int channels = 1){

		T* non_interleaved = (T*)malloc(width * height * 3 * sizeof(T));
		unsigned int S = width * height;

		for(unsigned int i = 0; i < S; i++){
			for(unsigned int c = 0; c < channels; c++){
				non_interleaved[i + c * S] = buffer[i * channels + c];
			}
		}

		img = cimg_library::CImg<T>(non_interleaved, width, height, 1, channels);
	}

	//fills an allocated region of memory with non-interleaved data
	void data_noninterleaved(T* data){
		memcpy(data, img.data(), sizeof(T) * size());
	}

	void data_interleaved(T* data){

		unsigned int C = channels();
		unsigned int X = width() * height();

		T* ptr = img.data();

		//for each channel
		for(unsigned int c = 0; c < C; c++)
			//convert each pixel
			for(unsigned int x = 0; x < X; x++)
				data[x * C + c] = ptr[c * X + x];
	}

	image<T> channel(unsigned int c){

		//create a new image
		image<T> single;

		single.img = img.get_channel(c);

		return single;

	}

	/// Copy the given data to the specified channel

	/// @param c is the channel number that the data will be copied to
	/// @param buffer is a pointer to the image to be copied to channel c

	void set_channel(unsigned int c, T* buffer){

		//calculate the number of pixels in a channel
		unsigned int channel_size = width() * height();        

		//retreive a pointer to the raw image data
		T* ptr = img.data() + channel_size * c;

		//copy the buffer to the specified channel
		memcpy(ptr, buffer, sizeof(T) * channel_size);
	}

	image<T> getslice(unsigned int c){

		//create a new image
		image<T> slice;

		slice.img = img.get_slice(c);

		return slice;

	}

	unsigned int channels(){
		return (unsigned int)img.spectrum();
	}

	unsigned int width(){
		return img.width();
	}

	unsigned int height(){
		return img.height();
	}

	T* data(){

		return img.data();
	}

	//returns the size (number of values) of the image
	unsigned long size(){
		return img.size();
	}

	/// Returns the number of nonzero values
	unsigned int nnz(){

		unsigned long P = width() * height();
		unsigned long C = channels();

		T* ptr = img.data();

		unsigned long n = 0;

		for(unsigned long p = 0; p < P; p++){
			for(unsigned long c = 0; c < C; c++){

				if(ptr[c * P + p] > 0){
					n++;
					break;
				}
			}
		}

		return n;	//return the number of nonzero pixels

	}

	//this function returns indices of pixels that have nonzero values
	std::vector<unsigned long> sparse_idx(){

		std::vector<unsigned long> s;		//allocate an array
		s.resize(nnz());					//allocate space in the array

		unsigned long P = width() * height();
		unsigned long C = channels();

		T* ptr = img.data();				//get a pointer to the image data

		unsigned long i = 0;
		for(unsigned long p = 0; p < P; p++){
			for(unsigned long c = 0; c < C; c++){

				if(ptr[c * P + p] > 0){
					s[i] = p;
					i++;
					break;
				}
			}
		}

		return s;			//return the index list
	}

	
	/// Returns the maximum pixel value in the image
	T maxv(){
		float max = 0;
		unsigned long N = width() * height();		//get the number of pixels

		for (unsigned long i=0; i<N; i++){

			if (img.data()[i] > max)
			{
				max = img.data()[i];
			}	
		}

		return max;	
	}

	/// Returns the minimum pixel value in the image
	T minv(){
		float min = 0;
		unsigned long N = width() * height();		//get the number of pixels

		for (unsigned long i=0; i<N; i++){

			if (img.data()[i] < min)
			{
				min = img.data()[i];
			}	
		}

		return min;	

	}

	image<T> srgb2lab(){

		image<T> rgb;
		rgb.img = img.get_sRGBtoRGB();

		image<T> lab;
		lab.img = rgb.img.get_RGBtoLab();

		return lab;

	}

	image<T> convolve2(image<T> mask){
		
		image<T> result;

		result.img = img.get_convolve(mask.img);

		return result;
	}


	image<T> rotate(float angle, float cx, float cy){
		
		image<T> result;
		float zoom = 1;
		unsigned int interpolation = 1;
		unsigned int boundary = 1;
		result.img = img.get_rotate (angle, cx, cy, zoom, interpolation, boundary);
		//result.save("data_output/test_rotate_neum.bmp");

		return result;
	}

	// leila's code for non_interleaving data in 3D
	//create an data set from an interleaved buffer
	void set_interleaved3(T* buffer, unsigned int width, unsigned int height, unsigned int depth, unsigned int channels = 3){

		T* non_interleaved3 = (T*)malloc(width * height * depth * 3 * sizeof(T));
		unsigned int p = width * height * depth;

		for(unsigned int i = 0; i < p; i++){
			for(unsigned int c = 0; c < channels; c++){
				non_interleaved3[i + c * p] = buffer[i * channels + c];
			}
		}

		img = cimg_library::CImg<T>(non_interleaved3, width, height, depth, channels);
	}
	
};

};		//end namespace stim


#endif