pyvale 2025.5.3__cp311-cp311-musllinux_1_2_aarch64.whl → 2025.7.1__cp311-cp311-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyvale might be problematic. Click here for more details.
- pyvale/__init__.py +12 -0
- pyvale/blendercalibrationdata.py +3 -1
- pyvale/blenderscene.py +7 -5
- pyvale/blendertools.py +27 -5
- pyvale/camera.py +1 -0
- pyvale/cameradata.py +3 -0
- pyvale/camerasensor.py +147 -0
- pyvale/camerastereo.py +4 -4
- pyvale/cameratools.py +23 -61
- pyvale/cython/rastercyth.c +1657 -1352
- pyvale/cython/rastercyth.cpython-311-aarch64-linux-musl.so +0 -0
- pyvale/cython/rastercyth.py +71 -26
- pyvale/data/DIC_Challenge_Star_Noise_Def.tiff +0 -0
- pyvale/data/DIC_Challenge_Star_Noise_Ref.tiff +0 -0
- pyvale/data/plate_hole_def0000.tiff +0 -0
- pyvale/data/plate_hole_def0001.tiff +0 -0
- pyvale/data/plate_hole_ref0000.tiff +0 -0
- pyvale/data/plate_rigid_def0000.tiff +0 -0
- pyvale/data/plate_rigid_def0001.tiff +0 -0
- pyvale/data/plate_rigid_ref0000.tiff +0 -0
- pyvale/dataset.py +96 -6
- pyvale/dic/cpp/dicbruteforce.cpp +370 -0
- pyvale/dic/cpp/dicfourier.cpp +648 -0
- pyvale/dic/cpp/dicinterpolator.cpp +559 -0
- pyvale/dic/cpp/dicmain.cpp +215 -0
- pyvale/dic/cpp/dicoptimizer.cpp +675 -0
- pyvale/dic/cpp/dicrg.cpp +137 -0
- pyvale/dic/cpp/dicscanmethod.cpp +677 -0
- pyvale/dic/cpp/dicsmooth.cpp +138 -0
- pyvale/dic/cpp/dicstrain.cpp +383 -0
- pyvale/dic/cpp/dicutil.cpp +563 -0
- pyvale/dic2d.py +164 -0
- pyvale/dic2dcpp.cpython-311-aarch64-linux-musl.so +0 -0
- pyvale/dicchecks.py +476 -0
- pyvale/dicdataimport.py +247 -0
- pyvale/dicregionofinterest.py +887 -0
- pyvale/dicresults.py +55 -0
- pyvale/dicspecklegenerator.py +238 -0
- pyvale/dicspecklequality.py +305 -0
- pyvale/dicstrain.py +387 -0
- pyvale/dicstrainresults.py +37 -0
- pyvale/errorintegrator.py +10 -8
- pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +124 -113
- pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +124 -132
- pyvale/examples/basics/ex1_3_customsens_therm3d.py +199 -195
- pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +125 -121
- pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +145 -141
- pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +96 -101
- pyvale/examples/basics/ex1_7_spatavg_therm2d.py +109 -105
- pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +92 -91
- pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +96 -90
- pyvale/examples/basics/ex2_3_sensangle_disp2d.py +88 -89
- pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +172 -171
- pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +88 -86
- pyvale/examples/basics/ex3_1_basictensors_strain2d.py +90 -90
- pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +93 -91
- pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +172 -160
- pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +154 -148
- pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +249 -231
- pyvale/examples/dic/ex1_region_of_interest.py +98 -0
- pyvale/examples/dic/ex2_plate_with_hole.py +149 -0
- pyvale/examples/dic/ex3_plate_with_hole_strain.py +93 -0
- pyvale/examples/dic/ex4_dic_blender.py +95 -0
- pyvale/examples/dic/ex5_dic_challenge.py +102 -0
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +4 -2
- pyvale/examples/renderblender/ex1_1_blenderscene.py +152 -105
- pyvale/examples/renderblender/ex1_2_blenderdeformed.py +151 -100
- pyvale/examples/renderblender/ex2_1_stereoscene.py +183 -116
- pyvale/examples/renderblender/ex2_2_stereodeformed.py +185 -112
- pyvale/examples/renderblender/ex3_1_blendercalibration.py +164 -109
- pyvale/examples/renderrasterisation/ex_rastenp.py +74 -35
- pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +6 -13
- pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +2 -2
- pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +2 -4
- pyvale/imagedef2d.py +3 -2
- pyvale/imagetools.py +137 -0
- pyvale/rastercy.py +34 -4
- pyvale/rasternp.py +300 -276
- pyvale/rasteropts.py +58 -0
- pyvale/renderer.py +47 -0
- pyvale/rendermesh.py +52 -62
- pyvale/renderscene.py +51 -0
- pyvale/sensorarrayfactory.py +2 -2
- pyvale/sensortools.py +19 -35
- pyvale/simcases/case21.i +1 -1
- pyvale/simcases/run_1case.py +8 -0
- pyvale/simtools.py +2 -2
- pyvale/visualsimplotter.py +180 -0
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/METADATA +11 -57
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/RECORD +96 -56
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/WHEEL +1 -1
- pyvale.libs/libgcc_s-69c45f16.so.1 +0 -0
- pyvale.libs/libgomp-b626072d.so.1.0.0 +0 -0
- pyvale.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
- pyvale/examples/visualisation/ex1_1_plot_traces.py +0 -102
- pyvale/examples/visualisation/ex2_1_animate_sim.py +0 -89
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/licenses/LICENSE +0 -0
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
// ================================================================================
|
|
2
|
+
// pyvale: the python validation engine
|
|
3
|
+
// License: MIT
|
|
4
|
+
// Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
// ================================================================================
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
// STD library Header files
|
|
9
|
+
#include <queue>
|
|
10
|
+
#include <atomic>
|
|
11
|
+
#include <thread>
|
|
12
|
+
#include <cstring>
|
|
13
|
+
#include <omp.h>
|
|
14
|
+
#include <csignal>
|
|
15
|
+
|
|
16
|
+
// Program Header files
|
|
17
|
+
#include "./dicbruteforce.hpp"
|
|
18
|
+
#include "./dicinterpolator.hpp"
|
|
19
|
+
#include "./dicoptimizer.hpp"
|
|
20
|
+
#include "./defines.hpp"
|
|
21
|
+
#include "./dicutil.hpp"
|
|
22
|
+
#include "./dicrg.hpp"
|
|
23
|
+
#include "./indicators.hpp"
|
|
24
|
+
#include "./cursor_control.hpp"
|
|
25
|
+
#include "./dicfourier.hpp"
|
|
26
|
+
|
|
27
|
+
namespace scanmethod {
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
// for graceful exit
|
|
31
|
+
std::atomic<bool> stop_request(false);
|
|
32
|
+
|
|
33
|
+
void signalHandler(int signal) {
|
|
34
|
+
if (signal == SIGINT) {
|
|
35
|
+
stop_request = true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
void image(const double *img_ref,
|
|
40
|
+
const Interpolator &interp_def,
|
|
41
|
+
const util::SubsetData &ssdata,
|
|
42
|
+
const util::Config &conf,
|
|
43
|
+
const int img_num){
|
|
44
|
+
|
|
45
|
+
const int num_ss = ssdata.num;
|
|
46
|
+
const int ss_size = ssdata.size;
|
|
47
|
+
|
|
48
|
+
// progress bar
|
|
49
|
+
indicators::ProgressBar bar;
|
|
50
|
+
util::create_progress_bar(bar, conf.filenames, img_num, 100);
|
|
51
|
+
std::atomic<int> current_progress = 0;
|
|
52
|
+
std::atomic<int> prev_pct = 0;
|
|
53
|
+
|
|
54
|
+
// loop over subsets within the ROI
|
|
55
|
+
#pragma omp parallel shared(stop_request)
|
|
56
|
+
{
|
|
57
|
+
|
|
58
|
+
// initialise subsets
|
|
59
|
+
util::Subset ss_def(ss_size);
|
|
60
|
+
util::Subset ss_ref(ss_size);
|
|
61
|
+
|
|
62
|
+
// optimization parameters
|
|
63
|
+
optimizer::Parameters opt(conf.num_params, conf.max_iter,
|
|
64
|
+
conf.precision, conf.opt_threshold,
|
|
65
|
+
conf.px_vert, conf.px_hori);
|
|
66
|
+
|
|
67
|
+
// if using SSD then not going to use opt_threshold. It can take
|
|
68
|
+
// any value. Convergence will be checked against precision only
|
|
69
|
+
if (conf.corr_crit=="SSD")
|
|
70
|
+
opt.opt_threshold = std::numeric_limits<double>::max();
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
#pragma omp for
|
|
74
|
+
for (int ss = 0; ss < num_ss; ss++){
|
|
75
|
+
|
|
76
|
+
// exit the main DIC loop when ctrl+C is hit
|
|
77
|
+
if (stop_request){
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// subset coordinate list takes central locations.
|
|
82
|
+
// Converting to top left corner for optimization routine
|
|
83
|
+
int ss_x = ssdata.coords[ss*2];
|
|
84
|
+
int ss_y = ssdata.coords[ss*2+1];
|
|
85
|
+
|
|
86
|
+
// get the reference subset
|
|
87
|
+
util::extract_ss(ss_ref, ss_x, ss_y, conf.px_hori, conf.px_vert, img_ref);
|
|
88
|
+
|
|
89
|
+
for (int i = 0; i < opt.num_params; i++){
|
|
90
|
+
opt.p[i] = 0.0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// perform optimization on subset from deformed image
|
|
94
|
+
double centre_x = ss_x + static_cast<double>(ssdata.size)/2.0 - 0.5;
|
|
95
|
+
double centre_y = ss_y + static_cast<double>(ssdata.size)/2.0 - 0.5;
|
|
96
|
+
util::Results res = optimizer::solve(centre_x, centre_y, ss_ref, ss_def, interp_def, opt, conf.corr_crit);
|
|
97
|
+
|
|
98
|
+
if (conf.corr_crit!="SSD")
|
|
99
|
+
res.cost = 1-res.cost;
|
|
100
|
+
|
|
101
|
+
// append the results for the current subset to result vectors
|
|
102
|
+
util::append_results(img_num, ss, res, num_ss);
|
|
103
|
+
|
|
104
|
+
// update progress bar
|
|
105
|
+
int progress = current_progress.fetch_add(1);
|
|
106
|
+
util::update_progress_bar(bar, progress, num_ss, prev_pct);
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
bar.mark_as_completed();
|
|
111
|
+
indicators::show_console_cursor(true);
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
void image_with_bf(const double *img_ref,
|
|
118
|
+
const double *img_def,
|
|
119
|
+
const Interpolator &interp_def,
|
|
120
|
+
const util::SubsetData &ssdata,
|
|
121
|
+
const util::Config &conf,
|
|
122
|
+
const int img_num){
|
|
123
|
+
|
|
124
|
+
const int num_ss = ssdata.num;
|
|
125
|
+
const int ss_size = ssdata.size;
|
|
126
|
+
|
|
127
|
+
// progress bar
|
|
128
|
+
indicators::ProgressBar bar;
|
|
129
|
+
util::create_progress_bar(bar, conf.filenames, img_num, num_ss);
|
|
130
|
+
std::atomic<int> current_progress = 0;
|
|
131
|
+
std::atomic<int> prev_pct = 0;
|
|
132
|
+
|
|
133
|
+
// initialise subsets
|
|
134
|
+
util::Subset ss_def(ss_size);
|
|
135
|
+
util::Subset ss_ref(ss_size);
|
|
136
|
+
|
|
137
|
+
// optimization parameters
|
|
138
|
+
optimizer::Parameters opt(conf.num_params, conf.max_iter,
|
|
139
|
+
conf.precision, conf.opt_threshold,
|
|
140
|
+
conf.px_vert, conf.px_hori);
|
|
141
|
+
|
|
142
|
+
// if using SSD then not going to use opt_threshold. It can take
|
|
143
|
+
// any value. Convergence will be checked against precision only
|
|
144
|
+
if (conf.corr_crit=="SSD")
|
|
145
|
+
opt.opt_threshold = std::numeric_limits<double>::max();
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
// brute force scan parameters
|
|
149
|
+
brute::Parameters brute(conf.bf_threshold, conf.max_disp);
|
|
150
|
+
|
|
151
|
+
// perform optimization on subset from deformed image
|
|
152
|
+
util::Results res(conf.num_params);
|
|
153
|
+
|
|
154
|
+
// counter for each thread
|
|
155
|
+
int ss_thread_num = 0;
|
|
156
|
+
|
|
157
|
+
// temp p values for copy from brute force to optimization.
|
|
158
|
+
double ptemp[6] = {0,0,0,0,0,0};
|
|
159
|
+
|
|
160
|
+
// loop over subsets within the ROI
|
|
161
|
+
#pragma omp parallel for firstprivate(ss_ref, ss_def, ss_thread_num, opt, brute, res, ptemp)
|
|
162
|
+
for (int ss = 0; ss < num_ss; ss++){
|
|
163
|
+
|
|
164
|
+
// exit the main DIC loop when ctrl+C is hit
|
|
165
|
+
if (stop_request){
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
// subset coordinate list contains central locations.
|
|
171
|
+
// Converting to top left corner for optimization routine
|
|
172
|
+
int ss_x = ssdata.coords[ss*2];
|
|
173
|
+
int ss_y = ssdata.coords[ss*2+1];
|
|
174
|
+
|
|
175
|
+
// get the reference subset values from the reference img
|
|
176
|
+
util::extract_ss(ss_ref, ss_x, ss_y, conf.px_hori, conf.px_vert, img_ref);
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
// if first subset in the loop or prev subset was a poor match
|
|
180
|
+
// start search with a brute force scan using the last set of
|
|
181
|
+
// brute force params that gave a good match.
|
|
182
|
+
if ((ss_thread_num == 0) || (res.cost > opt.opt_threshold)){
|
|
183
|
+
|
|
184
|
+
brute::expanding_wavefront(ss_x, ss_y, img_ref,
|
|
185
|
+
conf.px_hori,
|
|
186
|
+
conf.px_vert,
|
|
187
|
+
ss_ref, ss_def, brute);
|
|
188
|
+
|
|
189
|
+
ptemp[0] = brute.p_rigid[0];
|
|
190
|
+
ptemp[1] = brute.p_rigid[1];
|
|
191
|
+
|
|
192
|
+
for (int i = 0; i < opt.num_params; i++){
|
|
193
|
+
opt.p[i] = ptemp[i];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
double centre_x = ss_x + static_cast<double>(ssdata.size)/2.0 - 0.5;
|
|
198
|
+
double centre_y = ss_y + static_cast<double>(ssdata.size)/2.0 - 0.5;
|
|
199
|
+
util::Results res = optimizer::solve(centre_x, centre_y, ss_ref, ss_def, interp_def, opt, conf.corr_crit);
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
// if its not SSD, then we need to flip the cost values so that 1.0
|
|
203
|
+
// is a perfect match rather than 0.0
|
|
204
|
+
if (conf.corr_crit!="SSD")
|
|
205
|
+
res.cost = 1-res.cost;
|
|
206
|
+
|
|
207
|
+
// append the results for the current subset to result vectors
|
|
208
|
+
util::append_results(img_num, ss, res, num_ss);
|
|
209
|
+
|
|
210
|
+
ss_thread_num++;
|
|
211
|
+
|
|
212
|
+
// update progress bar
|
|
213
|
+
int progress = current_progress.fetch_add(1);
|
|
214
|
+
util::update_progress_bar(bar, progress, num_ss, prev_pct);
|
|
215
|
+
|
|
216
|
+
}
|
|
217
|
+
bar.mark_as_completed();
|
|
218
|
+
indicators::show_console_cursor(true);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
void reliability_guided(const double *img_ref,
|
|
227
|
+
const double *img_def,
|
|
228
|
+
const Interpolator &interp_def,
|
|
229
|
+
const std::vector<util::SubsetData> &ssdata,
|
|
230
|
+
const util::Config &conf,
|
|
231
|
+
const int img_num,
|
|
232
|
+
const bool save_at_end){
|
|
233
|
+
|
|
234
|
+
// assign some consts for readability
|
|
235
|
+
const int px_hori = conf.px_hori;
|
|
236
|
+
const int px_vert = conf.px_vert;
|
|
237
|
+
const int seed_x = conf.rg_seed.first;
|
|
238
|
+
const int seed_y = conf.rg_seed.second;
|
|
239
|
+
const int nsizes = ssdata.size();
|
|
240
|
+
const int last_size = nsizes-1;
|
|
241
|
+
const int num_ss = ssdata[last_size].num;
|
|
242
|
+
const int ss_size = ssdata[last_size].size;
|
|
243
|
+
const int ss_step = ssdata[last_size].step;
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
fourier::mgwd(ssdata, img_ref, img_def, interp_def,
|
|
247
|
+
conf.fft_mad, conf.fft_mad_scale);
|
|
248
|
+
|
|
249
|
+
// progress bar
|
|
250
|
+
indicators::ProgressBar bar;
|
|
251
|
+
util::create_progress_bar(bar, conf.filenames, img_num, num_ss);
|
|
252
|
+
std::atomic<int> current_progress(0);
|
|
253
|
+
std::atomic<int> prev_pct(0);
|
|
254
|
+
|
|
255
|
+
// quick check for the initial seed point
|
|
256
|
+
if (!rg::is_valid_point(seed_x, seed_y, ssdata[last_size])) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Initialize binary mask for computed points (initialized to 0)
|
|
261
|
+
std::vector<std::atomic<int>> computed_mask(ssdata[last_size].mask.size());
|
|
262
|
+
for (auto& val : computed_mask) val.store(0);
|
|
263
|
+
|
|
264
|
+
// queue for each thread
|
|
265
|
+
std::vector<std::priority_queue<rg::Point>> local_q(omp_get_max_threads());
|
|
266
|
+
|
|
267
|
+
// Mutex vector to protect each queue
|
|
268
|
+
std::vector<std::mutex> queue_mutexes(omp_get_max_threads());
|
|
269
|
+
|
|
270
|
+
# pragma omp parallel
|
|
271
|
+
{
|
|
272
|
+
|
|
273
|
+
int tid = omp_get_thread_num();
|
|
274
|
+
std::priority_queue<rg::Point>& thread_q = local_q[tid];
|
|
275
|
+
|
|
276
|
+
// Initialize ref and def subsets
|
|
277
|
+
util::Subset ss_def(ss_size);
|
|
278
|
+
util::Subset ss_ref(ss_size);
|
|
279
|
+
|
|
280
|
+
// Optimization parameters
|
|
281
|
+
optimizer::Parameters opt(conf.num_params, conf.max_iter,
|
|
282
|
+
conf.precision, conf.opt_threshold,
|
|
283
|
+
px_vert, px_hori);
|
|
284
|
+
|
|
285
|
+
// if using SSD then not going to use opt_threshold. It can take
|
|
286
|
+
// any value. Convergence will be checked against precision only
|
|
287
|
+
if (conf.corr_crit=="SSD")
|
|
288
|
+
opt.opt_threshold = std::numeric_limits<double>::max();
|
|
289
|
+
|
|
290
|
+
brute::Parameters brute(conf.bf_threshold, conf.max_disp);
|
|
291
|
+
|
|
292
|
+
std::vector<std::unique_ptr<fourier::FFT>> fft_windows;
|
|
293
|
+
|
|
294
|
+
for (size_t t = 0; t < ssdata.size(); ++t) {
|
|
295
|
+
fft_windows.push_back(std::make_unique<fourier::FFT>(ssdata[t].size));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// TODO: for the seed location I'm going to overwride the max
|
|
299
|
+
// number of iterations to make sure we get a good convergence.
|
|
300
|
+
// this is hardcoded for now. Could do with updating so that
|
|
301
|
+
// the seed location is checked ahead of the main correlation run.
|
|
302
|
+
opt.max_iter = 200;
|
|
303
|
+
|
|
304
|
+
// ---------------------------------------------------------------------------------------------------------------------------
|
|
305
|
+
// PROCESS THE SEED SUBSET
|
|
306
|
+
// ---------------------------------------------------------------------------------------------------------------------------
|
|
307
|
+
if (tid == 0) {
|
|
308
|
+
|
|
309
|
+
// seed coordinates
|
|
310
|
+
int x = seed_x / ss_step;
|
|
311
|
+
int y = seed_y / ss_step;
|
|
312
|
+
int idx = ssdata[last_size].mask[y * ssdata[last_size].num_ss_x + x];
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
// if the first image. Take the optimization parameters from rigid fourier
|
|
316
|
+
std::fill(opt.p.begin(), opt.p.end(), 0.0);
|
|
317
|
+
opt.p[0] = fourier::shifts[last_size].x[idx];
|
|
318
|
+
opt.p[1] = fourier::shifts[last_size].y[idx];
|
|
319
|
+
|
|
320
|
+
// Extract reference subset and solve for starting seed point
|
|
321
|
+
util::extract_ss(ss_ref, seed_x, seed_y, px_hori, px_vert, img_ref);
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
double centre_x = seed_x + static_cast<double>(ss_size)/2.0 - 0.5;
|
|
325
|
+
double centre_y = seed_y + static_cast<double>(ss_size)/2.0 - 0.5;
|
|
326
|
+
|
|
327
|
+
util::Results seed_res = optimizer::solve(centre_x, centre_y, ss_ref, ss_def, interp_def, opt, conf.corr_crit);
|
|
328
|
+
|
|
329
|
+
// if its not SSD, then we need to flip the cost values so that 1.0
|
|
330
|
+
// is a perfect match rather than 0.0
|
|
331
|
+
if (conf.corr_crit!="SSD")
|
|
332
|
+
seed_res.cost = 1.0-seed_res.cost;
|
|
333
|
+
|
|
334
|
+
// append the results for the current subset to result vectors
|
|
335
|
+
util::append_results(img_num, idx, seed_res, num_ss);
|
|
336
|
+
|
|
337
|
+
computed_mask[idx].store(1);
|
|
338
|
+
|
|
339
|
+
// int progress = current_progress.fetch_add(1);
|
|
340
|
+
// util::update_progress_bar(bar, progress, num_ss, prev_pct);
|
|
341
|
+
|
|
342
|
+
// loop over the neighbours for the initial seed point
|
|
343
|
+
for (size_t n = 0; n < ssdata[last_size].neigh[idx].size(); n++) {
|
|
344
|
+
|
|
345
|
+
// subset index of neighbour to the current point
|
|
346
|
+
int nidx = ssdata[last_size].neigh[idx][n];
|
|
347
|
+
|
|
348
|
+
int nx = ssdata[last_size].coords[nidx*2];
|
|
349
|
+
int ny = ssdata[last_size].coords[nidx*2+1];
|
|
350
|
+
|
|
351
|
+
util::extract_ss(ss_ref, nx, ny, px_hori, px_vert, img_ref);
|
|
352
|
+
|
|
353
|
+
// get parameter values from fft output or from previous image
|
|
354
|
+
std::fill(opt.p.begin(), opt.p.end(), 0.0);
|
|
355
|
+
opt.p[0] = fourier::shifts[last_size].x[nidx];
|
|
356
|
+
opt.p[1] = fourier::shifts[last_size].y[nidx];
|
|
357
|
+
|
|
358
|
+
// perform optimization for seed point neighbours
|
|
359
|
+
double centre_x = nx + static_cast<double>(ss_size)/2.0 - 0.5;
|
|
360
|
+
double centre_y = ny + static_cast<double>(ss_size)/2.0 - 0.5;
|
|
361
|
+
util::Results nres = optimizer::solve(centre_x, centre_y, ss_ref, ss_def, interp_def, opt, conf.corr_crit);
|
|
362
|
+
|
|
363
|
+
// if its not SSD, then we need to flip the cost values so that 1.0
|
|
364
|
+
// is a perfect match rather than 0.0
|
|
365
|
+
if (conf.corr_crit!="SSD")
|
|
366
|
+
nres.cost = 1.0-nres.cost;
|
|
367
|
+
|
|
368
|
+
// append the results for the current subset to result vectors
|
|
369
|
+
util::append_results(img_num, nidx, nres, num_ss);
|
|
370
|
+
|
|
371
|
+
// update mask
|
|
372
|
+
computed_mask[idx].store(1);
|
|
373
|
+
|
|
374
|
+
// add this point to queue
|
|
375
|
+
// Protect push with mutex
|
|
376
|
+
{
|
|
377
|
+
std::lock_guard<std::mutex> lock(queue_mutexes[0]);
|
|
378
|
+
local_q[0].push(rg::Point(nidx,nres.cost));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// update progress bar
|
|
382
|
+
// int progress = current_progress.fetch_add(1);
|
|
383
|
+
// util::update_progress_bar(bar, progress, num_ss, prev_pct);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
// ---------------------------------------------------------------------------------------------------------------------------
|
|
389
|
+
// PROCESS ALL OTHER SUBSETS
|
|
390
|
+
// ---------------------------------------------------------------------------------------------------------------------------
|
|
391
|
+
#pragma omp barrier
|
|
392
|
+
|
|
393
|
+
opt.max_iter = conf.max_iter;
|
|
394
|
+
|
|
395
|
+
std::vector<rg::Point> temp_neigh;
|
|
396
|
+
temp_neigh.reserve(4);
|
|
397
|
+
|
|
398
|
+
const int max_idle_iters = 100;
|
|
399
|
+
rg::Point current(0, 0);
|
|
400
|
+
|
|
401
|
+
while (!stop_request) {
|
|
402
|
+
bool got_point = false;
|
|
403
|
+
int idle_iters = 0;
|
|
404
|
+
|
|
405
|
+
// Try own queue safely
|
|
406
|
+
{
|
|
407
|
+
std::lock_guard<std::mutex> lock(queue_mutexes[tid]);
|
|
408
|
+
if (!thread_q.empty()) {
|
|
409
|
+
current = thread_q.top();
|
|
410
|
+
thread_q.pop();
|
|
411
|
+
got_point = true;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Steal if nothing in own queue
|
|
416
|
+
if (!got_point) {
|
|
417
|
+
while (!got_point && idle_iters < max_idle_iters) {
|
|
418
|
+
#pragma omp critical
|
|
419
|
+
{
|
|
420
|
+
for (size_t i = 0; i < local_q.size(); ++i) {
|
|
421
|
+
std::lock_guard<std::mutex> lock(queue_mutexes[i]);
|
|
422
|
+
if (!local_q[i].empty()) {
|
|
423
|
+
current = local_q[i].top();
|
|
424
|
+
local_q[i].pop();
|
|
425
|
+
got_point = true;
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (!got_point) {
|
|
431
|
+
++idle_iters;
|
|
432
|
+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (!got_point) {
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
temp_neigh.clear();
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
// index of current point in results arrays
|
|
445
|
+
int idx_results = save_at_end ? img_num * num_ss + current.idx : current.idx;
|
|
446
|
+
int idx_results_p = idx_results * opt.num_params;
|
|
447
|
+
|
|
448
|
+
// loop over neighbouring points
|
|
449
|
+
for (size_t n = 0; n < ssdata[last_size].neigh[current.idx].size(); n++) {
|
|
450
|
+
|
|
451
|
+
// subset index of neighbour to the current point
|
|
452
|
+
int nidx = ssdata[last_size].neigh[current.idx][n];
|
|
453
|
+
|
|
454
|
+
int expected = 0;
|
|
455
|
+
expected = computed_mask[nidx].exchange(1);
|
|
456
|
+
if (expected == 0) {
|
|
457
|
+
|
|
458
|
+
// coords of neigh
|
|
459
|
+
int nx = ssdata[last_size].coords[nidx*2];
|
|
460
|
+
int ny = ssdata[last_size].coords[nidx*2+1];
|
|
461
|
+
|
|
462
|
+
// extract subset
|
|
463
|
+
util::extract_ss(ss_ref, nx, ny, px_hori, px_vert, img_ref);
|
|
464
|
+
|
|
465
|
+
// if the neighbouring subset had not met correlation threshold then try values from fft windowing
|
|
466
|
+
if (util::cost_arr[idx_results] < opt.opt_threshold){
|
|
467
|
+
std::fill(opt.p.begin(), opt.p.end(), 0.0);
|
|
468
|
+
opt.p[0] = fourier::shifts[last_size].x[nidx];
|
|
469
|
+
opt.p[1] = fourier::shifts[last_size].y[nidx];
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
for (int i = 0; i < opt.num_params; i++){
|
|
473
|
+
opt.p[i] = util::p_arr[idx_results_p+i];
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// optimize
|
|
478
|
+
double centre_x = nx + static_cast<double>(ss_size)/2.0 - 0.5;
|
|
479
|
+
double centre_y = ny + static_cast<double>(ss_size)/2.0 - 0.5;
|
|
480
|
+
util::Results nres = optimizer::solve(centre_x, centre_y, ss_ref, ss_def, interp_def, opt, conf.corr_crit);
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
// if its not SSD, then we need to flip the cost values so that 1.0
|
|
484
|
+
// is a perfect match rather than 0.0
|
|
485
|
+
if (conf.corr_crit!="SSD")
|
|
486
|
+
nres.cost = 1.0-nres.cost;
|
|
487
|
+
|
|
488
|
+
// append results
|
|
489
|
+
#pragma omp critical
|
|
490
|
+
util::append_results(img_num, nidx, nres, num_ss);
|
|
491
|
+
|
|
492
|
+
// add results to temp neighbour results
|
|
493
|
+
temp_neigh.emplace_back(nidx, nres.cost);
|
|
494
|
+
|
|
495
|
+
// update progress bar
|
|
496
|
+
int progress = current_progress.fetch_add(1);
|
|
497
|
+
util::update_progress_bar(bar, progress, num_ss, prev_pct);
|
|
498
|
+
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
for (const auto& neigh : temp_neigh) {
|
|
503
|
+
std::lock_guard<std::mutex> lock(queue_mutexes[tid]);
|
|
504
|
+
thread_q.push(neigh);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
bar.mark_as_completed();
|
|
509
|
+
indicators::show_console_cursor(true);
|
|
510
|
+
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
void multi_window_fourier(const double *img_ref,
|
|
515
|
+
const double *img_def,
|
|
516
|
+
const Interpolator &interp_def,
|
|
517
|
+
const std::vector<util::SubsetData> &ssdata,
|
|
518
|
+
const util::Config &conf,
|
|
519
|
+
const int img_num){
|
|
520
|
+
|
|
521
|
+
// for the first image perform the FFT windowing. later images will be
|
|
522
|
+
// seeded with previous images
|
|
523
|
+
fourier::mgwd(ssdata, img_ref, img_def, interp_def,
|
|
524
|
+
conf.fft_mad, conf.fft_mad_scale);
|
|
525
|
+
|
|
526
|
+
const int nsizes = ssdata.size();
|
|
527
|
+
const int last_size = nsizes-1;
|
|
528
|
+
|
|
529
|
+
// get number of subsets and the size for the smalllest window size
|
|
530
|
+
const int num_ss = ssdata[last_size].num;
|
|
531
|
+
const int ss_size = ssdata[last_size].size;
|
|
532
|
+
|
|
533
|
+
// progress bar
|
|
534
|
+
indicators::ProgressBar bar;
|
|
535
|
+
util::create_progress_bar(bar, conf.filenames, img_num, num_ss);
|
|
536
|
+
std::atomic<int> current_progress = 0;
|
|
537
|
+
std::atomic<int> prev_pct = 0;
|
|
538
|
+
|
|
539
|
+
// loop over subsets within the ROI
|
|
540
|
+
#pragma omp parallel shared(stop_request)
|
|
541
|
+
{
|
|
542
|
+
|
|
543
|
+
// initialise subsets
|
|
544
|
+
util::Subset ss_def(ss_size);
|
|
545
|
+
util::Subset ss_ref(ss_size);
|
|
546
|
+
|
|
547
|
+
// optimization parameters
|
|
548
|
+
optimizer::Parameters opt(conf.num_params, conf.max_iter,
|
|
549
|
+
conf.precision, conf.opt_threshold,
|
|
550
|
+
conf.px_vert, conf.px_hori);
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
#pragma omp for
|
|
554
|
+
for (int ss = 0; ss < num_ss; ss++){
|
|
555
|
+
|
|
556
|
+
// exit the main DIC loop when ctrl+C is hit
|
|
557
|
+
if (stop_request){
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// subset coordinate list takes central locations.
|
|
562
|
+
// Converting to top left corner for optimization routine
|
|
563
|
+
int ss_x = ssdata[last_size].coords[ss*2];
|
|
564
|
+
int ss_y = ssdata[last_size].coords[ss*2+1];
|
|
565
|
+
|
|
566
|
+
// get the reference subset
|
|
567
|
+
util::extract_ss(ss_ref, ss_x, ss_y, conf.px_hori, conf.px_vert, img_ref);
|
|
568
|
+
|
|
569
|
+
std::fill(opt.p.begin(), opt.p.end(), 0.0);
|
|
570
|
+
opt.p[0] = fourier::shifts[last_size].x[ss];
|
|
571
|
+
opt.p[1] = fourier::shifts[last_size].y[ss];
|
|
572
|
+
|
|
573
|
+
// perform optimization on subset from deformed image
|
|
574
|
+
double centre_x = ss_x + static_cast<double>(ss_size)/2.0 - 0.5;
|
|
575
|
+
double centre_y = ss_y + static_cast<double>(ss_size)/2.0 - 0.5;
|
|
576
|
+
util::Results res = optimizer::solve(centre_x, centre_y, ss_ref, ss_def, interp_def, opt, conf.corr_crit);
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
// if its not SSD, then we need to flip the cost values so that 1.0
|
|
580
|
+
// is a perfect match rather than 0.0
|
|
581
|
+
if (conf.corr_crit!="SSD")
|
|
582
|
+
res.cost = 1.0-res.cost;
|
|
583
|
+
|
|
584
|
+
// append optimization results to results vectors
|
|
585
|
+
#pragma omp critical
|
|
586
|
+
util::append_results(img_num, ss, res, num_ss);
|
|
587
|
+
|
|
588
|
+
// update progress bar
|
|
589
|
+
int progress = current_progress.fetch_add(1);
|
|
590
|
+
util::update_progress_bar(bar, progress, num_ss, prev_pct);
|
|
591
|
+
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
bar.mark_as_completed();
|
|
595
|
+
indicators::show_console_cursor(true);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
void single_window_fourier(const double *img_ref,
|
|
600
|
+
const double *img_def,
|
|
601
|
+
const Interpolator &interp_def,
|
|
602
|
+
const util::SubsetData &ssdata,
|
|
603
|
+
const util::Config &conf,
|
|
604
|
+
const int img_num){
|
|
605
|
+
|
|
606
|
+
// for the first image perform the FFT windowing. later images will be
|
|
607
|
+
// seeded with previous images
|
|
608
|
+
fourier::sgwd(ssdata, 256, img_ref, img_def, interp_def);
|
|
609
|
+
|
|
610
|
+
// get number of subsets and the size for the smalllest window size
|
|
611
|
+
const int num_ss = ssdata.num;
|
|
612
|
+
const int ss_size = ssdata.size;
|
|
613
|
+
|
|
614
|
+
// progress bar
|
|
615
|
+
indicators::ProgressBar bar;
|
|
616
|
+
util::create_progress_bar(bar, conf.filenames, img_num, num_ss);
|
|
617
|
+
std::atomic<int> current_progress = 0;
|
|
618
|
+
std::atomic<int> prev_pct = 0;
|
|
619
|
+
|
|
620
|
+
// loop over subsets within the ROI
|
|
621
|
+
#pragma omp parallel shared(stop_request)
|
|
622
|
+
{
|
|
623
|
+
|
|
624
|
+
// initialise subsets
|
|
625
|
+
util::Subset ss_def(ss_size);
|
|
626
|
+
util::Subset ss_ref(ss_size);
|
|
627
|
+
|
|
628
|
+
// optimization parameters
|
|
629
|
+
optimizer::Parameters opt(conf.num_params, conf.max_iter,
|
|
630
|
+
conf.precision, conf.opt_threshold,
|
|
631
|
+
conf.px_vert, conf.px_hori);
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
#pragma omp for
|
|
635
|
+
for (int ss = 0; ss < num_ss; ss++){
|
|
636
|
+
|
|
637
|
+
// exit the main DIC loop when ctrl+C is hit
|
|
638
|
+
if (stop_request){
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// subset coordinate list takes central locations.
|
|
643
|
+
// Converting to top left corner for optimization routine
|
|
644
|
+
int ss_x = ssdata.coords[ss*2];
|
|
645
|
+
int ss_y = ssdata.coords[ss*2+1];
|
|
646
|
+
|
|
647
|
+
// get the reference subset
|
|
648
|
+
util::extract_ss(ss_ref, ss_x, ss_y, conf.px_hori, conf.px_vert, img_ref);
|
|
649
|
+
|
|
650
|
+
std::fill(opt.p.begin(), opt.p.end(), 0.0);
|
|
651
|
+
opt.p[0] = fourier::shifts[0].x[ss];
|
|
652
|
+
opt.p[1] = fourier::shifts[0].y[ss];
|
|
653
|
+
|
|
654
|
+
// perform optimization on subset from deformed image
|
|
655
|
+
double centre_x = ss_x + static_cast<double>(ss_size)/2.0 - 0.5;
|
|
656
|
+
double centre_y = ss_y + static_cast<double>(ss_size)/2.0 - 0.5;
|
|
657
|
+
util::Results res = optimizer::solve(centre_x, centre_y, ss_ref, ss_def, interp_def, opt, conf.corr_crit);
|
|
658
|
+
|
|
659
|
+
// if its not SSD, then we need to flip the cost values so that 1.0
|
|
660
|
+
// is a perfect match rather than 0.0
|
|
661
|
+
if (conf.corr_crit!="SSD")
|
|
662
|
+
res.cost = 1.0-res.cost;
|
|
663
|
+
|
|
664
|
+
// append optimization results to results vectors
|
|
665
|
+
util::append_results(img_num, ss, res, num_ss);
|
|
666
|
+
|
|
667
|
+
// update progress bar
|
|
668
|
+
int progress = current_progress.fetch_add(1);
|
|
669
|
+
util::update_progress_bar(bar, progress, num_ss, prev_pct);
|
|
670
|
+
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
bar.mark_as_completed();
|
|
674
|
+
indicators::show_console_cursor(true);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
}
|