mosaic.cpp
7.17 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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#include "stim/parser/filename.h"
#include "stim/envi/envi.h"
#include "stim/visualization/colormap.h"
#include "stim/envi/agilent_binary.h"
#include <thread>
void progress_thread_double(double* e); //progress bar threaded function
void mosaic_coord(unsigned int &x, unsigned int &y, stim::filename dmd_filename){
//get the file prefix
std::string prefix = dmd_filename.get_prefix();
//these files are in the format:
// ???????????_xxxxx_yyyyy.dmd
//first find the x coordinate
//find the position of the last underscore
size_t y_start = prefix.find_last_of("_");
//remove all values between x_start and the end of the string
std::string y_string = prefix.substr(y_start + 1);
y = atoi(y_string.c_str());
//crop out the x coordinate and the last underscore
prefix = prefix.substr(0, y_start);
//find the y coordinate using the same method as above
size_t x_start = prefix.find_last_of("_");
std::string x_string = prefix.substr(x_start + 1);
x = atoi(x_string.c_str());
}
//Use the file list to find the number of tiles along each dimension of the mosaic
void mosaic_size(unsigned int &sx, unsigned int &sy, std::vector<stim::filename> dmd_list){
sx = sy = 0;
unsigned int xi, yi;
//for each dmd file
for(unsigned int i = 0; i < dmd_list.size(); i++){
//find the coordinate of the tile represented by this file
mosaic_coord(xi, yi, dmd_list[i]);
//if the coordinate is larger than the current max, store it as the current max
if(xi > sx) sx = xi;
if(yi > sy) sy = yi;
}
//add 1 to reflect that the indexing starts at 0
sx++; sy++;
}
void mosaic_agilent(std::string filemask, std::string outfile, size_t &X, size_t &Y, size_t &B){
double progress = 0;
std::thread t1(progress_thread_double, &progress); //start the progress bar thread
//generate a list of tile files
stim::filename f = filemask; //create a filename from the specified file mask
if(!f.wildcards()) //if the file name doesn't contain wildcards
f = filemask + "/*.dmd"; //default to files of type DMD (generally used as agilent mosaic tiles) }
std::vector<stim::filename> tile_list = f.get_list(); //create a list of tile files
stim::agilent_binary<float> binfile(tile_list[0]); //load the first agilent binary file
size_t detector_size = binfile.dim(0); //get the detector size
std::cout<<"Building a mosaic with a detector size of "<<detector_size<<std::endl;
//calculate the mosaic size
unsigned int mx, my;
mosaic_size(mx, my, tile_list);
std::cout<<"Mosaic size: "<<mx<<" "<<my<<std::endl;
//if(create_header){ //if a header has to be created
std::ifstream in(tile_list[0].str().c_str(), std::ifstream::ate | std::ifstream::binary); //open the first dmd
size_t file_size = in.tellg(); //get the size of the file
B = (file_size - 1020) / (sizeof(float) * detector_size * detector_size); //estimate the number of bands by dividing by the frame size
//}
//else{
//f = f.path() + "/*.hdr"; //create a mask for the header file (the name is unknown)
//std::vector<stim::filename> hdr_list = f.get_list(); //allocate space for a list of headers that match this pattern
//if(hdr_list.size() == 0){ //throw an error of a header doesn't exist
// std::cout<<"No ENVI header file found. A header file created with Resolutions Pro (export ENVI) provides useful wavelength information. If one is unavailable, use the --create-header option to estimate these properties and create a minimal header file."<<std::endl;
// exit(1);
//}
//std::cout<<"First header name: "<<hdr_list[0].str()<<std::endl;
//open the representative ENVI header file (this should be the header for the thumbnail produced by Resolutions Pro)
//header.load(hdr_list[0].str());
//}
//change the header dimensions to reflect the detector size
// this corresponds to the size of the tile along X and Y
stim::envi_header header; //allocate space for an ENVI header
header.samples = detector_size;
header.lines = detector_size;
header.bands = B;
header.header_offset = 1020; //Agilent binary files have a 1020 byte header
//create a list of ENVI file structures
std::vector<stim::envi> envi_list;
envi_list.resize(mx * my); //set the length to the number of tiles
//open each tile
for(unsigned int m = 0; m < mx * my; m++){
envi_list[m].open(tile_list[m].str(), header);
envi_list[m].close();
}
//calculate the size of a single band of the mosaic
X = mx * detector_size; //number of samples
Y = my * detector_size; //number of lines
size_t type_size = envi_list[0].type_size(); //byte size of the data type
size_t tile_width = detector_size * type_size; //byte size of a tile
size_t band_width = X * type_size; //byte width of the band image
size_t band_size = band_width * Y; //size of the band in bytes
//allocate space for a single band of the mosaic
char* band = (char*)malloc(band_size);
//allocate space for a single tile of the mosaic
char* tile_band = (char*)malloc(detector_size * detector_size * type_size);
//open a binary file for writing
std::ofstream outstream(outfile.c_str(), std::ios::out|std::ios::binary);
//***********Combine Tiles into a Band Image**********************
//for each band
for(size_t b = 0; b < B; b++){
//unsigned int b = 0;
//for each tile along y
for(size_t yt = 0; yt < my; yt++){
//for each tile along x
for(size_t xt = 0; xt < mx; xt++){
envi_list[xt * my + yt].open(); //open the file for reading (windows has a max # of open files)
envi_list[xt * my + yt].band_index((void*)tile_band, b); //load the tile image
envi_list[xt * my + yt].close(); //close the file
size_t x_idx = xt * tile_width; //calculate the position of this line along x in the output image
//for each line along y
for(size_t y = 0; y < detector_size; y++){
size_t y_idx = ((my-1) - yt) * detector_size + y; //calculate the position of this line along y
//calculate the position of this line in the output image
size_t dst_i = y_idx * band_width + x_idx;
size_t src_i = y * tile_width;
memcpy(band + dst_i, tile_band + src_i, tile_width);
}
}
}
outstream.write(band, band_size);
progress = (double)(b + 1) / header.bands * 100;
}
progress = 100;
//close the binary file
outstream.close();
//free the memory allocated for the tile and output bands
free(tile_band);
free(band);
//update and save the header
//header.samples = X;
//header.lines = Y;
//header.header_offset = 0; //the final output doesn't have an offset
//header.save(outfile + ".hdr");
t1.join(); //wait for the progress bar thread to finish (it probably already is)
}
void mosaic_agilent_spectrum(){
}
void mosaic_agilent_interferogram(std::string filemask, std::string outfile, double ELWN, int UDR){
size_t X, Y, B; //store the size of the mosaic
mosaic_agilent(filemask, outfile, X, Y, B); //generate the mosaic
//create the header
stim::envi_header header;
header.samples = X;
header.lines = Y;
header.bands = B;
double int_delta = (1.0 / ELWN) * ((double)UDR / 2.0); //calculate the interferogram spacing
header.set_wavelengths(0, int_delta);
header.wavelength_units = "centimeters";
header.save(outfile + ".hdr");
}