Blame view

stim/image/image.h 9.4 KB
d32a1854   David Mayerich   added framework f...
1
2
  #ifndef STIM_IMAGE_H
  #define STIM_IMAGE_H
fbf0ab02   David Mayerich   added support for...
3
  
c8c976a9   David Mayerich   replaced CImg wit...
4
5
  #include <opencv2/core/core.hpp>
  #include <opencv2/highgui/highgui.hpp>
912d9073   David Mayerich   added vector.h to...
6
  #include <vector>
d32a1854   David Mayerich   added framework f...
7
  #include <iostream>
a2bf1d08   David Mayerich   general bug fixes...
8
  #include <limits>
6d30a707   Tianshu Cheng   add cuda/array_ad...
9
  
7b3948ab   David Mayerich   added support for...
10
  namespace stim{
c8c976a9   David Mayerich   replaced CImg wit...
11
12
  /// 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...
13
14
15
16
17
18
  
  //currently this interface uses CImg
  //	T = data type (usually unsigned char)
  template <class T>
  class image{
  
c8c976a9   David Mayerich   replaced CImg wit...
19
20
21
22
  	//cimg_library::CImg<T> img;
  	T* img;										//pointer to the image data (assumes RGB for loading/saving)
  	size_t R[3];
  
a2bf1d08   David Mayerich   general bug fixes...
23
24
25
  	size_t X() const { return R[1]; }
  	size_t Y() const { return R[2]; }
  	size_t C() const { return R[0]; }
c8c976a9   David Mayerich   replaced CImg wit...
26
27
28
29
30
31
32
33
34
  
  	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
  	}
1a224b6a   David Mayerich   fixed linux compa...
35
  
c8c976a9   David Mayerich   replaced CImg wit...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  
  	void clear(){								//clears all image data
  		unalloc();								//unallocate previous memory
  		init();									//re-initialize the variables
  	}
  
  	void allocate(){
  		img = (T*) malloc( sizeof(T) * R[0] * R[1] * R[2] );	//allocate memory
  	}
  
  	void allocate(size_t x, size_t y, size_t c){	//allocate memory based on the resolution
  		R[0] = c; R[1] = x; R[2] = y;				//set the resolution
  		allocate();									//allocate memory
  	}
  
  	size_t bytes(){ return size() * sizeof(T); }
  
  	size_t idx(size_t x, size_t y, size_t c = 0){
  		return y * C() * X() + x * C() + c;
  	}
1a224b6a   David Mayerich   fixed linux compa...
56
  
c8c976a9   David Mayerich   replaced CImg wit...
57
58
59
60
61
62
63
64
65
  
  	int cv_type(){
  		if(std::is_same<T, unsigned char>::value)	return CV_MAKETYPE(CV_8U, (int)C());
  		if(std::is_same<T, char>::value)			return CV_MAKETYPE(CV_8S, (int)C());
  		if(std::is_same<T, unsigned short>::value)	return CV_MAKETYPE(CV_16U, (int)C());
  		if(std::is_same<T, short>::value)			return CV_MAKETYPE(CV_16S, (int)C());
  		if(std::is_same<T, int>::value)				return CV_MAKETYPE(CV_32S, (int)C());
  		if(std::is_same<T, float>::value)			return CV_MAKETYPE(CV_32F, (int)C());
  		if(std::is_same<T, double>::value)			return CV_MAKETYPE(CV_64F, (int)C());
1a224b6a   David Mayerich   fixed linux compa...
66
  
c8c976a9   David Mayerich   replaced CImg wit...
67
68
69
70
  		std::cout<<"ERROR in stim::image::cv_type - no valid data type found"<<std::endl;
  		exit(1);
  	}
  
a2bf1d08   David Mayerich   general bug fixes...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  	/// Returns the value for "white" based on the dynamic range (assumes white is 1.0 for floating point images)
  	T white(){
  		if(std::is_same<T, unsigned char>::value)		return UCHAR_MAX;
  		if(std::is_same<T, unsigned short>::value)		return SHRT_MAX;
  		if(std::is_same<T, unsigned>::value)			return UINT_MAX;
  		if(std::is_same<T, unsigned long>::value)		return ULONG_MAX;
  		if(std::is_same<T, unsigned long long>::value)	return ULLONG_MAX;
  		if(std::is_same<T, float>::value)				return 1.0f;
  		if(std::is_same<T, double>::value)				return 1.0;
  
  		std::cout<<"ERROR in stim::image::white - no white value known for this data type"<<std::endl;
  
  	}
  
d32a1854   David Mayerich   added framework f...
85
86
87
  
  public:
  
a2bf1d08   David Mayerich   general bug fixes...
88
  	/// Default constructor - creates an empty image object
c8c976a9   David Mayerich   replaced CImg wit...
89
  	image(){ init(); }							//initialize all variables to zero, don't allocate any memory
7b3948ab   David Mayerich   added support for...
90
  
a2bf1d08   David Mayerich   general bug fixes...
91
  	/// Constructor with a filename - loads the specified file
c8c976a9   David Mayerich   replaced CImg wit...
92
93
  	image(std::string filename){				//constructor initialize the image with an image file
  		load(filename);
7b3948ab   David Mayerich   added support for...
94
95
  	}
  
c8c976a9   David Mayerich   replaced CImg wit...
96
  	/// Create a new image from scratch given a number of samples and channels
1a224b6a   David Mayerich   fixed linux compa...
97
  	image(size_t x, size_t y = 1, size_t c = 1){
a2bf1d08   David Mayerich   general bug fixes...
98
  		allocate(x, y, c);
c8c976a9   David Mayerich   replaced CImg wit...
99
  	}
f186dbda   Tianshu Cheng   header file for b...
100
  
a2bf1d08   David Mayerich   general bug fixes...
101
  	/// Create a new image with the data given in 'data'
c8c976a9   David Mayerich   replaced CImg wit...
102
103
104
  	image(T* data, size_t x, size_t y, size_t c = 1){
  		allocate(x, y, c);
  		memcpy(img, data, bytes());
41acaf5d   David Mayerich   added a CUDA Gaus...
105
106
  	}
  
a2bf1d08   David Mayerich   general bug fixes...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  	/// Copy constructor - duplicates an image object
  	image(const stim::image<T>& I){
  		allocate(I.X(), I.Y(), I.C());
  		//allocate(I.R[1], I.R[2], I.R[0]);
  		memcpy(img, I.img, bytes());
  	}
  
  	/// Destructor - clear memory
  	~image(){
  		free(img);
  	}
  
  	stim::image<T> operator=(const stim::image<T>& I){
  		if(&I == this)									//handle self-assignment
  			return *this;
  		allocate(I.X(), I.Y(), I.C());
  		memcpy(img, I.img, bytes());
  		return *this;
  	}
  
c8c976a9   David Mayerich   replaced CImg wit...
127
  	/// Load an image from a file
d32a1854   David Mayerich   added framework f...
128
  	void load(std::string filename){
c8c976a9   David Mayerich   replaced CImg wit...
129
130
  
  		cv::Mat cvImage = cv::imread(filename, CV_LOAD_IMAGE_UNCHANGED);	//use OpenCV to open the image file
a2bf1d08   David Mayerich   general bug fixes...
131
132
133
134
  		if(!cvImage.data){
  			std::cout<<"ERROR stim::image::load() - unable to find image "<<filename<<std::endl;
  			exit(1);
  		}
c8c976a9   David Mayerich   replaced CImg wit...
135
136
  		allocate(cvImage.cols, cvImage.rows, cvImage.channels());			//allocate space for the image
  		T* cv_ptr = (T*)cvImage.data;
a2bf1d08   David Mayerich   general bug fixes...
137
138
139
140
  		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
  			set_interleaved_bgr(cv_ptr, X(), Y());
d32a1854   David Mayerich   added framework f...
141
142
143
144
  	}
  
  	//save a file
  	void save(std::string filename){
c8c976a9   David Mayerich   replaced CImg wit...
145
146
  		//OpenCV uses an interleaved format, so convert first and then output
  		T* buffer = (T*) malloc(bytes());
a2bf1d08   David Mayerich   general bug fixes...
147
148
149
150
  
  		if(C() == 1)
  			memcpy(buffer, img, bytes());
  		else if(C() == 3)
9b766f1f   Pavel Govyadinov   completed merge f...
151
  			get_interleaved_bgr(buffer);
c8c976a9   David Mayerich   replaced CImg wit...
152
153
  		cv::Mat cvImage((int)Y(), (int)X(), cv_type(), buffer);
  		cv::imwrite(filename, cvImage);
d32a1854   David Mayerich   added framework f...
154
155
  	}
  
8b7be670   David Mayerich   implemented savin...
156
  	//create an image from an interleaved buffer
c8c976a9   David Mayerich   replaced CImg wit...
157
158
159
160
  	void set_interleaved_rgb(T* buffer, size_t width, size_t height){
  		allocate(width, height, 3);
  		memcpy(img, buffer, bytes());
  	}
fbf0ab02   David Mayerich   added support for...
161
  
c8c976a9   David Mayerich   replaced CImg wit...
162
163
164
165
166
167
168
  	void set_interleaved_bgr(T* buffer, size_t width, size_t height){
  		allocate(width, height, 3);
  		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++){
  					img[idx(x, y, c)] = buffer[y * X() * C() + x * C() + (2-c)];
  				}
fbf0ab02   David Mayerich   added support for...
169
170
  			}
  		}
8b7be670   David Mayerich   implemented savin...
171
172
  	}
  
9b766f1f   Pavel Govyadinov   completed merge f...
173
  	void get_interleaved_bgr(T* data){
8b7be670   David Mayerich   implemented savin...
174
175
  
  		//for each channel
c8c976a9   David Mayerich   replaced CImg wit...
176
177
178
179
180
181
182
  		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...
183
184
  	}
  
9b766f1f   Pavel Govyadinov   completed merge f...
185
186
187
188
189
  	void get_interleaved_rgb(T* data){
  		memcpy(data, img, bytes());
  	}
  
  
9d3ba0b1   David Mayerich   added stim::hsi a...
190
  	image<T> channel(size_t c){
41acaf5d   David Mayerich   added a CUDA Gaus...
191
192
  
  		//create a new image
a2bf1d08   David Mayerich   general bug fixes...
193
  		image<T> r(X(), Y(), 1);
41acaf5d   David Mayerich   added a CUDA Gaus...
194
  
c8c976a9   David Mayerich   replaced CImg wit...
195
196
197
198
199
  		for(size_t x = 0; x < X(); x++){
  			for(size_t y = 0; y < Y(); y++){
  				r.img[r.idx(x, y, c)] = img[idx(x, y, c)];
  			}
  		}
41acaf5d   David Mayerich   added a CUDA Gaus...
200
  
c8c976a9   David Mayerich   replaced CImg wit...
201
  		return r;
41acaf5d   David Mayerich   added a CUDA Gaus...
202
203
204
  
  	}
  
c8c976a9   David Mayerich   replaced CImg wit...
205
206
  	T& operator()(size_t x, size_t y, size_t c = 0){
  		return img[idx(x, y, c)];
3d0b6243   David Mayerich   fixed hsiproc bug...
207
208
209
210
211
212
213
  	}
  
  	/// 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...
214
  		size_t N = size();
3d0b6243   David Mayerich   fixed hsiproc bug...
215
  
c8c976a9   David Mayerich   replaced CImg wit...
216
217
  		for(size_t n = 0; n < N; n++)
  			img[n] = v;
3d0b6243   David Mayerich   fixed hsiproc bug...
218
219
220
221
222
  
  		return *this;
  
  	}
  
f186dbda   Tianshu Cheng   header file for b...
223
224
225
226
227
  	/// 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...
228
  	void set_channel(T* buffer, size_t c){
6d30a707   Tianshu Cheng   add cuda/array_ad...
229
  
c8c976a9   David Mayerich   replaced CImg wit...
230
231
232
233
234
235
  		size_t x, y;
  		for(y = 0; y < Y(); y++){
  			for(x = 0; x < X(); x++){
  				img[idx(x, y, c)] = buffer[c];
  			}
  		}
6d30a707   Tianshu Cheng   add cuda/array_ad...
236
237
  	}
  
9d3ba0b1   David Mayerich   added stim::hsi a...
238
  	size_t channels(){
c8c976a9   David Mayerich   replaced CImg wit...
239
  		return C();
8b7be670   David Mayerich   implemented savin...
240
241
  	}
  
9d3ba0b1   David Mayerich   added stim::hsi a...
242
  	size_t width(){
c8c976a9   David Mayerich   replaced CImg wit...
243
  		return X();
8b7be670   David Mayerich   implemented savin...
244
245
  	}
  
9d3ba0b1   David Mayerich   added stim::hsi a...
246
  	size_t height(){
c8c976a9   David Mayerich   replaced CImg wit...
247
  		return Y();
3d0b6243   David Mayerich   fixed hsiproc bug...
248
249
  	}
  
6d30a707   Tianshu Cheng   add cuda/array_ad...
250
  	T* data(){
c8c976a9   David Mayerich   replaced CImg wit...
251
  		return img;
6d30a707   Tianshu Cheng   add cuda/array_ad...
252
253
  	}
  
7b3948ab   David Mayerich   added support for...
254
  	//returns the size (number of values) of the image
c8c976a9   David Mayerich   replaced CImg wit...
255
  	size_t size(){ return C() * X() * Y(); }
d32a1854   David Mayerich   added framework f...
256
  
faef7718   David Mayerich   updates to stim::...
257
  	/// Returns the number of nonzero values
9d3ba0b1   David Mayerich   added stim::hsi a...
258
  	size_t nnz(){
faef7718   David Mayerich   updates to stim::...
259
  
c8c976a9   David Mayerich   replaced CImg wit...
260
  		size_t N = X() * Y() * C();
faef7718   David Mayerich   updates to stim::...
261
  
c8c976a9   David Mayerich   replaced CImg wit...
262
263
264
  		size_t nz = 0;
  		for(size_t n = 0; n < N; n++)
  			if(img[n] != 0) nz++;
faef7718   David Mayerich   updates to stim::...
265
  
c8c976a9   David Mayerich   replaced CImg wit...
266
  		return nz;	//return the number of nonzero pixels
faef7718   David Mayerich   updates to stim::...
267
268
269
270
  
  	}
  
  	//this function returns indices of pixels that have nonzero values
9d3ba0b1   David Mayerich   added stim::hsi a...
271
  	std::vector<size_t> sparse_idx(){
faef7718   David Mayerich   updates to stim::...
272
  
c8c976a9   David Mayerich   replaced CImg wit...
273
  		std::vector<size_t> s;				//allocate an array
faef7718   David Mayerich   updates to stim::...
274
275
  		s.resize(nnz());					//allocate space in the array
  
c8c976a9   David Mayerich   replaced CImg wit...
276
277
  		size_t N = size();
  		//size_t C = channels();
faef7718   David Mayerich   updates to stim::...
278
  
c8c976a9   David Mayerich   replaced CImg wit...
279
  		//T* ptr = img.data();				//get a pointer to the image data
faef7718   David Mayerich   updates to stim::...
280
  
9d3ba0b1   David Mayerich   added stim::hsi a...
281
  		size_t i = 0;
c8c976a9   David Mayerich   replaced CImg wit...
282
283
284
285
  		for(size_t n = 0; n < N; n++){
  			if(img[n] != 0){
  				s[i] = n;
  				i++;
faef7718   David Mayerich   updates to stim::...
286
287
288
289
290
  			}
  		}
  
  		return s;			//return the index list
  	}
6d30a707   Tianshu Cheng   add cuda/array_ad...
291
  
1a224b6a   David Mayerich   fixed linux compa...
292
  
6d30a707   Tianshu Cheng   add cuda/array_ad...
293
  	/// Returns the maximum pixel value in the image
96f9b10f   Laila Saadatifard   change the header...
294
  	T maxv(){
c8c976a9   David Mayerich   replaced CImg wit...
295
296
  		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...
297
  
c8c976a9   David Mayerich   replaced CImg wit...
298
  		for (size_t n=0; n<N; n++){		//for every value
6d30a707   Tianshu Cheng   add cuda/array_ad...
299
  
c8c976a9   David Mayerich   replaced CImg wit...
300
301
  			if (img[n] > max_val){			//if the value is higher than the current max
  				max_val = img[n];
1a224b6a   David Mayerich   fixed linux compa...
302
  			}
6d30a707   Tianshu Cheng   add cuda/array_ad...
303
304
  		}
  
1a224b6a   David Mayerich   fixed linux compa...
305
  		return max_val;
6d30a707   Tianshu Cheng   add cuda/array_ad...
306
  	}
d32a1854   David Mayerich   added framework f...
307
  
c8c976a9   David Mayerich   replaced CImg wit...
308
  	/// Returns the maximum pixel value in the image
96f9b10f   Laila Saadatifard   change the header...
309
  	T minv(){
c8c976a9   David Mayerich   replaced CImg wit...
310
311
  		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...
312
  
c8c976a9   David Mayerich   replaced CImg wit...
313
314
315
  		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...
316
  			}
6d30a707   Tianshu Cheng   add cuda/array_ad...
317
318
  		}
  
1a224b6a   David Mayerich   fixed linux compa...
319
  		return min_val;
6d30a707   Tianshu Cheng   add cuda/array_ad...
320
321
  	}
  
a2bf1d08   David Mayerich   general bug fixes...
322
323
324
325
326
327
  	/// 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...
328
  
a2bf1d08   David Mayerich   general bug fixes...
329
330
331
  		return r;								//return the inverted image
  	}
  
6d30a707   Tianshu Cheng   add cuda/array_ad...
332
  	image<T> srgb2lab(){
c8c976a9   David Mayerich   replaced CImg wit...
333
334
  		std::cout<<"ERROR stim::image::srgb2lab - function has been broken, re-implement."<<std::endl;
  		exit(1);
6d30a707   Tianshu Cheng   add cuda/array_ad...
335
336
337
  	}
  
  	image<T> convolve2(image<T> mask){
1a224b6a   David Mayerich   fixed linux compa...
338
  
c8c976a9   David Mayerich   replaced CImg wit...
339
340
  		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...
341
  	}
d32a1854   David Mayerich   added framework f...
342
343
  
  
f186dbda   Tianshu Cheng   header file for b...
344
  	image<T> rotate(float angle, float cx, float cy){
c8c976a9   David Mayerich   replaced CImg wit...
345
346
  		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...
347
  	}
945ee13c   Laila Saadatifard   the get_list func...
348
349
350
  
  	// leila's code for non_interleaving data in 3D
  	//create an data set from an interleaved buffer
9d3ba0b1   David Mayerich   added stim::hsi a...
351
  	void set_interleaved3(T* buffer, size_t width, size_t height, size_t depth, size_t channels = 3){
c8c976a9   David Mayerich   replaced CImg wit...
352
353
  		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...
354
  	}
1a224b6a   David Mayerich   fixed linux compa...
355
  
d32a1854   David Mayerich   added framework f...
356
357
  };
  
7b3948ab   David Mayerich   added support for...
358
359
  };		//end namespace stim
  
d32a1854   David Mayerich   added framework f...
360
361
  
  #endif