Commit 9b2a5d713cf6d32a0ba1072319cfa83f4d9ad79a
1 parent
2ce6954b
implemented finite differences and SG filters in stim::envi
Showing
7 changed files
with
521 additions
and
0 deletions
Show diff stats
1 | +function c = fd_coefficients(z,x,m) | |
2 | +% Calculates FD weights. The parameters are: | |
3 | +% z location where approximations are to be accurate, | |
4 | +% x vector with x-coordinates for grid points, | |
5 | +% m highest derivative that we want to find weights for | |
6 | +% c array size m+1,lentgh(x) containing (as output) in | |
7 | +% successive rows the weights for derivatives 0,1,...,m. | |
8 | + | |
9 | +n=length(x); c=zeros(m+1,n); c1=1; c4=x(1)-z; c(1,1)=1; | |
10 | +for i=2:n | |
11 | + mn=min(i,m+1); c2=1; c5=c4; c4=x(i)-z; | |
12 | + for j=1:i-1 | |
13 | + c3=x(i)-x(j); c2=c2*c3; | |
14 | + if j==i-1 | |
15 | + c(2:mn,i)=c1*((1:mn-1)'.*c(1:mn-1,i-1)-c5*c(2:mn,i-1))/c2; | |
16 | + c(1,i)=-c1*c5*c(1,i-1)/c2; | |
17 | + end | |
18 | + c(2:mn,j)=(c4*c(2:mn,j)-(1:mn-1)'.*c(1:mn-1,j))/c3; | |
19 | + c(1,j)=c4*c(1,j)/c3; | |
20 | + end | |
21 | + c1=c2; | |
22 | +end | |
0 | 23 | \ No newline at end of file | ... | ... |
1 | +function C = sg_coefficients(n, order) | |
2 | + | |
3 | +if(mod(n, 2) == 0) | |
4 | + disp('The number of coefficients must be odd'); | |
5 | + return; | |
6 | +end | |
7 | + | |
8 | +%assemble the column vector based on positions | |
9 | +r = floor(n/2); %maximum extent around zero (0) | |
10 | +x = -r:1:r; | |
11 | + | |
12 | +%calculate J | |
13 | +J = zeros(n, order + 1); | |
14 | + | |
15 | +%columns values are 1, x_i, x_i^2, ... | |
16 | +for i = 1:order+1 | |
17 | + J(:, i) = (x').^(i-1); | |
18 | +end | |
19 | +C = (J' * J)^(-1) * J'; | |
0 | 20 | \ No newline at end of file | ... | ... |
stim/envi/bil.h
... | ... | @@ -1174,7 +1174,106 @@ public: |
1174 | 1174 | } |
1175 | 1175 | } |
1176 | 1176 | |
1177 | + /// Convolve the given band range with a kernel specified by a vector of coefficients. | |
1177 | 1178 | |
1179 | + /// @param outfile is an already open stream to the output file | |
1180 | + /// @param C is an array of coefficients | |
1181 | + /// @param start is the band to start processing (the first coefficient starts here) | |
1182 | + /// @param nbands is the number of bands to process | |
1183 | + /// @param center is the index for the center coefficient for the kernel (used to set the wavelengths in the output file) | |
1184 | + | |
1185 | + void convolve(std::string outfile, std::vector<double> C, size_t start, size_t end, bool PROGRESS = false){ | |
1186 | + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing | |
1187 | + size_t B = end - start + 1; | |
1188 | + size_t Xb = X() * sizeof(T); //calculate the size of a band (frame) in bytes | |
1189 | + size_t XBb = Xb * Z(); | |
1190 | + | |
1191 | + size_t N = C.size(); //get the number of bands that the kernel spans | |
1192 | + std::deque<T*> frame(N, NULL); //create an array to store pointers to each frame | |
1193 | + for(size_t f = 0; f < N; f++) | |
1194 | + frame[f] = (T*)malloc(Xb); //allocate space for the frame | |
1195 | + | |
1196 | + T* outline = (T*)malloc(Xb); //allocate space for the output band | |
1197 | + | |
1198 | + //Implementation: In order to minimize reads from secondary storage, each band is only loaded once into the 'frame' deque. | |
1199 | + // When a new band is loaded, the last band is popped, a new frame is copied to the pointer, and it is | |
1200 | + // re-inserted into the deque. | |
1201 | + for(size_t y = 0; y < Y(); y++){ | |
1202 | + file.seekg(y * XBb + start * Xb, std::ios::beg); //move to the beginning of the 'start' band | |
1203 | + for(size_t f = 0; f < N; f++) //for each frame | |
1204 | + file.read((char*)frame[f], Xb); //load the frame | |
1205 | + for(size_t b = 0; b < B; b++){ //for each band | |
1206 | + memset(outline, 0, Xb); //set the output band to zero (0) | |
1207 | + for(size_t c = 0; c < N; c++){ //for each frame (corresponding to each coefficient) | |
1208 | + for(size_t x = 0; x < X(); x++){ //for each pixel | |
1209 | + outline[x] += (T)(C[c] * frame[c][x]); //calculate the contribution of the current frame (scaled by the corresponding coefficient) | |
1210 | + } | |
1211 | + } | |
1212 | + out.write((char*)outline, Xb); //output the band | |
1213 | + file.read((char*)frame[0], Xb); //read the next band | |
1214 | + frame.push_back(frame.front()); //put the first element in the back | |
1215 | + frame.pop_front(); //pop the first element | |
1216 | + } | |
1217 | + if(PROGRESS) progress = (double)(y+1) / (double)Y() * 100; | |
1218 | + } | |
1219 | + } | |
1220 | + | |
1221 | + /// Approximate the spectral derivative of the image | |
1222 | + | |
1223 | + void deriv(std::string outfile, size_t d, size_t order, const std::vector<double> w = std::vector<double>(), bool PROGRESS = false){ | |
1224 | + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing | |
1225 | + | |
1226 | + size_t Xb = X() * sizeof(T); //calculate the size of a line (frame) in bytes | |
1227 | + size_t XBb = Xb * Z(); | |
1228 | + size_t B = Z(); | |
1229 | + | |
1230 | + file.seekg(0, std::ios::beg); //seek to the beginning of the file | |
1231 | + | |
1232 | + size_t N = order + d; //approximating a derivative requires order + d samples | |
1233 | + std::deque<T*> frame(N, NULL); //create an array to store pointers to each frame | |
1234 | + for(size_t f = 0; f < N; f++) //for each frame | |
1235 | + frame[f] = (T*)malloc(Xb); //allocate space for the frame | |
1236 | + | |
1237 | + T* outline = (T*)malloc(Xb); //allocate space for the output band | |
1238 | + | |
1239 | + //Implementation: In order to minimize reads from secondary storage, each band is only loaded once into the 'frame' deque. | |
1240 | + // When a new band is loaded, the last band is popped, a new frame is copied to the pointer, and it is | |
1241 | + // re-inserted into the deque. | |
1242 | + size_t mid = (size_t)(N / 2); //calculate the mid point of the kernel | |
1243 | + size_t iw; //index to the first wavelength used to evaluate the derivative at this band | |
1244 | + | |
1245 | + for(size_t y = 0; y < Y(); y++){ | |
1246 | + //file.seekg(y * XBb, std::ios::beg); //seek to the beginning of the current Y plane | |
1247 | + for(size_t f = 0; f < N; f++) //for each frame | |
1248 | + file.read((char*)frame[f], Xb); //load a line | |
1249 | + | |
1250 | + for(size_t b = 0; b < B; b++){ //for each band | |
1251 | + if(b < mid) //calculate the first wavelength used to evaluate the derivative at this band | |
1252 | + iw = 0; | |
1253 | + else if(b > B - (N - mid + 1)) | |
1254 | + iw = B - N; | |
1255 | + else{ | |
1256 | + iw = b - mid; | |
1257 | + file.read((char*)frame[0], Xb); //read the next band | |
1258 | + frame.push_back(frame.front()); //put the first element in the back | |
1259 | + frame.pop_front(); //pop the first element | |
1260 | + } | |
1261 | + std::vector<double> w_pts(w.begin() + iw, w.begin() + iw + N); //get the wavelengths corresponding to each sample | |
1262 | + std::vector<double> C = diff_coefficients(w[b], w_pts, d); //get the optimal sample weights | |
1263 | + | |
1264 | + memset(outline, 0, Xb); //set the output band to zero (0) | |
1265 | + for(size_t c = 0; c < N; c++){ //for each frame (corresponding to each coefficient) | |
1266 | + for(size_t x = 0; x < X(); x++){ //for each pixel | |
1267 | + outline[x] += (T)(C[c] * frame[c][x]); //calculate the contribution of the current frame (scaled by the corresponding coefficient) | |
1268 | + } | |
1269 | + } | |
1270 | + out.write((char*)outline, Xb); //output the band | |
1271 | + | |
1272 | + } | |
1273 | + if(PROGRESS) progress = (double)(y+1) / (double)Y() * 100; | |
1274 | + } | |
1275 | + | |
1276 | + } | |
1178 | 1277 | |
1179 | 1278 | /// Close the file. |
1180 | 1279 | bool close(){ | ... | ... |
stim/envi/bip.h
... | ... | @@ -1250,6 +1250,99 @@ public: |
1250 | 1250 | } |
1251 | 1251 | } |
1252 | 1252 | |
1253 | + /// Convolve the given band range with a kernel specified by a vector of coefficients. | |
1254 | + | |
1255 | + /// @param outfile is an already open stream to the output file | |
1256 | + /// @param C is an array of coefficients | |
1257 | + /// @param start is the band to start processing (the first coefficient starts here) | |
1258 | + /// @param nbands is the number of bands to process | |
1259 | + /// @param center is the index for the center coefficient for the kernel (used to set the wavelengths in the output file) | |
1260 | + | |
1261 | + void convolve(std::string outfile, std::vector<double> C, size_t start, size_t end, bool PROGRESS = false){ | |
1262 | + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing | |
1263 | + | |
1264 | + size_t N = end - start + 1; //number of bands in the output spectrum | |
1265 | + size_t Nb = N * sizeof(T); //size of the output spectrum in bytes | |
1266 | + size_t B = Z(); //calculate the number of values in a spectrum | |
1267 | + size_t Bb = B * sizeof(T); //calculate the size of a spectrum in bytes | |
1268 | + | |
1269 | + file.seekg(0, std::ios::beg); //move to the beginning of the input file | |
1270 | + | |
1271 | + size_t nC = C.size(); //get the number of bands that the kernel spans | |
1272 | + T* inspec = (T*)malloc(Bb); //allocate space for the input spectrum | |
1273 | + T* outspec = (T*)malloc(Nb); //allocate space for the output spectrum | |
1274 | + | |
1275 | + size_t XY = X() * Y(); //number of pixels in the image | |
1276 | + for(size_t xy = 0; xy < XY; xy++){ //for each pixel | |
1277 | + file.read((char*)inspec, Bb); //read an input spectrum | |
1278 | + memset(outspec, 0, Nb); //set the output spectrum to zero (0) | |
1279 | + for(size_t b = 0; b < N; b++){ //for each component of the spectrum | |
1280 | + for(size_t c = 0; c < nC; c++){ //for each coefficient in the kernel | |
1281 | + outspec[b] += (T)(inspec[b + start + c] * C[c]); //perform the sum/multiply part of the convolution | |
1282 | + } | |
1283 | + } | |
1284 | + out.write((char*)outspec, Nb); //output the band | |
1285 | + if(PROGRESS) progress = (double)(xy+1) / (double)XY * 100; | |
1286 | + } | |
1287 | + } | |
1288 | + | |
1289 | + void deriv(std::string outfile, size_t d, size_t order, const std::vector<double> w, bool PROGRESS = false){ | |
1290 | + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing | |
1291 | + | |
1292 | + | |
1293 | + size_t B = Z(); //calculate the number of values in a spectrum | |
1294 | + size_t Bb = B * sizeof(T); //calculate the size of a spectrum in bytes | |
1295 | + | |
1296 | + bool UNIFORM = true; | |
1297 | + double ds = w[1] - w[0]; //initialize ds | |
1298 | + for(size_t b = 1; b < B; b++) //test to see if the spectral spacing is uniform (if it is, convolution is much faster) | |
1299 | + if(w[b] - w[b-1] != ds) UNIFORM = false; | |
1300 | + | |
1301 | + size_t nC = order + d; //approximating a derivative requires order + d samples | |
1302 | + | |
1303 | + file.seekg(0, std::ios::beg); //move to the beginning of the input file | |
1304 | + | |
1305 | + T* inspec = (T*)malloc(Bb); //allocate space for the input spectrum | |
1306 | + T* outspec = (T*)malloc(Bb); //allocate space for the output spectrum | |
1307 | + | |
1308 | + size_t XY = X() * Y(); //number of pixels in the image | |
1309 | + size_t mid = (size_t)(nC / 2); //calculate the mid point of the kernel | |
1310 | + size_t iw; //index to the first wavelength used to evaluate the derivative at this band | |
1311 | + for(size_t xy = 0; xy < XY; xy++){ //for each pixel | |
1312 | + file.read((char*)inspec, Bb); //read an input spectrum | |
1313 | + memset(outspec, 0, Bb); //set the output spectrum to zero (0) | |
1314 | + | |
1315 | + iw = 0; | |
1316 | + for(size_t b = 0; b < mid; b++){ //for each component of the spectrum | |
1317 | + std::vector<double> w_pts(w.begin() + iw, w.begin() + iw + nC); //get the wavelengths corresponding to each sample | |
1318 | + std::vector<double> C = diff_coefficients(w[b], w_pts, d); //get the optimal sample weights | |
1319 | + for(size_t c = 0; c < nC; c++) //for each coefficient in the kernel | |
1320 | + outspec[b] += (T)(inspec[iw + c] * C[c]); //perform the sum/multiply part of the convolution | |
1321 | + } | |
1322 | + std::vector<double> w_pts(w.begin(), w.begin() + nC); //get the wavelengths corresponding to each sample | |
1323 | + std::vector<double> C = diff_coefficients(w[0], w_pts, d); //get the optimal sample weights | |
1324 | + for(size_t b = mid; b <= B - (nC - mid); b++){ | |
1325 | + iw = b - mid; | |
1326 | + if(!UNIFORM){ //if the spacing is non-uniform, we have to re-calculate these points every iteration | |
1327 | + std::vector<double> w_pts(w.begin() + iw, w.begin() + iw + nC); //get the wavelengths corresponding to each sample | |
1328 | + std::vector<double> C = diff_coefficients(w[b], w_pts, d); //get the optimal sample weights | |
1329 | + } | |
1330 | + for(size_t c = 0; c < nC; c++) //for each coefficient in the kernel | |
1331 | + outspec[b] += (T)(inspec[iw + c] * C[c]); //perform the sum/multiply part of the convolution | |
1332 | + } | |
1333 | + iw = B - nC; | |
1334 | + for(size_t b = B - (nC - mid) + 1; b < B; b++){ | |
1335 | + std::vector<double> w_pts(w.begin() + iw, w.begin() + iw + nC); //get the wavelengths corresponding to each sample | |
1336 | + std::vector<double> C = diff_coefficients(w[b], w_pts, d); //get the optimal sample weights | |
1337 | + for(size_t c = 0; c < nC; c++) //for each coefficient in the kernel | |
1338 | + outspec[b] += (T)(inspec[iw + c] * C[c]); //perform the sum/multiply part of the convolution | |
1339 | + } | |
1340 | + | |
1341 | + out.write((char*)outspec, Bb); //output the band | |
1342 | + if(PROGRESS) progress = (double)(xy+1) / (double)XY * 100; | |
1343 | + } | |
1344 | + } | |
1345 | + | |
1253 | 1346 | |
1254 | 1347 | |
1255 | 1348 | /// Close the file. | ... | ... |
stim/envi/bsq.h
... | ... | @@ -7,6 +7,7 @@ |
7 | 7 | #include <cstring> |
8 | 8 | #include <utility> |
9 | 9 | #include <vector> |
10 | +#include <deque> | |
10 | 11 | |
11 | 12 | |
12 | 13 | |
... | ... | @@ -1058,6 +1059,128 @@ public: |
1058 | 1059 | out.write((char*)dst, band_dst_bytes); //write the combined image to an output file |
1059 | 1060 | if(PROGRESS) progress = (double)(b + 1) / (double) Z() * 100; |
1060 | 1061 | } |
1062 | + out.close(); | |
1063 | + } | |
1064 | + | |
1065 | + /// Convolve the given band range with a kernel specified by a vector of coefficients. | |
1066 | + | |
1067 | + /// @param outfile is an already open stream to the output file | |
1068 | + /// @param C is an array of coefficients | |
1069 | + /// @param start is the band to start processing (the first coefficient starts here) | |
1070 | + /// @param nbands is the number of bands to process | |
1071 | + /// @param center is the index for the center coefficient for the kernel (used to set the wavelengths in the output file) | |
1072 | + | |
1073 | + void convolve(std::ofstream& out, std::vector<double> C, size_t start, size_t end, bool PROGRESS = false){ | |
1074 | + size_t nbands = end - start + 1; | |
1075 | + size_t XY = X() * Y(); //calculate the number of values in a band | |
1076 | + size_t XYb = XY * sizeof(T); //calculate the size of a band (frame) in bytes | |
1077 | + | |
1078 | + file.seekg(XYb * start, std::ios::beg); //move to the beginning of the 'start' band | |
1079 | + | |
1080 | + size_t nframes = C.size(); //get the number of bands that the kernel spans | |
1081 | + std::deque<T*> frame(nframes, NULL); //create an array to store pointers to each frame | |
1082 | + for(size_t f = 0; f < nframes; f++){ //for each frame | |
1083 | + frame[f] = (T*)malloc(XYb); //allocate space for the frame | |
1084 | + file.read((char*)frame[f], XYb); //load the frame | |
1085 | + } | |
1086 | + | |
1087 | + T* outband = (T*)malloc(XYb); //allocate space for the output band | |
1088 | + | |
1089 | + //Implementation: In order to minimize reads from secondary storage, each band is only loaded once into the 'frame' deque. | |
1090 | + // When a new band is loaded, the last band is popped, a new frame is copied to the pointer, and it is | |
1091 | + // re-inserted into the deque. | |
1092 | + for(size_t b = 0; b < nbands; b++){ //for each band | |
1093 | + memset(outband, 0, XYb); //set the output band to zero (0) | |
1094 | + for(size_t c = 0; c < nframes; c++){ //for each frame (corresponding to each coefficient) | |
1095 | + for(size_t xy = 0; xy < XY; xy++){ //for each pixel | |
1096 | + outband[xy] += (T)(C[c] * frame[c][xy]); //calculate the contribution of the current frame (scaled by the corresponding coefficient) | |
1097 | + } | |
1098 | + } | |
1099 | + out.write((char*)outband, XYb); //output the band | |
1100 | + file.read((char*)frame[0], XYb); //read the next band | |
1101 | + frame.push_back(frame.front()); //put the first element in the back | |
1102 | + frame.pop_front(); //pop the first element | |
1103 | + if(PROGRESS) progress = (double)(b+1) / (double)nbands * 100; | |
1104 | + } | |
1105 | + } | |
1106 | + | |
1107 | + /// Performs a single convolution and saves it to an output file | |
1108 | + | |
1109 | + /// @param outfile is the convolved file to be output | |
1110 | + /// @param C is an array of coefficients | |
1111 | + /// @param start is the band to start processing (the first coefficient starts here) | |
1112 | + /// @param nbands is the number of bands to process | |
1113 | + void convolve(std::string outfile, std::vector<double> C, size_t start, size_t end, bool PROGRESS = false){ | |
1114 | + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing | |
1115 | + convolve(out, C, start, end, PROGRESS); //start the convolution | |
1116 | + out.close(); | |
1117 | + } | |
1118 | + | |
1119 | + /// Performs a set of convolutions and chains the results together in a single file | |
1120 | + | |
1121 | + /// @param outfile is the convolved file to be output | |
1122 | + /// @param C is an array containing an array of coefficients for each kernel | |
1123 | + /// @param start is the list of start bands for each kernel | |
1124 | + /// @param end is the list of end bands for each kernel | |
1125 | + void convolve(std::string outfile, std::vector< std::vector<double> > C, std::vector<size_t> start, std::vector<size_t> end, bool PROGRESS = false){ | |
1126 | + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing | |
1127 | + | |
1128 | + size_t K = C.size(); //get the number of kernels | |
1129 | + for(size_t k = 0; k < K; k++){ | |
1130 | + size_t b0 = start[k]; //calculate the range of the convolution | |
1131 | + size_t b1 = end[k]; | |
1132 | + convolve(out, C[k], b0, b1, PROGRESS); //perform the convolution with the current kernel in the given range | |
1133 | + } | |
1134 | + out.close(); | |
1135 | + } | |
1136 | + | |
1137 | + /// Approximate the spectral derivative of the image | |
1138 | + | |
1139 | + void deriv(std::string outfile, size_t d, size_t order, const std::vector<double> w = std::vector<double>(), bool PROGRESS = false){ | |
1140 | + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing | |
1141 | + | |
1142 | + size_t XY = X() * Y(); //calculate the number of values in a band | |
1143 | + size_t XYb = XY * sizeof(T); //calculate the size of a band (frame) in bytes | |
1144 | + size_t B = Z(); | |
1145 | + file.seekg(0, std::ios::beg); //move to the beginning of the file | |
1146 | + | |
1147 | + size_t N = order + d; //approximating a derivative requires order + d samples | |
1148 | + std::deque<T*> frame(N, NULL); //create an array to store pointers to each frame | |
1149 | + for(size_t f = 0; f < N; f++){ //for each frame | |
1150 | + frame[f] = (T*)malloc(XYb); //allocate space for the frame | |
1151 | + file.read((char*)frame[f], XYb); //load the frame | |
1152 | + } | |
1153 | + | |
1154 | + T* outband = (T*)malloc(XYb); //allocate space for the output band | |
1155 | + | |
1156 | + //Implementation: In order to minimize reads from secondary storage, each band is only loaded once into the 'frame' deque. | |
1157 | + // When a new band is loaded, the last band is popped, a new frame is copied to the pointer, and it is | |
1158 | + // re-inserted into the deque. | |
1159 | + size_t mid = (size_t)(N / 2); //calculate the mid point of the kernel | |
1160 | + size_t iw; //index to the first wavelength used to evaluate the derivative at this band | |
1161 | + for(size_t b = 0; b < B; b++){ //for each band | |
1162 | + if(b < mid) //calculate the first wavelength used to evaluate the derivative at this band | |
1163 | + iw = 0; | |
1164 | + else if(b > B - (N - mid + 1)) | |
1165 | + iw = B - N; | |
1166 | + else{ | |
1167 | + iw = b - mid; | |
1168 | + file.read((char*)frame[0], XYb); //read the next band | |
1169 | + frame.push_back(frame.front()); //put the first element in the back | |
1170 | + frame.pop_front(); //pop the first element | |
1171 | + } | |
1172 | + std::vector<double> w_pts(w.begin() + iw, w.begin() + iw + N); //get the wavelengths corresponding to each sample | |
1173 | + std::vector<double> C = diff_coefficients(w[b], w_pts, d); //get the optimal sample weights | |
1174 | + | |
1175 | + memset(outband, 0, XYb); //set the output band to zero (0) | |
1176 | + for(size_t c = 0; c < N; c++){ //for each frame (corresponding to each coefficient) | |
1177 | + for(size_t xy = 0; xy < XY; xy++){ //for each pixel | |
1178 | + outband[xy] += (T)(C[c] * frame[c][xy]); //calculate the contribution of the current frame (scaled by the corresponding coefficient) | |
1179 | + } | |
1180 | + } | |
1181 | + out.write((char*)outband, XYb); //output the band | |
1182 | + if(PROGRESS) progress = (double)(b+1) / (double)B * 100; | |
1183 | + } | |
1061 | 1184 | |
1062 | 1185 | } |
1063 | 1186 | ... | ... |
stim/envi/envi.h
... | ... | @@ -5,6 +5,7 @@ |
5 | 5 | #include "../envi/bsq.h" |
6 | 6 | #include "../envi/bip.h" |
7 | 7 | #include "../envi/bil.h" |
8 | +#include "../math/fd_coefficients.h" | |
8 | 9 | #include <iostream> |
9 | 10 | //#include "../image/image.h" |
10 | 11 | |
... | ... | @@ -1341,6 +1342,103 @@ public: |
1341 | 1342 | } |
1342 | 1343 | } |
1343 | 1344 | } |
1345 | + | |
1346 | + /// Convolve the given band range with a kernel specified by a vector of coefficients. | |
1347 | + | |
1348 | + /// @param outfile is the combined file to be output | |
1349 | + /// @param c is an array of coefficients | |
1350 | + /// @param start is the band to start processing (the first coefficient starts here) | |
1351 | + /// @param nbands is the number of bands to process | |
1352 | + /// @param center is the index for the center coefficient for the kernel (used to set the wavelengths in the output file) | |
1353 | + void convolve(std::string outfile, std::vector<double> C, size_t start, size_t end, size_t center = 0, bool PROGRESS = false){ | |
1354 | + size_t nbands = end - start + 1; | |
1355 | + envi_header h = header; //copy the current header | |
1356 | + h.bands = nbands; //set the number of new bands | |
1357 | + if(header.wavelength.size() != 0){ | |
1358 | + h.wavelength.resize(nbands); //set the number of wavelengths to the number of bands | |
1359 | + for(size_t b = 0; b < nbands; b++) | |
1360 | + h.wavelength[b] = header.wavelength[b+center]; | |
1361 | + } | |
1362 | + if(header.band_names.size() != 0){ | |
1363 | + h.band_names.resize(nbands); | |
1364 | + for(size_t b = 0; b < nbands; b++) | |
1365 | + h.band_names[b] = header.band_names[b+center]; | |
1366 | + } | |
1367 | + h.save(outfile + ".hdr"); //save the new header | |
1368 | + | |
1369 | + if (header.interleave == envi_header::BSQ){ | |
1370 | + if (header.data_type == envi_header::float32) | |
1371 | + ((bsq<float>*)file)->convolve(outfile, C, start, end, PROGRESS); | |
1372 | + else if (header.data_type == envi_header::float64) | |
1373 | + ((bsq<double>*)file)->convolve(outfile, C, start, end, PROGRESS); | |
1374 | + else{ | |
1375 | + std::cout << "ERROR: unidentified data type" << std::endl; | |
1376 | + exit(1); | |
1377 | + } | |
1378 | + } | |
1379 | + else if (header.interleave == envi_header::BIL){ | |
1380 | + if (header.data_type == envi_header::float32) | |
1381 | + ((bil<float>*)file)->convolve(outfile, C, start, end, PROGRESS); | |
1382 | + else if (header.data_type == envi_header::float64) | |
1383 | + ((bil<double>*)file)->convolve(outfile, C, start, end, PROGRESS); | |
1384 | + else{ | |
1385 | + std::cout << "ERROR: unidentified data type" << std::endl; | |
1386 | + exit(1); | |
1387 | + } | |
1388 | + } | |
1389 | + else if (header.interleave == envi_header::BIP){ | |
1390 | + if (header.data_type == envi_header::float32) | |
1391 | + ((bip<float>*)file)->convolve(outfile, C, start, end, PROGRESS); | |
1392 | + else if (header.data_type == envi_header::float64) | |
1393 | + ((bip<double>*)file)->convolve(outfile, C, start, end, PROGRESS); | |
1394 | + else{ | |
1395 | + std::cout << "ERROR: unidentified data type" << std::endl; | |
1396 | + exit(1); | |
1397 | + } | |
1398 | + } | |
1399 | + } | |
1400 | + | |
1401 | + /// Approximates the nth derivative of the spectra to the specified order | |
1402 | + | |
1403 | + /// @param outfile is the file where the derivative approximation will be saved | |
1404 | + /// @n is the derivative to be calculated | |
1405 | + /// @order is the order of the error (must be even) | |
1406 | + void deriv(std::string outfile, size_t d, size_t order, bool PROGRESS = false){ | |
1407 | + header.save(outfile + ".hdr"); | |
1408 | + if (header.interleave == envi_header::BSQ){ | |
1409 | + if (header.data_type == envi_header::float32) | |
1410 | + ((bsq<float>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS); | |
1411 | + else if (header.data_type == envi_header::float64) | |
1412 | + ((bsq<double>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS); | |
1413 | + else{ | |
1414 | + std::cout << "ERROR: unidentified data type" << std::endl; | |
1415 | + exit(1); | |
1416 | + } | |
1417 | + } | |
1418 | + | |
1419 | + else if (header.interleave == envi_header::BIL){ | |
1420 | + if (header.data_type == envi_header::float32) | |
1421 | + ((bil<float>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS); | |
1422 | + else if (header.data_type == envi_header::float64) | |
1423 | + ((bil<double>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS); | |
1424 | + else{ | |
1425 | + std::cout << "ERROR: unidentified data type" << std::endl; | |
1426 | + exit(1); | |
1427 | + } | |
1428 | + } | |
1429 | + | |
1430 | + else if (header.interleave == envi_header::BIP){ | |
1431 | + if (header.data_type == envi_header::float32) | |
1432 | + ((bip<float>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS); | |
1433 | + else if (header.data_type == envi_header::float64) | |
1434 | + ((bip<double>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS); | |
1435 | + else{ | |
1436 | + std::cout << "ERROR: unidentified data type" << std::endl; | |
1437 | + exit(1); | |
1438 | + } | |
1439 | + } | |
1440 | + exit(1); | |
1441 | + } | |
1344 | 1442 | }; |
1345 | 1443 | |
1346 | 1444 | } //end namespace rts | ... | ... |
1 | +#ifndef STIM_FINITE_DIFFERENCE_COEFFICIENTS | |
2 | +#define STIM_FINITE_DIFFERENCE_COEFFICIENTS | |
3 | + | |
4 | +#include <vector> | |
5 | +#include <algorithm> | |
6 | + | |
7 | +/// Calculate the coefficients used for finite differences on arbitrary grids. This code is based on: | |
8 | +/// Fornberg, "Generation of Finite Difference Formulas on Arbitrarily Spaced Grids", Mathematics of Computation, 51(184) 699-706, 1988 | |
9 | + | |
10 | +/// @param Z is the location where the approximation is to be accurate | |
11 | +/// @param X is a vector of coordinates for grid points | |
12 | +/// @param M is the highest derivative to be computed | |
13 | +/// This function returns a matrix C[a][b] where a is the derivative and b is the coefficient for x = b | |
14 | + | |
15 | +template <typename T> | |
16 | +std::vector< std::vector<T> > diff_coefficient_matrix(T Z, std::vector<T> X, size_t M){ | |
17 | + size_t n = X.size(); //calculate the number of data points available | |
18 | + std::vector< std::vector<T> > C(M+1); //create an array of m arrays | |
19 | + for(size_t m = 0; m < M+1; m++) //for each derivative | |
20 | + C[m].resize(n); //allocate space for n coefficients | |
21 | + | |
22 | + T c1, c2, c3, c4, c5; | |
23 | + c1 = 1; //initialize the matrix | |
24 | + c4 = X[0] - Z; | |
25 | + C[0][0] = 1; | |
26 | + for(size_t i = 2; i <= n; i++){ | |
27 | + size_t mn = (std::min)(i, M+1); | |
28 | + c2 = 1; | |
29 | + c5 = c4; | |
30 | + c4 = X[i-1] - Z; | |
31 | + for(size_t j = 1; j <= i-1; j++){ | |
32 | + c3 = X[i-1] - X[j-1]; | |
33 | + c2 = c2 * c3; | |
34 | + if(j == i-1){ | |
35 | + for(size_t k = 2; k <= mn; k++){ | |
36 | + C[k-1][i-1] = c1 * ((k-1) * C[k-2][i-2] - c5 * C[k-1][i-2]) / c2; | |
37 | + } | |
38 | + C[0][i-1] = -c1 * c5 * C[0][i-2]/c2; | |
39 | + } | |
40 | + T c_p0 = C[0][j-1]; | |
41 | + T c_p1 = C[1][j-1]; | |
42 | + for(size_t k = 2; k <= mn; k++){ | |
43 | + c_p1 = C[k-1][j-1]; | |
44 | + C[k-1][j-1] = (c4 * c_p1 - (k-1) * c_p0) / c3; | |
45 | + c_p0 = c_p1; | |
46 | + } | |
47 | + C[0][j-1] = c4 * C[0][j-1] / c3; | |
48 | + } | |
49 | + c1 = c2; | |
50 | + } | |
51 | + return C; | |
52 | +} | |
53 | + | |
54 | +/// Returns the coefficients used to estimate the nth derivative at x0 given values at points in x | |
55 | + | |
56 | +/// @param x0 is the point where the derivative f'(x0) is to be estimated | |
57 | +/// @param x is the set of points where the values of f(x) are known | |
58 | +/// @param n specifies the derivative, ex. 2 estimates the second derivative f''(x0) | |
59 | +template <typename T> | |
60 | +std::vector<T> diff_coefficients(T x0, std::vector<T> x, size_t n){ | |
61 | + std::vector< std::vector<T> > C = diff_coefficient_matrix(x0, x, n); //calculate all derivative coefficients | |
62 | + return C.back(); | |
63 | +} | |
64 | + | |
65 | + | |
66 | + | |
67 | +#endif | |
0 | 68 | \ No newline at end of file | ... | ... |