Blame view

stim/image/image.h 18.1 KB
d32a1854   David Mayerich   added framework f...
1
2
  #ifndef STIM_IMAGE_H
  #define STIM_IMAGE_H
fbf0ab02   David Mayerich   added support for...
3
  
2e5e3a26   David Mayerich   added 2D convolut...
4
  #ifdef USING_OPENCV
dd5aab2f   David Mayerich   fixed errors in s...
5
6
7
  	//#include <opencv2/core/core.hpp>
  	//#include <opencv2/highgui/highgui.hpp>
  	#include <opencv2/opencv.hpp>
2e5e3a26   David Mayerich   added 2D convolut...
8
  #endif
912d9073   David Mayerich   added vector.h to...
9
  #include <vector>
d32a1854   David Mayerich   added framework f...
10
  #include <iostream>
a2bf1d08   David Mayerich   general bug fixes...
11
  #include <limits>
e252a6d6   David Mayerich   somehow the C++11...
12
  #include <typeinfo>
cfcf8619   David Mayerich   changes to filena...
13
  #include <fstream>
b4cea01a   David Mayerich   removed automated...
14
  #include <cstring>
6d30a707   Tianshu Cheng   add cuda/array_ad...
15
  
7b3948ab   David Mayerich   added support for...
16
  namespace stim{
c8c976a9   David Mayerich   replaced CImg wit...
17
18
  /// This static class provides the STIM interface for loading, saving, and storing 2D images.
  /// Data is stored in an interleaved (BIP) format (default for saving and loading is RGB).
d32a1854   David Mayerich   added framework f...
19
20
21
22
23
24
  
  //currently this interface uses CImg
  //	T = data type (usually unsigned char)
  template <class T>
  class image{
  
cfcf8619   David Mayerich   changes to filena...
25
  	T* img;										//pointer to the image data (interleaved RGB for color)
c8c976a9   David Mayerich   replaced CImg wit...
26
27
  	size_t R[3];
  
dbeb83f2   David Mayerich   added separable c...
28
29
30
  	inline size_t X() const { return R[1]; }
  	inline size_t Y() const { return R[2]; }
  	inline size_t C() const { return R[0]; }
c8c976a9   David Mayerich   replaced CImg wit...
31
  
c8c976a9   David Mayerich   replaced CImg wit...
32
33
34
35
36
37
38
  	void init(){								//initializes all variables, assumes no memory is allocated
  		memset(R, 0, sizeof(size_t) * 3);		//set the resolution and number of channels to zero
  		img = NULL;
  	}
  
  	void unalloc(){								//frees any resources associated with the image
  		if(img)	free(img);						//if memory has been allocated, free it
c8c976a9   David Mayerich   replaced CImg wit...
39
  	}
1a224b6a   David Mayerich   fixed linux compa...
40
  
c8c976a9   David Mayerich   replaced CImg wit...
41
42
43
44
45
46
47
  
  	void clear(){								//clears all image data
  		unalloc();								//unallocate previous memory
  		init();									//re-initialize the variables
  	}
  
  	void allocate(){
e9a1b974   Pavel Govyadinov   imlemented Dr. Ma...
48
  		unalloc();
814eb271   David Mayerich   fixed problems wi...
49
  		img = (T*) malloc( sizeof(T) * R[0] * R[1] * R[2] );	//allocate memory
c8c976a9   David Mayerich   replaced CImg wit...
50
51
52
  	}
  
  	void allocate(size_t x, size_t y, size_t c){	//allocate memory based on the resolution
c8c976a9   David Mayerich   replaced CImg wit...
53
54
55
56
  		R[0] = c; R[1] = x; R[2] = y;				//set the resolution
  		allocate();									//allocate memory
  	}
  
86dfa80b   David Mayerich   added 2D gaussian...
57
  	inline size_t idx(size_t x, size_t y, size_t c = 0) const {
dbeb83f2   David Mayerich   added separable c...
58
  		return y * R[0] * R[1] + x * R[0] + c;
c8c976a9   David Mayerich   replaced CImg wit...
59
  	}
1a224b6a   David Mayerich   fixed linux compa...
60
  
2e5e3a26   David Mayerich   added 2D convolut...
61
  #ifdef USING_OPENCV
c8c976a9   David Mayerich   replaced CImg wit...
62
  	int cv_type(){
e252a6d6   David Mayerich   somehow the C++11...
63
64
65
66
67
68
69
  		if(typeid(T) == typeid(unsigned char))		return CV_MAKETYPE(CV_8U, (int)C());
  		if(typeid(T) == typeid(char))				return CV_MAKETYPE(CV_8S, (int)C());
  		if(typeid(T) == typeid(unsigned short))		return CV_MAKETYPE(CV_16U, (int)C());
  		if(typeid(T) == typeid(short))				return CV_MAKETYPE(CV_16S, (int)C());
  		if(typeid(T) == typeid(int))				return CV_MAKETYPE(CV_32S, (int)C());
  		if(typeid(T) == typeid(float))				return CV_MAKETYPE(CV_32F, (int)C());
  		if(typeid(T) == typeid(double))				return CV_MAKETYPE(CV_64F, (int)C());
1a224b6a   David Mayerich   fixed linux compa...
70
  
c8c976a9   David Mayerich   replaced CImg wit...
71
  		std::cout<<"ERROR in stim::image::cv_type - no valid data type found"<<std::endl;
3ff136b3   David Mayerich   replaced C++11 co...
72
  		exit(1);
c8c976a9   David Mayerich   replaced CImg wit...
73
  	}
2e5e3a26   David Mayerich   added 2D convolut...
74
  #endif
a2bf1d08   David Mayerich   general bug fixes...
75
76
  	/// Returns the value for "white" based on the dynamic range (assumes white is 1.0 for floating point images)
  	T white(){
0129eeb3   David Mayerich   updated type chec...
77
  		return std::numeric_limits<T>::max();
a2bf1d08   David Mayerich   general bug fixes...
78
79
  	}
  
d32a1854   David Mayerich   added framework f...
80
81
82
  
  public:
  
a7ed4b2e   David Mayerich   ivote updates
83
84
  	size_t bytes() { return size() * sizeof(T); }
  
a2bf1d08   David Mayerich   general bug fixes...
85
  	/// Default constructor - creates an empty image object
814eb271   David Mayerich   fixed problems wi...
86
  	image(){ init(); }							//initialize all variables to zero, don't allocate any memory
7b3948ab   David Mayerich   added support for...
87
  
a2bf1d08   David Mayerich   general bug fixes...
88
  	/// Constructor with a filename - loads the specified file
c8c976a9   David Mayerich   replaced CImg wit...
89
  	image(std::string filename){				//constructor initialize the image with an image file
fba6e7e3   Pavel Govyadinov   fixed image.h bug...
90
  		init();
c8c976a9   David Mayerich   replaced CImg wit...
91
  		load(filename);
7b3948ab   David Mayerich   added support for...
92
93
  	}
  
c8c976a9   David Mayerich   replaced CImg wit...
94
  	/// Create a new image from scratch given a number of samples and channels
1a224b6a   David Mayerich   fixed linux compa...
95
  	image(size_t x, size_t y = 1, size_t c = 1){
e9a1b974   Pavel Govyadinov   imlemented Dr. Ma...
96
  		init();
a2bf1d08   David Mayerich   general bug fixes...
97
  		allocate(x, y, c);
c8c976a9   David Mayerich   replaced CImg wit...
98
  	}
f186dbda   Tianshu Cheng   header file for b...
99
  
a2bf1d08   David Mayerich   general bug fixes...
100
  	/// Create a new image with the data given in 'data'
c8c976a9   David Mayerich   replaced CImg wit...
101
  	image(T* data, size_t x, size_t y, size_t c = 1){
e9a1b974   Pavel Govyadinov   imlemented Dr. Ma...
102
  		init();
c8c976a9   David Mayerich   replaced CImg wit...
103
104
  		allocate(x, y, c);
  		memcpy(img, data, bytes());
41acaf5d   David Mayerich   added a CUDA Gaus...
105
106
  	}
  
a2bf1d08   David Mayerich   general bug fixes...
107
  	/// Copy constructor - duplicates an image object
814eb271   David Mayerich   fixed problems wi...
108
  	image(const stim::image<T>& I){
e9a1b974   Pavel Govyadinov   imlemented Dr. Ma...
109
  		init();
a2bf1d08   David Mayerich   general bug fixes...
110
  		allocate(I.X(), I.Y(), I.C());
a2bf1d08   David Mayerich   general bug fixes...
111
112
113
114
115
116
117
118
  		memcpy(img, I.img, bytes());
  	}
  
  	/// Destructor - clear memory
  	~image(){
  		free(img);
  	}
  
a7ed4b2e   David Mayerich   ivote updates
119
  	///Resize an image - this function looks like it hasn't been implemented
86dfa80b   David Mayerich   added 2D gaussian...
120
121
122
123
  	void resize(size_t x, size_t y, size_t c = 1) {
  		allocate(x, y, c);
  	}
  
735a2a24   David Mayerich   started testing o...
124
  	stim::image<T>& operator=(const stim::image<T>& I){
814eb271   David Mayerich   fixed problems wi...
125
  		init();
a2bf1d08   David Mayerich   general bug fixes...
126
127
128
129
130
131
132
  		if(&I == this)									//handle self-assignment
  			return *this;
  		allocate(I.X(), I.Y(), I.C());
  		memcpy(img, I.img, bytes());
  		return *this;
  	}
  
cfcf8619   David Mayerich   changes to filena...
133
134
  	//save a Netpbm file
  	void load_netpbm(std::string filename) {
683f216a   David Mayerich   fixed? Linux comp...
135
  		std::ifstream infile(filename.c_str(), std::ios::in | std::ios::binary);		//open an output file
cfcf8619   David Mayerich   changes to filena...
136
137
138
139
  		if (!infile) {
  			std::cout << "Error opening input file in image::load_netpbm()" << std::endl;
  			exit(1);
  		}
cfcf8619   David Mayerich   changes to filena...
140
  
2e5e3a26   David Mayerich   added 2D convolut...
141
142
  		size_t nc;													//allocate space for the number of channels
  		char format[2];												//allocate space to hold the image format tag
cfcf8619   David Mayerich   changes to filena...
143
  		infile.read(format, 2);										//read the image format tag
2e5e3a26   David Mayerich   added 2D convolut...
144
  		infile.seekg(1, std::ios::cur);								//skip the newline character
cfcf8619   David Mayerich   changes to filena...
145
146
147
148
149
  
  		if (format[0] != 'P') {
  			std::cout << "Error in image::load_netpbm() - file format tag is invalid: " << format[0] << format[1] << std::endl;
  			exit(1);
  		}
2e5e3a26   David Mayerich   added 2D convolut...
150
151
  		if (format[1] == '5') nc = 1;								//get the number of channels from the format flag
  		else if (format[1] == '6') nc = 3;
cfcf8619   David Mayerich   changes to filena...
152
153
154
155
  		else {
  			std::cout << "Error in image::load_netpbm() - file format tag is invalid: " << format[0] << format[1] << std::endl;
  			exit(1);
  		}
2e5e3a26   David Mayerich   added 2D convolut...
156
157
158
159
160
161
162
163
164
  
  		unsigned char c;								//stores a character
  		while (infile.peek() == '#') {					//if the next character indicates the start of a comment
  			while (true) {
  				c = infile.get();
  				if (c == 0x0A) break;
  			}
  		}
  
cfcf8619   David Mayerich   changes to filena...
165
  		std::string sw;									//create a string to store the width of the image
cfcf8619   David Mayerich   changes to filena...
166
167
168
169
170
171
172
173
174
175
176
177
178
  		while(true){
  			c = infile.get();							//get a single character
  			if (c == ' ') break;						//exit if we've encountered a space
  			sw.push_back(c);							//push the character on to the string
  		}
  		size_t w = atoi(sw.c_str());					//convert the string into an integer
  
  		std::string sh;
  		while (true) {
  			c = infile.get();
  			if (c == 0x0A) break;
  			sh.push_back(c);
  		}
cfcf8619   David Mayerich   changes to filena...
179
  
2e5e3a26   David Mayerich   added 2D convolut...
180
181
182
183
184
185
  		while (true) {									//skip the maximum value
  			c = infile.get();
  			if (c == 0x0A) break;
  		}
  		size_t h = atoi(sh.c_str());					//convert the string into an integer
  
01707489   David Mayerich   implemented a new...
186
187
188
189
190
191
  		allocate(w, h, nc);													//allocate space for the image
  		unsigned char* buffer = (unsigned char*)malloc(w * h * nc);			//create a buffer to store the read data
  		infile.read((char*)buffer, size());									//copy the binary data from the file to the image
  		infile.close();														//close the file
  		for (size_t n = 0; n < size(); n++) img[n] = (T)buffer[n];			//copy the buffer data into the image
  		free(buffer);														//free the buffer array
cfcf8619   David Mayerich   changes to filena...
192
193
194
  	}
  	
  
2e5e3a26   David Mayerich   added 2D convolut...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  #ifdef USING_OPENCV
  	void from_opencv(unsigned char* buffer, size_t width, size_t height) {
  		allocate(width, height, 3);
  		T value;
  		size_t i;
  		for (size_t c = 0; c < C(); c++) {								//copy directly
  			for (size_t y = 0; y < Y(); y++) {
  				for (size_t x = 0; x < X(); x++) {
  					i = y * X() * C() + x * C() + (2 - c);
  					value = buffer[i];
  					img[idx(x, y, c)] = value;
  				}
  			}
  		}
  	}
  #endif
c8c976a9   David Mayerich   replaced CImg wit...
211
  	/// Load an image from a file
d32a1854   David Mayerich   added framework f...
212
  	void load(std::string filename){
2e5e3a26   David Mayerich   added 2D convolut...
213
  #ifdef USING_OPENCV
c8c976a9   David Mayerich   replaced CImg wit...
214
  		cv::Mat cvImage = cv::imread(filename, CV_LOAD_IMAGE_UNCHANGED);	//use OpenCV to open the image file
a2bf1d08   David Mayerich   general bug fixes...
215
  		if(!cvImage.data){
814eb271   David Mayerich   fixed problems wi...
216
  			std::cout<<"ERROR stim::image::load() - unable to find image "<<filename<<std::endl;
a2bf1d08   David Mayerich   general bug fixes...
217
218
  			exit(1);
  		}
26da82c8   David Mayerich   finalized stim::g...
219
220
221
222
  		int cols = cvImage.cols;
  		int rows = cvImage.rows;
  		int channels = cvImage.channels();
  		allocate(cols, rows, channels);			//allocate space for the image
ca99f951   David Mayerich   faster implementa...
223
  		unsigned char* cv_ptr = (unsigned char*)cvImage.data;
814eb271   David Mayerich   fixed problems wi...
224
225
226
  		if(C() == 1)														//if this is a single-color image, just copy the data
  			memcpy(img, cv_ptr, bytes());
  		if(C() == 3)														//if this is a 3-color image, OpenCV uses BGR interleaving
ca99f951   David Mayerich   faster implementa...
227
  			from_opencv(cv_ptr, X(), Y());
2e5e3a26   David Mayerich   added 2D convolut...
228
229
230
  #else
  		load_netpbm(filename);
  #endif
ca99f951   David Mayerich   faster implementa...
231
232
  	}
  
2e5e3a26   David Mayerich   added 2D convolut...
233
  
d32a1854   David Mayerich   added framework f...
234
  
cfcf8619   David Mayerich   changes to filena...
235
236
  	//save a Netpbm file
  	void save_netpbm(std::string filename) {
683f216a   David Mayerich   fixed? Linux comp...
237
  		std::ofstream outfile(filename.c_str(), std::ios::out | std::ios::binary);		//open an output file
cfcf8619   David Mayerich   changes to filena...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  		if(!outfile) {
  			std::cout << "Error generating output file in image::save_netpbm()" << std::endl;
  			exit(1);
  		}
  		if (sizeof(T) != 1) {
  			std::cout << "Error in image::save_netpbm() - data type must be 8-bit integer." << std::endl;
  			exit(1);
  		}
  		std::string format;
  		if (channels() == 1) outfile << "P5" << (char)0x0A;			//output P5 if the file is grayscale
  		else if (channels() == 3) outfile << "P6" << (char)0x0A;		//output P6 if the file is color
  		else {
  			std::cout << "Error in image::save_netpbm() - data must be grayscale or RGB." << std::endl;
  			exit(1);
  		}
2e5e3a26   David Mayerich   added 2D convolut...
253
254
255
  		size_t w = width();
  		size_t h = height();
  		outfile << w << " " << h << (char)0x0A;			//save the width and height
cfcf8619   David Mayerich   changes to filena...
256
257
258
259
260
  		outfile << "255" << (char)0x0A;								//output the maximum value
  		outfile.write((const char*)img, size());			//write the binary data
  		outfile.close();
  	}
  
d32a1854   David Mayerich   added framework f...
261
262
  	//save a file
  	void save(std::string filename){
2e5e3a26   David Mayerich   added 2D convolut...
263
  #ifdef USING_OPENCV
c8c976a9   David Mayerich   replaced CImg wit...
264
265
  		//OpenCV uses an interleaved format, so convert first and then output
  		T* buffer = (T*) malloc(bytes());
a2bf1d08   David Mayerich   general bug fixes...
266
267
268
269
  
  		if(C() == 1)
  			memcpy(buffer, img, bytes());
  		else if(C() == 3)
9b766f1f   Pavel Govyadinov   completed merge f...
270
  			get_interleaved_bgr(buffer);
c8c976a9   David Mayerich   replaced CImg wit...
271
272
  		cv::Mat cvImage((int)Y(), (int)X(), cv_type(), buffer);
  		cv::imwrite(filename, cvImage);
efe7b7cc   Pavel Govyadinov   Added a detailed ...
273
  		free(buffer);
2e5e3a26   David Mayerich   added 2D convolut...
274
275
276
  #else
  		save_netpbm(filename);
  #endif
d32a1854   David Mayerich   added framework f...
277
278
  	}
  
ca99f951   David Mayerich   faster implementa...
279
280
281
282
283
  	void set_interleaved(T* buffer, size_t width, size_t height, size_t channels){
  		allocate(width, height, channels);
  		memcpy(img, buffer, bytes());
  	}
  
8b7be670   David Mayerich   implemented savin...
284
  	//create an image from an interleaved buffer
814eb271   David Mayerich   fixed problems wi...
285
  	void set_interleaved_rgb(T* buffer, size_t width, size_t height){
ca99f951   David Mayerich   faster implementa...
286
  		set_interleaved(buffer, width, height, 3);
c8c976a9   David Mayerich   replaced CImg wit...
287
  	}
fbf0ab02   David Mayerich   added support for...
288
  
814eb271   David Mayerich   fixed problems wi...
289
290
  	void set_interleaved_bgr(T* buffer, size_t width, size_t height){
  		allocate(width, height, 3);
ca99f951   David Mayerich   faster implementa...
291
292
  		T value;
  		size_t i;
c8c976a9   David Mayerich   replaced CImg wit...
293
294
295
  		for(size_t c = 0; c < C(); c++){								//copy directly
  			for(size_t y = 0; y < Y(); y++){
  				for(size_t x = 0; x < X(); x++){
ca99f951   David Mayerich   faster implementa...
296
297
298
  					i = y * X() * C() + x * C() + (2-c);
  					value = buffer[i];
  					img[idx(x, y, c)] = value;
c8c976a9   David Mayerich   replaced CImg wit...
299
  				}
fbf0ab02   David Mayerich   added support for...
300
301
  			}
  		}
8b7be670   David Mayerich   implemented savin...
302
303
  	}
  
ca99f951   David Mayerich   faster implementa...
304
305
306
307
  	void set_interleaved(T* buffer, size_t width, size_t height){
  		set_interleaved_rgb(buffer, width, height);
  	}
  
9b766f1f   Pavel Govyadinov   completed merge f...
308
  	void get_interleaved_bgr(T* data){
8b7be670   David Mayerich   implemented savin...
309
310
  
  		//for each channel
c8c976a9   David Mayerich   replaced CImg wit...
311
312
313
314
315
316
317
  		for(size_t y = 0; y < Y(); y++){
  			for(size_t x = 0; x < X(); x++){
  				for(size_t c = 0; c < C(); c++){
  					data[y * X() * C() + x * C() + (2-c)] = img[idx(x, y, c)];
  				}
  			}
  		}
8b7be670   David Mayerich   implemented savin...
318
319
  	}
  
9b766f1f   Pavel Govyadinov   completed merge f...
320
321
322
323
  	void get_interleaved_rgb(T* data){
  		memcpy(data, img, bytes());
  	}
  
904614c3   David Mayerich   added normalizati...
324
325
326
327
328
329
330
331
332
333
334
335
  	//copies data in the given channel order as a non-interleaved image
  	void get_noninterleaved(T* data){
  		//for each channel
  		for(size_t y = 0; y < Y(); y++){
  			for(size_t x = 0; x < X(); x++){
  				for(size_t c = 0; c < C(); c++){
  					data[c * Y() * X() + y * X() + x] = img[idx(x, y, c)];
  				}
  			}
  		}
  	}
  
dbeb83f2   David Mayerich   added separable c...
336
337
  	/// Return an image representing a specified channel
  	/// @param c is the channel to be returned
86dfa80b   David Mayerich   added 2D gaussian...
338
  	image<T> channel(size_t c) const {		
dbeb83f2   David Mayerich   added separable c...
339
  		image<T> r(X(), Y(), 1);				//create a new image
c8c976a9   David Mayerich   replaced CImg wit...
340
341
  		for(size_t x = 0; x < X(); x++){
  			for(size_t y = 0; y < Y(); y++){
8e2fb2b4   David Mayerich   fixed a segmentat...
342
  				r.img[r.idx(x, y, 0)] = img[idx(x, y, c)];
c8c976a9   David Mayerich   replaced CImg wit...
343
344
  			}
  		}
c8c976a9   David Mayerich   replaced CImg wit...
345
  		return r;
dbeb83f2   David Mayerich   added separable c...
346
347
348
  	}
  
  	/// Returns an std::vector containing each channel as a separate image
683f216a   David Mayerich   fixed? Linux comp...
349
350
  	std::vector< image<T> > split() const {
  		std::vector< image<T> > r;			//create an image array
dbeb83f2   David Mayerich   added separable c...
351
  		r.resize(C());						//create images for each channel
41acaf5d   David Mayerich   added a CUDA Gaus...
352
  
dbeb83f2   David Mayerich   added separable c...
353
354
355
356
  		for (size_t c = 0; c < C(); c++) {	//for each channel
  			r[c] = channel(c);				//copy the channel image to the array
  		}
  		return r;
41acaf5d   David Mayerich   added a CUDA Gaus...
357
358
  	}
  
86dfa80b   David Mayerich   added 2D gaussian...
359
  	/// Merge a series of single-channel images into a multi-channel image
683f216a   David Mayerich   fixed? Linux comp...
360
  	void merge(std::vector< image<T> >& list) {
86dfa80b   David Mayerich   added 2D gaussian...
361
362
363
364
365
366
367
  		size_t x = list[0].width();				//calculate the size of the image
  		size_t y = list[0].height();
  		allocate(x, y, list.size());			//re-allocate the image
  		for (size_t c = 0; c < list.size(); c++)		//for each channel
  			set_channel(list[c].channel(0).data(), c);	//insert the channel into the output image
  	}
  
c8c976a9   David Mayerich   replaced CImg wit...
368
369
  	T& operator()(size_t x, size_t y, size_t c = 0){
  		return img[idx(x, y, c)];
3d0b6243   David Mayerich   fixed hsiproc bug...
370
371
372
373
374
375
376
  	}
  
  	/// Set all elements in the image to a given scalar value
  
  	/// @param v is the value used to set all values in the image
  	image<T> operator=(T v){
  
c8c976a9   David Mayerich   replaced CImg wit...
377
  		size_t N = size();
3d0b6243   David Mayerich   fixed hsiproc bug...
378
  
c8c976a9   David Mayerich   replaced CImg wit...
379
380
  		for(size_t n = 0; n < N; n++)
  			img[n] = v;
3d0b6243   David Mayerich   fixed hsiproc bug...
381
382
383
384
385
  
  		return *this;
  
  	}
  
a7ed4b2e   David Mayerich   ivote updates
386
387
388
389
390
391
392
393
394
  	/// invert the image, given a specified maximum value (ex. maxval = 255, I' = 255 - I)
  	/*image<T> invert(T maxval) {
  		image<T> result(width(), height(), channels());		//create a new image
  		size_t N = size();									//get the number of elements in the image
  		for (size_t n = 0; n < N; n++)
  			result.data()[n] = maxval - img[n];				//perform the inversion and save the result to the new image
  		return result;
  	}*/
  
5bd6c411   David Mayerich   added contrast st...
395
396
397
398
399
400
401
402
403
404
  	/// Stretch the contrast of the image such that the minimum and maximum intensity match the given values
  	image<T> stretch(T low, T high) {
  		T maxval = maxv();
  		T minval = minv();
  		
  		image<T> result = *this;				//create a new image for output
  		size_t N = size();						//get the number of values in the image
  		double range = maxval - minval;			//calculate the current range of the image
  		double desired_range = high - low;		//calculate the desired range of the image
  		for (size_t n = 0; n < N; n++) {		//for each element in the image
ec0fdb47   Mahsa Lotfollahi   changes in stretc...
405
  			result.data()[n] = desired_range * (img[n] - minval) / range + low;
5bd6c411   David Mayerich   added contrast st...
406
407
408
409
  		}
  		return result;
  	}
  
70f0baaf   Laila Saadatifard   update the image....
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
  	/// Add a border of width w with the given value around the image
  	/// @param w specifies the total size of the border
  	/// @param T is the pixel value (all channels will be the same)
  	image<T> border(size_t w, T value = 0) {
  		image<T> result(width() + w * 2, height() + w * 2, channels());						//create an output image
  		result = value;														//assign the border value to all pixels in the new image
  		for (size_t y = 0; y < height(); y++) {								//for each pixel in the original image
  			for (size_t x = 0; x < width(); x++) {
  				size_t n = (y + w) * (width() + w * 2) + x + w;				//calculate the index of the corresponding pixel in the result image
  				size_t n0 = idx(x,y);										//calculate the index for this pixel in the original image
  				result.data()[n] = img[n0];									// copy the original image to the result image afer the border area
  			}
  		}
  		return result;
  	}
  
f186dbda   Tianshu Cheng   header file for b...
426
427
428
429
430
  	/// 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
  
c8c976a9   David Mayerich   replaced CImg wit...
431
  	void set_channel(T* buffer, size_t c){
6d30a707   Tianshu Cheng   add cuda/array_ad...
432
  
c8c976a9   David Mayerich   replaced CImg wit...
433
434
435
  		size_t x, y;
  		for(y = 0; y < Y(); y++){
  			for(x = 0; x < X(); x++){
2e5e3a26   David Mayerich   added 2D convolut...
436
  				img[idx(x, y, c)] = buffer[y * X() + x];
c8c976a9   David Mayerich   replaced CImg wit...
437
438
  			}
  		}
6d30a707   Tianshu Cheng   add cuda/array_ad...
439
440
  	}
  
86dfa80b   David Mayerich   added 2D gaussian...
441
  	size_t channels() const{
c8c976a9   David Mayerich   replaced CImg wit...
442
  		return C();
8b7be670   David Mayerich   implemented savin...
443
444
  	}
  
86dfa80b   David Mayerich   added 2D gaussian...
445
  	size_t width() const{
c8c976a9   David Mayerich   replaced CImg wit...
446
  		return X();
8b7be670   David Mayerich   implemented savin...
447
448
  	}
  
86dfa80b   David Mayerich   added 2D gaussian...
449
  	size_t height() const{
c8c976a9   David Mayerich   replaced CImg wit...
450
  		return Y();
3d0b6243   David Mayerich   fixed hsiproc bug...
451
452
  	}
  
6d30a707   Tianshu Cheng   add cuda/array_ad...
453
  	T* data(){
c8c976a9   David Mayerich   replaced CImg wit...
454
  		return img;
6d30a707   Tianshu Cheng   add cuda/array_ad...
455
456
  	}
  
7b3948ab   David Mayerich   added support for...
457
  	//returns the size (number of values) of the image
c8c976a9   David Mayerich   replaced CImg wit...
458
  	size_t size(){ return C() * X() * Y(); }
d32a1854   David Mayerich   added framework f...
459
  
faef7718   David Mayerich   updates to stim::...
460
  	/// Returns the number of nonzero values
9d3ba0b1   David Mayerich   added stim::hsi a...
461
  	size_t nnz(){
faef7718   David Mayerich   updates to stim::...
462
  
c8c976a9   David Mayerich   replaced CImg wit...
463
  		size_t N = X() * Y() * C();
faef7718   David Mayerich   updates to stim::...
464
  
c8c976a9   David Mayerich   replaced CImg wit...
465
466
467
  		size_t nz = 0;
  		for(size_t n = 0; n < N; n++)
  			if(img[n] != 0) nz++;
faef7718   David Mayerich   updates to stim::...
468
  
c8c976a9   David Mayerich   replaced CImg wit...
469
  		return nz;	//return the number of nonzero pixels
faef7718   David Mayerich   updates to stim::...
470
471
472
473
  
  	}
  
  	//this function returns indices of pixels that have nonzero values
9d3ba0b1   David Mayerich   added stim::hsi a...
474
  	std::vector<size_t> sparse_idx(){
faef7718   David Mayerich   updates to stim::...
475
  
c8c976a9   David Mayerich   replaced CImg wit...
476
  		std::vector<size_t> s;				//allocate an array
faef7718   David Mayerich   updates to stim::...
477
478
  		s.resize(nnz());					//allocate space in the array
  
c8c976a9   David Mayerich   replaced CImg wit...
479
480
  		size_t N = size();
  		//size_t C = channels();
faef7718   David Mayerich   updates to stim::...
481
  
c8c976a9   David Mayerich   replaced CImg wit...
482
  		//T* ptr = img.data();				//get a pointer to the image data
faef7718   David Mayerich   updates to stim::...
483
  
9d3ba0b1   David Mayerich   added stim::hsi a...
484
  		size_t i = 0;
c8c976a9   David Mayerich   replaced CImg wit...
485
486
487
488
  		for(size_t n = 0; n < N; n++){
  			if(img[n] != 0){
  				s[i] = n;
  				i++;
faef7718   David Mayerich   updates to stim::...
489
490
491
492
493
  			}
  		}
  
  		return s;			//return the index list
  	}
6d30a707   Tianshu Cheng   add cuda/array_ad...
494
  
1a224b6a   David Mayerich   fixed linux compa...
495
  
6d30a707   Tianshu Cheng   add cuda/array_ad...
496
  	/// Returns the maximum pixel value in the image
96f9b10f   Laila Saadatifard   change the header...
497
  	T maxv(){
c8c976a9   David Mayerich   replaced CImg wit...
498
499
  		T max_val = img[0];				//initialize the maximum value to the first one
  		size_t N = size();	//get the number of pixels
6d30a707   Tianshu Cheng   add cuda/array_ad...
500
  
c8c976a9   David Mayerich   replaced CImg wit...
501
  		for (size_t n=0; n<N; n++){		//for every value
6d30a707   Tianshu Cheng   add cuda/array_ad...
502
  
c8c976a9   David Mayerich   replaced CImg wit...
503
504
  			if (img[n] > max_val){			//if the value is higher than the current max
  				max_val = img[n];
1a224b6a   David Mayerich   fixed linux compa...
505
  			}
6d30a707   Tianshu Cheng   add cuda/array_ad...
506
  		}
1a224b6a   David Mayerich   fixed linux compa...
507
  		return max_val;
6d30a707   Tianshu Cheng   add cuda/array_ad...
508
  	}
d32a1854   David Mayerich   added framework f...
509
  
c8c976a9   David Mayerich   replaced CImg wit...
510
  	/// Returns the maximum pixel value in the image
96f9b10f   Laila Saadatifard   change the header...
511
  	T minv(){
c8c976a9   David Mayerich   replaced CImg wit...
512
513
  		T min_val = img[0];				//initialize the maximum value to the first one
  		size_t N = size();	//get the number of pixels
6d30a707   Tianshu Cheng   add cuda/array_ad...
514
  
c8c976a9   David Mayerich   replaced CImg wit...
515
516
517
  		for (size_t n=0; n<N; n++){		//for every value
  			if (img[n] < min_val){			//if the value is higher than the current max
  				min_val = img[n];
1a224b6a   David Mayerich   fixed linux compa...
518
  			}
6d30a707   Tianshu Cheng   add cuda/array_ad...
519
520
  		}
  
1a224b6a   David Mayerich   fixed linux compa...
521
  		return min_val;
6d30a707   Tianshu Cheng   add cuda/array_ad...
522
523
  	}
  
a2bf1d08   David Mayerich   general bug fixes...
524
525
526
527
528
529
  	/// Invert an image by calculating I1 = alpha - I0, where alpha is the maximum image value
  	image<T> invert(T white_val){
  		size_t N = size();						//calculate the total number of values in the image
  		image<T> r(X(), Y(), C());				//allocate space for the resulting image
  		for(size_t n = 0; n < N; n++)
  			r.img[n] = white_val - img[n];		//perform the inversion
1a224b6a   David Mayerich   fixed linux compa...
530
  
a2bf1d08   David Mayerich   general bug fixes...
531
532
  		return r;								//return the inverted image
  	}
a2bf1d08   David Mayerich   general bug fixes...
533
  
3c17c706   David Mayerich   added a crop func...
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  	image<T> crop(size_t x0, size_t y0, size_t w, size_t h){
  		image<T> result(w, h, C());								//create the output cropped image
  
  		size_t srci;
  		size_t dsti;
  		size_t line_bytes = w * C();							//calculate the number of bytes in a line
  		for (size_t yi = 0; yi < h; yi++) {						//for each row in the cropped image
  			srci = (y0 + yi) * X() * C() + x0 * C();			//calculate the source index
  			dsti = yi * w * C();								//calculate the destination index
  			memcpy(&result.img[dsti], &img[srci], line_bytes);	//copy the data
  		}
  		return result;
  	}
  
e702aa4e   David Mayerich   implemented array...
548
549
550
551
552
553
554
555
556
557
558
559
560
  	//crop regions given by an array of 1D index values
  	std::vector<image<T>> crop_idx(size_t w, size_t h, std::vector<size_t> idx) {
  		std::vector<image<T>> result(idx.size());										//create an array of image files to return
  		for (size_t i = 0; i < idx.size(); i++) {										//for each specified index point
  			size_t y = idx[i] / X();													//calculate the y coordinate from the 1D index (center of ROI)
  			size_t x = idx[i] - y * X();												//calculate the x coordinate (center of ROI)
  			y -= w / 2;																	//update x and y values to reflect the lower corner of the ROI
  			x -= h / 2;
  			result[i] = crop(x, y, w, h);												//get the cropped image and store it in the result array
  		}
  		return result;
  	}
  
6d30a707   Tianshu Cheng   add cuda/array_ad...
561
  	image<T> srgb2lab(){
c8c976a9   David Mayerich   replaced CImg wit...
562
563
  		std::cout<<"ERROR stim::image::srgb2lab - function has been broken, re-implement."<<std::endl;
  		exit(1);
6d30a707   Tianshu Cheng   add cuda/array_ad...
564
565
566
  	}
  
  	image<T> convolve2(image<T> mask){
c8c976a9   David Mayerich   replaced CImg wit...
567
568
  		std::cout<<"ERROR stim::image::convolve2 - function has been broken, and shouldn't really be in here."<<std::endl;
  		exit(1);
6d30a707   Tianshu Cheng   add cuda/array_ad...
569
  	}
d32a1854   David Mayerich   added framework f...
570
571
  
  
f186dbda   Tianshu Cheng   header file for b...
572
  	image<T> rotate(float angle, float cx, float cy){
c8c976a9   David Mayerich   replaced CImg wit...
573
574
  		std::cout<<"ERROR stim::image::rotate - function has been broken, and shouldn't really be in here."<<std::endl;
  		exit(1);
f186dbda   Tianshu Cheng   header file for b...
575
  	}
945ee13c   Laila Saadatifard   the get_list func...
576
  
945ee13c   Laila Saadatifard   the get_list func...
577
578
  	// leila's code for non_interleaving data in 3D
  	//create an data set from an interleaved buffer
9d3ba0b1   David Mayerich   added stim::hsi a...
579
  	void set_interleaved3(T* buffer, size_t width, size_t height, size_t depth, size_t channels = 3){
c8c976a9   David Mayerich   replaced CImg wit...
580
581
  		std::cout<<"ERROR stim::image::set_interleaved3 - stim::image no longer supports 3D images."<<std::endl;
  		exit(1);
945ee13c   Laila Saadatifard   the get_list func...
582
  	}
1a224b6a   David Mayerich   fixed linux compa...
583
  
dbeb83f2   David Mayerich   added separable c...
584
  	/// Casting operator, casts every value in an image to a different data type V
2e5e3a26   David Mayerich   added 2D convolut...
585
586
  	template<typename V>
  	operator image<V>() {
dbeb83f2   David Mayerich   added separable c...
587
588
589
  		image<V> r(X(), Y(), C());					//create a new image
  		std::copy(img, img + size(), r.data());		//copy and cast the data
  		return r;									//return the new image
2e5e3a26   David Mayerich   added 2D convolut...
590
591
  	}
  
d32a1854   David Mayerich   added framework f...
592
593
  };
  
7b3948ab   David Mayerich   added support for...
594
595
  };		//end namespace stim
  
d32a1854   David Mayerich   added framework f...
596
597
  
  #endif