image_stack.h
5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#ifndef STIM_IMAGE_STACK_H
#define STIM_IMAGE_STACK_H
#include <stim/parser/wildcards.h>
#include <stim/parser/filename.h>
#include <stim/grids/grid.h>
#include <stim/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, typename F = float>
class image_stack : public virtual stim::grid<T, 4, F>{
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>::read;
public:
//default constructor
image_stack() : grid<T, 4>() {
}
/// Overloads grid::samples() to return the number of samples associated with a given spatial dimension
/// this is necessary because R[0] stores the color
size_t samples(size_t d){
return grid<T, 4, F>::samples(d + 1);
}
size_t samples(){
return R[1] * R[2] * R[3]; //return the number of spatial samples
}
/// Returns the number of color channels
size_t channels(){
return R[0];
}
/// Overloads grid::size() to return the size of the grid associated with a given spatial dimension
F size(size_t d){
return grid<T, 4, F>::size(d + 1);
}
/// Sets the spacing between samples in the image stack
void spacing(F sx, F sy, F sz){
grid<T, 4, F>::S[1] = sx; //set the sample spacing for the appropriate spatial dimension
grid<T, 4, F>::S[2] = sy;
grid<T, 4, F>::S[3] = sz;
}
F spacing(size_t d){
return grid<T, 4, F>::spacing(d + 1);
}
/// Overloads the spacing parameter to set the size of the grid associated with a given spatial dimension
//void spacing(F sx, F sy = 1.0f, F sz = 1.0f){
// grid<T, 4, F>::spacing((F)1.0, sx, sy, sz);
//}
///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);
//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
stim::image<T> I(file_list[0].str());
//set the image resolution and number of channels
R[0] = I.channels();
R[1] = I.width();
R[2] = I.height();
R[3] = 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++){
stim::image<T> I(file_list[i].str()); //load the image
I.get_interleaved_rgb(&ptr[ i * R[0] * R[1] * R[2] ]); //retrieve the interlaced data from the image - store it in the grid
}
}
///Inserts image I into slot i.
/// @param stim::image<T> I; image to insert.
/// @int I, where to place the image.
void insert_image(stim::image<T> I, int i){
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){
stim::image<T> I; //create an image
I.set_interleaved_rgb(&ptr[ i * R[0] * R[1] * R[2] ], R[1], R[2], R[0]); //retrieve the interlaced data from the image - store it in the grid
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;
}
///set dimensions of the grid.
/// @param channels, number of channels in each image.
/// @param width, number of pixels in width each image.
/// @param height, number of pixels in height.
/// @param depth, number of pixels in depth.
void init(int channels, int width, int height, int depth)
{
R.resize(4);
R[0] = channels;
R[1] = width;
R[2] = height;
R[3] = depth;
ptr = (T*)malloc(sizeof(T) * samples());
}
///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);
//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