Blame view

stim/image/image.h 9.71 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
  	void get_interleaved_rgb(T* data){
  		memcpy(data, img, bytes());
  	}
  
904614c3   David Mayerich   added normalizati...
189
190
191
192
193
194
195
196
197
198
199
200
  	//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)];
  				}
  			}
  		}
  	}
  
9b766f1f   Pavel Govyadinov   completed merge f...
201
  
9d3ba0b1   David Mayerich   added stim::hsi a...
202
  	image<T> channel(size_t c){
41acaf5d   David Mayerich   added a CUDA Gaus...
203
204
  
  		//create a new image
a2bf1d08   David Mayerich   general bug fixes...
205
  		image<T> r(X(), Y(), 1);
41acaf5d   David Mayerich   added a CUDA Gaus...
206
  
c8c976a9   David Mayerich   replaced CImg wit...
207
208
209
210
211
  		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...
212
  
c8c976a9   David Mayerich   replaced CImg wit...
213
  		return r;
41acaf5d   David Mayerich   added a CUDA Gaus...
214
215
216
  
  	}
  
c8c976a9   David Mayerich   replaced CImg wit...
217
218
  	T& operator()(size_t x, size_t y, size_t c = 0){
  		return img[idx(x, y, c)];
3d0b6243   David Mayerich   fixed hsiproc bug...
219
220
221
222
223
224
225
  	}
  
  	/// 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...
226
  		size_t N = size();
3d0b6243   David Mayerich   fixed hsiproc bug...
227
  
c8c976a9   David Mayerich   replaced CImg wit...
228
229
  		for(size_t n = 0; n < N; n++)
  			img[n] = v;
3d0b6243   David Mayerich   fixed hsiproc bug...
230
231
232
233
234
  
  		return *this;
  
  	}
  
f186dbda   Tianshu Cheng   header file for b...
235
236
237
238
239
  	/// 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...
240
  	void set_channel(T* buffer, size_t c){
6d30a707   Tianshu Cheng   add cuda/array_ad...
241
  
c8c976a9   David Mayerich   replaced CImg wit...
242
243
244
245
246
247
  		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...
248
249
  	}
  
9d3ba0b1   David Mayerich   added stim::hsi a...
250
  	size_t channels(){
c8c976a9   David Mayerich   replaced CImg wit...
251
  		return C();
8b7be670   David Mayerich   implemented savin...
252
253
  	}
  
9d3ba0b1   David Mayerich   added stim::hsi a...
254
  	size_t width(){
c8c976a9   David Mayerich   replaced CImg wit...
255
  		return X();
8b7be670   David Mayerich   implemented savin...
256
257
  	}
  
9d3ba0b1   David Mayerich   added stim::hsi a...
258
  	size_t height(){
c8c976a9   David Mayerich   replaced CImg wit...
259
  		return Y();
3d0b6243   David Mayerich   fixed hsiproc bug...
260
261
  	}
  
6d30a707   Tianshu Cheng   add cuda/array_ad...
262
  	T* data(){
c8c976a9   David Mayerich   replaced CImg wit...
263
  		return img;
6d30a707   Tianshu Cheng   add cuda/array_ad...
264
265
  	}
  
7b3948ab   David Mayerich   added support for...
266
  	//returns the size (number of values) of the image
c8c976a9   David Mayerich   replaced CImg wit...
267
  	size_t size(){ return C() * X() * Y(); }
d32a1854   David Mayerich   added framework f...
268
  
faef7718   David Mayerich   updates to stim::...
269
  	/// Returns the number of nonzero values
9d3ba0b1   David Mayerich   added stim::hsi a...
270
  	size_t nnz(){
faef7718   David Mayerich   updates to stim::...
271
  
c8c976a9   David Mayerich   replaced CImg wit...
272
  		size_t N = X() * Y() * C();
faef7718   David Mayerich   updates to stim::...
273
  
c8c976a9   David Mayerich   replaced CImg wit...
274
275
276
  		size_t nz = 0;
  		for(size_t n = 0; n < N; n++)
  			if(img[n] != 0) nz++;
faef7718   David Mayerich   updates to stim::...
277
  
c8c976a9   David Mayerich   replaced CImg wit...
278
  		return nz;	//return the number of nonzero pixels
faef7718   David Mayerich   updates to stim::...
279
280
281
282
  
  	}
  
  	//this function returns indices of pixels that have nonzero values
9d3ba0b1   David Mayerich   added stim::hsi a...
283
  	std::vector<size_t> sparse_idx(){
faef7718   David Mayerich   updates to stim::...
284
  
c8c976a9   David Mayerich   replaced CImg wit...
285
  		std::vector<size_t> s;				//allocate an array
faef7718   David Mayerich   updates to stim::...
286
287
  		s.resize(nnz());					//allocate space in the array
  
c8c976a9   David Mayerich   replaced CImg wit...
288
289
  		size_t N = size();
  		//size_t C = channels();
faef7718   David Mayerich   updates to stim::...
290
  
c8c976a9   David Mayerich   replaced CImg wit...
291
  		//T* ptr = img.data();				//get a pointer to the image data
faef7718   David Mayerich   updates to stim::...
292
  
9d3ba0b1   David Mayerich   added stim::hsi a...
293
  		size_t i = 0;
c8c976a9   David Mayerich   replaced CImg wit...
294
295
296
297
  		for(size_t n = 0; n < N; n++){
  			if(img[n] != 0){
  				s[i] = n;
  				i++;
faef7718   David Mayerich   updates to stim::...
298
299
300
301
302
  			}
  		}
  
  		return s;			//return the index list
  	}
6d30a707   Tianshu Cheng   add cuda/array_ad...
303
  
1a224b6a   David Mayerich   fixed linux compa...
304
  
6d30a707   Tianshu Cheng   add cuda/array_ad...
305
  	/// Returns the maximum pixel value in the image
96f9b10f   Laila Saadatifard   change the header...
306
  	T maxv(){
c8c976a9   David Mayerich   replaced CImg wit...
307
308
  		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...
309
  
c8c976a9   David Mayerich   replaced CImg wit...
310
  		for (size_t n=0; n<N; n++){		//for every value
6d30a707   Tianshu Cheng   add cuda/array_ad...
311
  
c8c976a9   David Mayerich   replaced CImg wit...
312
313
  			if (img[n] > max_val){			//if the value is higher than the current max
  				max_val = img[n];
1a224b6a   David Mayerich   fixed linux compa...
314
  			}
6d30a707   Tianshu Cheng   add cuda/array_ad...
315
316
  		}
  
1a224b6a   David Mayerich   fixed linux compa...
317
  		return max_val;
6d30a707   Tianshu Cheng   add cuda/array_ad...
318
  	}
d32a1854   David Mayerich   added framework f...
319
  
c8c976a9   David Mayerich   replaced CImg wit...
320
  	/// Returns the maximum pixel value in the image
96f9b10f   Laila Saadatifard   change the header...
321
  	T minv(){
c8c976a9   David Mayerich   replaced CImg wit...
322
323
  		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...
324
  
c8c976a9   David Mayerich   replaced CImg wit...
325
326
327
  		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...
328
  			}
6d30a707   Tianshu Cheng   add cuda/array_ad...
329
330
  		}
  
1a224b6a   David Mayerich   fixed linux compa...
331
  		return min_val;
6d30a707   Tianshu Cheng   add cuda/array_ad...
332
333
  	}
  
a2bf1d08   David Mayerich   general bug fixes...
334
335
336
337
338
339
  	/// 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...
340
  
a2bf1d08   David Mayerich   general bug fixes...
341
342
343
  		return r;								//return the inverted image
  	}
  
6d30a707   Tianshu Cheng   add cuda/array_ad...
344
  	image<T> srgb2lab(){
c8c976a9   David Mayerich   replaced CImg wit...
345
346
  		std::cout<<"ERROR stim::image::srgb2lab - function has been broken, re-implement."<<std::endl;
  		exit(1);
6d30a707   Tianshu Cheng   add cuda/array_ad...
347
348
349
  	}
  
  	image<T> convolve2(image<T> mask){
1a224b6a   David Mayerich   fixed linux compa...
350
  
c8c976a9   David Mayerich   replaced CImg wit...
351
352
  		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...
353
  	}
d32a1854   David Mayerich   added framework f...
354
355
  
  
f186dbda   Tianshu Cheng   header file for b...
356
  	image<T> rotate(float angle, float cx, float cy){
c8c976a9   David Mayerich   replaced CImg wit...
357
358
  		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...
359
  	}
945ee13c   Laila Saadatifard   the get_list func...
360
361
362
  
  	// leila's code for non_interleaving data in 3D
  	//create an data set from an interleaved buffer
9d3ba0b1   David Mayerich   added stim::hsi a...
363
  	void set_interleaved3(T* buffer, size_t width, size_t height, size_t depth, size_t channels = 3){
c8c976a9   David Mayerich   replaced CImg wit...
364
365
  		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...
366
  	}
1a224b6a   David Mayerich   fixed linux compa...
367
  
d32a1854   David Mayerich   added framework f...
368
369
  };
  
7b3948ab   David Mayerich   added support for...
370
371
  };		//end namespace stim
  
d32a1854   David Mayerich   added framework f...
372
373
  
  #endif