d2/align: raw migration of alignment state structure to Libale.
[Ale.git] / d2 / align.h
Commit [+] Author Date Line Data
8a81d3be
DH
David Hilvert2007-04-03 18:57:00 +00001// Copyright 2002, 2004, 2007 David Hilvert <dhilvert@auricle.dyndns.org>,
2// <dhilvert@ugcs.caltech.edu>
30afe4b6 dhilvert2005-01-07 06:42:00 +00003
4/* This file is part of the Anti-Lamenessing Engine.
5
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
70932f40 David Hilvert2007-07-19 21:14:00 +00008 the Free Software Foundation; either version 3 of the License, or
30afe4b6 dhilvert2005-01-07 06:42:00 +00009 (at your option) any later version.
10
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/*
22 * align.h: Handle alignment of frames.
23 */
24
25#ifndef __d2align_h__
26#define __d2align_h__
27
46f9776a dhilvert2005-01-07 06:44:00 +000028#include "filter.h"
29#include "transformation.h"
30afe4b6 dhilvert2005-01-07 06:42:00 +000030#include "image.h"
31#include "point.h"
32#include "render.h"
33#include "tfile.h"
34#include "image_rw.h"
35
36class align {
37private:
38
39 /*
40 * Private data members
41 */
42
43 static ale_pos scale_factor;
44
45 /*
46f9776a dhilvert2005-01-07 06:44:00 +000046 * Original frame transformation
47 */
48 static transformation orig_t;
49
50 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +000051 * Keep data older than latest
52 */
53 static int _keep;
54 static transformation *kept_t;
55 static int *kept_ok;
56
57 /*
58 * Transformation file handlers
59 */
60
61 static tload_t *tload;
62 static tsave_t *tsave;
63
64 /*
04382119 dhilvert2005-04-29 09:23:00 +000065 * Control point variables
66 */
67
68 static const point **cp_array;
69 static unsigned int cp_count;
70
71 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +000072 * Reference rendering to align against
73 */
74
75 static render *reference;
46f9776a dhilvert2005-01-07 06:44:00 +000076 static filter::scaled_filter *interpolant;
3617b771 David Hilvert2009-05-31 15:07:14 +000077 static ale_image reference_image;
30afe4b6 dhilvert2005-01-07 06:42:00 +000078
46f9776a dhilvert2005-01-07 06:44:00 +000079 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +000080 * Per-pixel alignment weight map
46f9776a dhilvert2005-01-07 06:44:00 +000081 */
82
2f4c0699 David Hilvert2009-06-03 19:47:53 +000083 static ale_image weight_map;
46f9776a dhilvert2005-01-07 06:44:00 +000084
85 /*
86 * Frequency-dependent alignment weights
87 */
88
89 static double horiz_freq_cut;
90 static double vert_freq_cut;
91 static double avg_freq_cut;
46f9776a dhilvert2005-01-07 06:44:00 +000092 static const char *fw_output;
93
94 /*
95 * Algorithmic alignment weighting
96 */
97
98 static const char *wmx_exec;
99 static const char *wmx_file;
100 static const char *wmx_defs;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000101
102 /*
19b07c65 David Hilvert2007-09-11 18:07:00 +0000103 * Non-certainty alignment weights
2aa417e6 dhilvert2005-01-07 06:44:00 +0000104 */
105
c2d1a70e David Hilvert2009-05-30 15:37:04 +0000106 static ale_image alignment_weights;
46f9776a dhilvert2005-01-07 06:44:00 +0000107
30afe4b6 dhilvert2005-01-07 06:42:00 +0000108 /*
109 * Latest transformation.
110 */
111
112 static transformation latest_t;
113
114 /*
115 * Flag indicating whether the latest transformation
116 * resulted in a match.
117 */
118
119 static int latest_ok;
120
121 /*
122 * Frame number most recently aligned.
123 */
124
125 static int latest;
126
127 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000128 * Exposure registration
129 *
130 * 0. Preserve the original exposure of images.
131 *
132 * 1. Match exposure between images.
3dc20778 dhilvert2005-01-10 23:06:00 +0000133 *
134 * 2. Use only image metadata for registering exposure.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000135 */
136
137 static int _exp_register;
138
139 /*
140 * Alignment class.
141 *
142 * 0. Translation only. Only adjust the x and y position of images.
143 * Do not rotate input images or perform projective transformations.
144 *
145 * 1. Euclidean transformations only. Adjust the x and y position
146 * of images and the orientation of the image about the image center.
147 *
148 * 2. Perform general projective transformations. See the file gpt.h
149 * for more information about general projective transformations.
150 */
151
152 static int alignment_class;
153
154 /*
0a432b63 David Hilvert2007-03-13 08:03:00 +0000155 * Default initial alignment type.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000156 *
157 * 0. Identity transformation.
158 *
159 * 1. Most recently accepted frame's final transformation.
160 */
161
162 static int default_initial_alignment_type;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000163
164 /*
f09b7254 dhilvert2005-01-07 06:44:00 +0000165 * Projective group behavior
166 *
167 * 0. Perturb in output coordinates.
168 *
169 * 1. Perturb in source coordinates
170 */
171
172 static int perturb_type;
173
174 /*
46f9776a dhilvert2005-01-07 06:44:00 +0000175 * Alignment for failed frames -- default or optimal?
176 *
177 * A frame that does not meet the match threshold can be assigned the
178 * best alignment found, or can be assigned its alignment default.
179 */
180
181 static int is_fail_default;
182
183 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000184 * Alignment code.
185 *
186 * 0. Align images with an error contribution from each color channel.
187 *
188 * 1. Align images with an error contribution only from the green channel.
189 * Other color channels do not affect alignment.
190 *
191 * 2. Align images using a summation of channels. May be useful when dealing
192 * with images that have high frequency color ripples due to color aliasing.
193 */
194
195 static int channel_alignment_type;
196
197 /*
198 * Error metric exponent
199 */
200
42772195 David Hilvert2007-10-21 15:36:00 +0000201 static ale_real metric_exponent;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000202
203 /*
204 * Match threshold
205 */
206
207 static float match_threshold;
208
209 /*
210 * Perturbation lower and upper bounds.
211 */
212
213 static ale_pos perturb_lower;
f09b7254 dhilvert2005-01-07 06:44:00 +0000214 static int perturb_lower_percent;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000215 static ale_pos perturb_upper;
f09b7254 dhilvert2005-01-07 06:44:00 +0000216 static int perturb_upper_percent;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000217
218 /*
5292ffa7 David Hilvert2008-05-28 01:17:53 +0000219 * Preferred level-of-detail scale factor is 2^lod_preferred/perturb.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000220 */
221
5292ffa7
DH
David Hilvert2008-05-28 01:17:53 +0000222 static int lod_preferred;
223
224 /*
225 * Minimum dimension for reduced LOD.
226 */
227
228 static int min_dimension;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000229
230 /*
231 * Maximum rotational perturbation
232 */
233
234 static ale_pos rot_max;
235
236 /*
46f9776a dhilvert2005-01-07 06:44:00 +0000237 * Barrel distortion alignment multiplier
238 */
239
240 static ale_pos bda_mult;
241
242 /*
243 * Barrel distortion maximum adjustment rate
244 */
245
246 static ale_pos bda_rate;
247
248 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000249 * Alignment match sum
250 */
251
252 static ale_accum match_sum;
253
254 /*
255 * Alignment match count.
256 */
257
258 static int match_count;
259
260 /*
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000261 * Monte Carlo parameter
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +0000262 */
263
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000264 static ale_pos _mc;
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +0000265
266 /*
07271611 dhilvert2005-01-07 06:48:00 +0000267 * Certainty weight flag
268 *
269 * 0. Don't use certainty weights for alignment.
270 *
271 * 1. Use certainty weights for alignment.
272 */
273
274 static int certainty_weights;
275
276 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +0000277 * Global search parameter
278 *
7bcfe5db dhilvert2005-01-07 06:44:00 +0000279 * 0. Local: Local search only.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000280 * 1. Inner: Alignment reference image inner region
281 * 2. Outer: Alignment reference image outer region
7bcfe5db dhilvert2005-01-07 06:44:00 +0000282 * 3. All: Alignment reference image inner and outer regions.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000283 * 4. Central: Inner if possible; else, best of inner and outer.
04382119 dhilvert2005-04-29 09:23:00 +0000284 * 5. Points: Align by control points.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000285 */
286
287 static int _gs;
288
289 /*
4949c031 dhilvert2005-01-07 06:44:00 +0000290 * Minimum overlap for global searches
291 */
292
a7882498 David Hilvert2007-10-16 19:48:00 +0000293 static ale_accum _gs_mo;
326c35b1 David Hilvert2007-04-19 21:28:00 +0000294 static int gs_mo_percent;
4949c031 dhilvert2005-01-07 06:44:00 +0000295
296 /*
903df240
DH
David Hilvert2008-04-24 14:36:35 +0000297 * Minimum certainty for multi-alignment element registration.
298 */
299
300 static ale_real _ma_cert;
301
302 /*
46f9776a dhilvert2005-01-07 06:44:00 +0000303 * Exclusion regions
304 */
305
df55d1a2 dhilvert2006-08-30 07:40:00 +0000306 static exclusion *ax_parameters;
46f9776a dhilvert2005-01-07 06:44:00 +0000307 static int ax_count;
308
309 /*
773018a3 David Hilvert2007-09-07 15:14:00 +0000310 * Types for scale clusters.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000311 */
312
773018a3
DH
David Hilvert2007-09-07 15:14:00 +0000313 struct nl_scale_cluster {
314 const image *accum_max;
315 const image *accum_min;
580b5321
DH
David Hilvert2007-09-10 17:35:00 +0000316 const image *certainty_max;
317 const image *certainty_min;
773018a3
DH
David Hilvert2007-09-07 15:14:00 +0000318 const image *aweight_max;
319 const image *aweight_min;
320 exclusion *ax_parameters;
321
322 ale_pos input_scale;
e7f30dec
DH
David Hilvert2007-09-21 19:25:00 +0000323 const image *input_certainty_max;
324 const image *input_certainty_min;
773018a3
DH
David Hilvert2007-09-07 15:14:00 +0000325 const image *input_max;
326 const image *input_min;
327 };
328
2aa417e6 dhilvert2005-01-07 06:44:00 +0000329 struct scale_cluster {
330 const image *accum;
580b5321 David Hilvert2007-09-10 17:35:00 +0000331 const image *certainty;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000332 const image *aweight;
df55d1a2 dhilvert2006-08-30 07:40:00 +0000333 exclusion *ax_parameters;
07271611 dhilvert2005-01-07 06:48:00 +0000334
335 ale_pos input_scale;
e7f30dec David Hilvert2007-09-21 19:25:00 +0000336 const image *input_certainty;
07271611 dhilvert2005-01-07 06:48:00 +0000337 const image *input;
46cc7d96
DH
David Hilvert2007-09-07 17:18:00 +0000338
339 nl_scale_cluster *nl_scale_clusters;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000340 };
341
342 /*
df55d1a2 dhilvert2006-08-30 07:40:00 +0000343 * Check for exclusion region coverage in the reference
344 * array.
345 */
346 static int ref_excluded(int i, int j, point offset, exclusion *params, int param_count) {
347 for (int idx = 0; idx < param_count; idx++)
348 if (params[idx].type == exclusion::RENDER
349 && i + offset[0] >= params[idx].x[0]
350 && i + offset[0] <= params[idx].x[1]
351 && j + offset[1] >= params[idx].x[2]
352 && j + offset[1] <= params[idx].x[3])
353 return 1;
354
355 return 0;
356 }
357
358 /*
359 * Check for exclusion region coverage in the input
360 * array.
361 */
362 static int input_excluded(ale_pos ti, ale_pos tj, exclusion *params, int param_count) {
363 for (int idx = 0; idx < param_count; idx++)
364 if (params[idx].type == exclusion::FRAME
365 && ti >= params[idx].x[0]
366 && ti <= params[idx].x[1]
367 && tj >= params[idx].x[2]
368 && tj <= params[idx].x[3])
369 return 1;
370
371 return 0;
372 }
373
374 /*
4949c031 dhilvert2005-01-07 06:44:00 +0000375 * Overlap function. Determines the number of pixels in areas where
376 * the arrays overlap. Uses the reference array's notion of pixel
377 * positions.
378 */
379 static unsigned int overlap(struct scale_cluster c, transformation t, int ax_count) {
380 assert (reference_image);
381
382 unsigned int result = 0;
383
384 point offset = c.accum->offset();
385
386 for (unsigned int i = 0; i < c.accum->height(); i++)
387 for (unsigned int j = 0; j < c.accum->width(); j++) {
388
df55d1a2 dhilvert2006-08-30 07:40:00 +0000389 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
4949c031 dhilvert2005-01-07 06:44:00 +0000390 continue;
391
392 /*
393 * Transform
394 */
395
396 struct point q;
397
07271611 dhilvert2005-01-07 06:48:00 +0000398 q = (c.input_scale < 1.0 && interpolant == NULL)
399 ? t.scaled_inverse_transform(
400 point(i + offset[0], j + offset[1]))
401 : t.unscaled_inverse_transform(
4949c031 dhilvert2005-01-07 06:44:00 +0000402 point(i + offset[0], j + offset[1]));
403
404 ale_pos ti = q[0];
405 ale_pos tj = q[1];
406
407 /*
408 * Check that the transformed coordinates are within
409 * the boundaries of array c.input, and check that the
410 * weight value in the accumulated array is nonzero,
411 * unless we know it is nonzero by virtue of the fact
412 * that it falls within the region of the original
413 * frame (e.g. when we're not increasing image
df55d1a2 dhilvert2006-08-30 07:40:00 +0000414 * extents). Also check for frame exclusion.
4949c031 dhilvert2005-01-07 06:44:00 +0000415 */
416
df55d1a2 dhilvert2006-08-30 07:40:00 +0000417 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
418 continue;
419
4949c031 dhilvert2005-01-07 06:44:00 +0000420 if (ti >= 0
421 && ti <= c.input->height() - 1
422 && tj >= 0
423 && tj <= c.input->width() - 1
580b5321 David Hilvert2007-09-10 17:35:00 +0000424 && c.certainty->get_pixel(i, j)[0] != 0)
4949c031 dhilvert2005-01-07 06:44:00 +0000425 result++;
426 }
427
428 return result;
429 }
430
431 /*
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000432 * Monte carlo iteration class.
433 *
434 * Monte Carlo alignment has been used for statistical comparisons in
435 * spatial registration, and is now used for tonal registration
436 * and final match calculation.
437 */
438
439 /*
440 * We use a random process for which the expected number of sampled
441 * pixels is +/- .000003 from the coverage in the range [.005,.995] for
442 * an image with 100,000 pixels. (The actual number may still deviate
443 * from the expected number by more than this amount, however.) The
444 * method is as follows:
445 *
446 * We have coverage == USE/ALL, or (expected # pixels to use)/(# total
447 * pixels). We derive from this SKIP/USE.
448 *
449 * SKIP/USE == (SKIP/ALL)/(USE/ALL) == (1 - (USE/ALL))/(USE/ALL)
450 *
451 * Once we have SKIP/USE, we know the expected number of pixels to skip
452 * in each iteration. We use a random selection process that provides
453 * SKIP/USE close to this calculated value.
454 *
455 * If we can draw uniformly to select the number of pixels to skip, we
456 * do. In this case, the maximum number of pixels to skip is twice the
457 * expected number.
458 *
459 * If we cannot draw uniformly, we still assign equal probability to
460 * each of the integer values in the interval [0, 2 * (SKIP/USE)], but
461 * assign an unequal amount to the integer value ceil(2 * SKIP/USE) +
462 * 1.
463 */
464
465 /*
466 * When reseeding the random number generator, we want the same set of
467 * pixels to be used in cases where two alignment options are compared.
468 * If we wanted to avoid bias from repeatedly utilizing the same seed,
469 * we could seed with the number of the frame most recently aligned:
470 *
471 * srand(latest);
472 *
473 * However, in cursory tests, it seems okay to just use the default
474 * seed of 1, and so we do this, since it is simpler; both of these
475 * approaches to reseeding achieve better results than not reseeding.
476 * (1 is the default seed according to the GNU Manual Page for
477 * rand(3).)
478 *
479 * For subdomain calculations, we vary the seed by adding the subdomain
480 * index.
481 */
482
483 class mc_iterate {
484 ale_pos mc_max;
485 unsigned int index;
486 unsigned int index_max;
487 int i_min;
488 int i_max;
489 int j_min;
490 int j_max;
491
492 rng_t rng;
493
63f46ff7 David Hilvert2007-09-21 00:03:00 +0000494 public:
f0af1fea
DH
David Hilvert2007-09-20 23:22:00 +0000495 mc_iterate(int _i_min, int _i_max, int _j_min, int _j_max, unsigned int subdomain)
496 : rng() {
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000497
498 ale_pos coverage;
499
500 i_min = _i_min;
501 i_max = _i_max;
502 j_min = _j_min;
503 j_max = _j_max;
504
a0c28c9a
DH
David Hilvert2008-03-23 15:55:54 -0500505 if (i_max < i_min || j_max < j_min)
506 index_max = 0;
507 else
508 index_max = (i_max - i_min) * (j_max - j_min);
699711e2 David Hilvert2007-09-20 21:03:00 +0000509
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000510 if (index_max < 500 || _mc > 100 || _mc <= 0)
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000511 coverage = 1;
512 else
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000513 coverage = _mc / 100;
699711e2 David Hilvert2007-09-20 21:03:00 +0000514
a85f57f9 David Hilvert2007-10-15 17:07:00 +0000515 double su = (1 - coverage) / coverage;
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000516
517 mc_max = (floor(2*su) * (1 + floor(2*su)) + 2*su)
518 / (2 + 2 * floor(2*su) - 2*su);
519
520 rng.seed(1 + subdomain);
521
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000522#define FIXED16 3
523#if ALE_COORDINATES == FIXED16
524 /*
525 * XXX: This calculation might not yield the correct
526 * expected value.
527 */
e4a3555e
DH
David Hilvert2007-10-24 22:37:00 +0000528 index = -1 + (int) ceil(((ale_pos) mc_max+1)
529 / (ale_pos) ( (1 + 0xffffff)
530 / (1 + (rng.get() & 0xffffff))));
793fc1a6 David Hilvert2007-10-25 16:36:00 +0000531#else
ff364936 David Hilvert2007-10-26 23:35:00 +0000532 index = -1 + (int) ceil((ale_accum) (mc_max+1)
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000533 * ( (1 + ((ale_accum) (rng.get())) )
534 / (1 + ((ale_accum) RAND_MAX)) ));
535#endif
536#undef FIXED16
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000537 }
538
539 int get_i() {
540 return index / (j_max - j_min) + i_min;
541 }
542
543 int get_j() {
544 return index % (j_max - j_min) + j_min;
545 }
546
63f46ff7 David Hilvert2007-09-21 00:03:00 +0000547 void operator++(int whats_this_for) {
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000548#define FIXED16 3
549#if ALE_COORDINATES == FIXED16
e4a3555e
DH
David Hilvert2007-10-24 22:37:00 +0000550 index += (int) ceil(((ale_pos) mc_max+1)
551 / (ale_pos) ( (1 + 0xffffff)
552 / (1 + (rng.get() & 0xffffff))));
793fc1a6 David Hilvert2007-10-25 16:36:00 +0000553#else
ff364936 David Hilvert2007-10-26 23:35:00 +0000554 index += (int) ceil((ale_accum) (mc_max+1)
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000555 * ( (1 + ((ale_accum) (rng.get())) )
556 / (1 + ((ale_accum) RAND_MAX)) ));
557#endif
558#undef FIXED16
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000559 }
560
561 int done() {
562 return (index >= index_max);
563 }
564 };
565
566 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000567 * Not-quite-symmetric difference function. Determines the difference in areas
4949c031 dhilvert2005-01-07 06:44:00 +0000568 * where the arrays overlap. Uses the reference array's notion of pixel positions.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000569 *
570 * For the purposes of determining the difference, this function divides each
571 * pixel value by the corresponding image's average pixel magnitude, unless we
572 * are:
573 *
574 * a) Extending the boundaries of the image, or
575 *
576 * b) following the previous frame's transform
577 *
578 * If we are doing monte-carlo pixel sampling for alignment, we
579 * typically sample a subset of available pixels; otherwise, we sample
580 * all pixels.
581 *
582 */
4707675e dhilvert2006-10-19 10:24:00 +0000583
f8864302
DH
David Hilvert2008-04-11 18:15:57 +0000584 template<class diff_trans>
585 class diff_stat_generic {
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000586
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000587 transformation::elem_bounds_t elem_bounds;
e492922d David Hilvert2007-05-09 05:53:00 +0000588
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000589 struct run {
590
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000591 diff_trans offset;
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000592
593 ale_accum result;
594 ale_accum divisor;
595
596 point max, min;
597 ale_accum centroid[2], centroid_divisor;
598 ale_accum de_centroid[2], de_centroid_v, de_sum;
599
5d53e401 David Hilvert2007-05-02 03:12:00 +0000600 void init() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000601
602 result = 0;
603 divisor = 0;
e492922d David Hilvert2007-05-09 05:53:00 +0000604
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000605 min = point::posinf();
606 max = point::neginf();
607
608 centroid[0] = 0;
609 centroid[1] = 0;
610 centroid_divisor = 0;
611
612 de_centroid[0] = 0;
613 de_centroid[1] = 0;
614
615 de_centroid_v = 0;
616
617 de_sum = 0;
618 }
619
1b980378 David Hilvert2008-07-18 18:30:40 +0000620 void init(diff_trans _offset) {
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +0000621 offset = _offset;
622 init();
623 }
624
625 /*
626 * Required for STL sanity.
627 */
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000628 run() : offset(diff_trans::eu_identity()) {
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +0000629 init();
630 }
631
1b980378
DH
David Hilvert2008-07-18 18:30:40 +0000632 run(diff_trans _offset) : offset(_offset) {
633 init(_offset);
e492922d
DH
David Hilvert2007-05-09 05:53:00 +0000634 }
635
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000636 void add(const run &_run) {
637 result += _run.result;
638 divisor += _run.divisor;
639
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000640 for (int d = 0; d < 2; d++) {
641 if (min[d] > _run.min[d])
642 min[d] = _run.min[d];
643 if (max[d] < _run.max[d])
644 max[d] = _run.max[d];
645 centroid[d] += _run.centroid[d];
646 de_centroid[d] += _run.de_centroid[d];
647 }
648
649 centroid_divisor += _run.centroid_divisor;
650 de_centroid_v += _run.de_centroid_v;
651 de_sum += _run.de_sum;
652 }
653
283c3ecc David Hilvert2008-01-26 01:36:00 +0000654 run(const run &_run) : offset(_run.offset) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000655
656 /*
657 * Initialize
658 */
1b980378 David Hilvert2008-07-18 18:30:40 +0000659 init(_run.offset);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000660
661 /*
662 * Add
663 */
664 add(_run);
665 }
666
667 run &operator=(const run &_run) {
668
669 /*
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000670 * Initialize
671 */
1b980378 David Hilvert2008-07-18 18:30:40 +0000672 init(_run.offset);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000673
674 /*
675 * Add
676 */
677 add(_run);
678
679 return *this;
680 }
681
682 ~run() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000683 }
684
685 ale_accum get_error() const {
c9968081 David Hilvert2007-10-24 02:54:00 +0000686 return pow(result / divisor, 1/(ale_accum) metric_exponent);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000687 }
688
368d214e
DH
David Hilvert2007-05-09 07:57:00 +0000689 void sample(int f, scale_cluster c, int i, int j, point t, point u,
690 const run &comparison) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000691
692 pixel pa = c.accum->get_pixel(i, j);
693
42772195
DH
David Hilvert2007-10-21 15:36:00 +0000694 ale_real this_result[2] = { 0, 0 };
695 ale_real this_divisor[2] = { 0, 0 };
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000696
f064b1a9
DH
David Hilvert2007-09-21 21:21:00 +0000697 pixel p[2];
698 pixel weight[2];
699 weight[0] = pixel(1, 1, 1);
700 weight[1] = pixel(1, 1, 1);
701
ca7acd56 David Hilvert2008-06-05 23:43:51 +0000702 pixel tm = offset.get_tonal_multiplier(point(i, j) + c.accum->offset());
28e6b6f7 David Hilvert2008-06-05 02:36:34 +0000703
1e559234 David Hilvert2007-09-11 19:34:00 +0000704 if (interpolant != NULL) {
4132897c
DH
David Hilvert2007-10-26 18:13:00 +0000705 interpolant->filtered(i, j, &p[0], &weight[0], 1, f);
706
fa3844c7 David Hilvert2007-10-26 18:39:00 +0000707 if (weight[0].min_norm() > ale_real_weight_floor) {
4132897c
DH
David Hilvert2007-10-26 18:13:00 +0000708 p[0] /= weight[0];
709 } else {
710 return;
711 }
712
1e559234 David Hilvert2007-09-11 19:34:00 +0000713 } else {
e7f30dec David Hilvert2007-09-21 19:25:00 +0000714 p[0] = c.input->get_bl(t);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000715 }
716
28e6b6f7 David Hilvert2008-06-05 02:36:34 +0000717 p[0] *= tm;
64e05da1 David Hilvert2008-05-05 16:21:18 -0500718
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000719 if (u.defined()) {
19b07c65 David Hilvert2007-09-11 18:07:00 +0000720 p[1] = c.input->get_bl(u);
28e6b6f7 David Hilvert2008-06-05 02:36:34 +0000721 p[1] *= tm;
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000722 }
723
724
725 /*
726 * Handle certainty.
727 */
728
f064b1a9 David Hilvert2007-09-21 21:21:00 +0000729 if (certainty_weights == 1) {
32ec9768
DH
David Hilvert2007-09-21 23:14:00 +0000730
731 /*
732 * For speed, use arithmetic interpolation (get_bl(.))
733 * instead of geometric (get_bl(., 1))
734 */
735
736 weight[0] *= c.input_certainty->get_bl(t);
c4fb894c David Hilvert2007-09-21 22:44:00 +0000737 if (u.defined())
32ec9768 David Hilvert2007-09-21 23:14:00 +0000738 weight[1] *= c.input_certainty->get_bl(u);
e7f30dec
DH
David Hilvert2007-09-21 19:25:00 +0000739 weight[0] *= c.certainty->get_pixel(i, j);
740 weight[1] *= c.certainty->get_pixel(i, j);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000741 }
742
743 if (c.aweight != NULL) {
744 weight[0] *= c.aweight->get_pixel(i, j);
745 weight[1] *= c.aweight->get_pixel(i, j);
746 }
747
748 /*
749 * Update sampling area statistics
750 */
751
752 if (min[0] > i)
753 min[0] = i;
754 if (min[1] > j)
755 min[1] = j;
756 if (max[0] < i)
757 max[0] = i;
758 if (max[1] < j)
759 max[1] = j;
760
761 centroid[0] += (weight[0][0] + weight[0][1] + weight[0][2]) * i;
762 centroid[1] += (weight[0][0] + weight[0][1] + weight[0][2]) * j;
763 centroid_divisor += (weight[0][0] + weight[0][1] + weight[0][2]);
764
765 /*
766 * Determine alignment type.
767 */
768
769 for (int m = 0; m < (u.defined() ? 2 : 1); m++)
770 if (channel_alignment_type == 0) {
771 /*
772 * Align based on all channels.
773 */
774
775
776 for (int k = 0; k < 3; k++) {
777 ale_real achan = pa[k];
778 ale_real bchan = p[m][k];
779
780 this_result[m] += weight[m][k] * pow(fabs(achan - bchan), metric_exponent);
781 this_divisor[m] += weight[m][k] * pow(achan > bchan ? achan : bchan, metric_exponent);
782 }
783 } else if (channel_alignment_type == 1) {
784 /*
785 * Align based on the green channel.
786 */
787
788 ale_real achan = pa[1];
789 ale_real bchan = p[m][1];
790
791 this_result[m] = weight[m][1] * pow(fabs(achan - bchan), metric_exponent);
792 this_divisor[m] = weight[m][1] * pow(achan > bchan ? achan : bchan, metric_exponent);
793 } else if (channel_alignment_type == 2) {
794 /*
795 * Align based on the sum of all channels.
796 */
797
798 ale_real asum = 0;
799 ale_real bsum = 0;
800 ale_real wsum = 0;
801
802 for (int k = 0; k < 3; k++) {
803 asum += pa[k];
804 bsum += p[m][k];
805 wsum += weight[m][k] / 3;
806 }
807
808 this_result[m] = wsum * pow(fabs(asum - bsum), metric_exponent);
809 this_divisor[m] = wsum * pow(asum > bsum ? asum : bsum, metric_exponent);
810 }
811
812 if (u.defined()) {
42772195
DH
David Hilvert2007-10-21 15:36:00 +0000813// ale_real de = fabs(this_result[0] / this_divisor[0]
814// - this_result[1] / this_divisor[1]);
815 ale_real de = fabs(this_result[0] - this_result[1]);
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000816
42772195
DH
David Hilvert2007-10-21 15:36:00 +0000817 de_centroid[0] += de * (ale_real) i;
818 de_centroid[1] += de * (ale_real) j;
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000819
42772195 David Hilvert2007-10-21 15:36:00 +0000820 de_centroid_v += de * (ale_real) t.lengthto(u);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000821
822 de_sum += de;
823 }
824
825 result += (this_result[0]);
826 divisor += (this_divisor[0]);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000827 }
828
829 void rescale(ale_pos scale) {
830 offset.rescale(scale);
831
832 de_centroid[0] *= scale;
833 de_centroid[1] *= scale;
834 de_centroid_v *= scale;
835 }
836
837 point get_centroid() {
838 point result = point(centroid[0] / centroid_divisor, centroid[1] / centroid_divisor);
839
840 assert (finite(centroid[0])
841 && finite(centroid[1])
842 && (result.defined() || centroid_divisor == 0));
843
844 return result;
845 }
846
847 point get_error_centroid() {
848 point result = point(de_centroid[0] / de_sum, de_centroid[1] / de_sum);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000849 return result;
850 }
851
852
853 ale_pos get_error_perturb() {
854 ale_pos result = de_centroid_v / de_sum;
855
856 return result;
857 }
858
859 };
860
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +0000861 /*
862 * When non-empty, runs.front() is best, runs.back() is
863 * testing.
864 */
865
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000866 std::vector<run> runs;
867
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +0000868 /*
869 * old_runs stores the latest available perturbation set for
870 * each multi-alignment element.
871 */
872
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000873 typedef int run_index;
30ea890d David Hilvert2007-05-14 20:54:00 +0000874 std::map<run_index, run> old_runs;
5d53e401 David Hilvert2007-05-02 03:12:00 +0000875
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000876 static void *diff_subdomain(void *args);
877
878 struct subdomain_args {
879 struct scale_cluster c;
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000880 std::vector<run> runs;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000881 int ax_count;
882 int f;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000883 int i_min, i_max, j_min, j_max;
884 int subdomain;
885 };
886
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000887 struct scale_cluster si;
888 int ax_count;
889 int frame;
890
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +0000891 std::vector<ale_pos> perturb_multipliers;
892
30ea890d David Hilvert2007-05-14 20:54:00 +0000893public:
1b980378 David Hilvert2008-07-18 18:30:40 +0000894 void diff(struct scale_cluster c, const diff_trans &t,
afa6d8f6 David Hilvert2007-05-13 03:19:00 +0000895 int _ax_count, int f) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000896
897 if (runs.size() == 2)
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +0000898 runs.pop_back();
899
1b980378 David Hilvert2008-07-18 18:30:40 +0000900 runs.push_back(run(t));
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000901
902 si = c;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000903 ax_count = _ax_count;
904 frame = f;
905
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000906 ui::get()->d2_align_sample_start();
907
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +0000908 if (interpolant != NULL) {
909
910 /*
911 * XXX: This has not been tested, and may be completely
912 * wrong.
913 */
914
915 transformation tt = transformation::eu_identity();
916 tt.set_current_element(t);
917 interpolant->set_parameters(tt, c.input, c.accum->offset());
918 }
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000919
920 int N;
921#ifdef USE_PTHREAD
922 N = thread::count();
923
924 pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t) * N);
925 pthread_attr_t *thread_attr = (pthread_attr_t *) malloc(sizeof(pthread_attr_t) * N);
926
927#else
928 N = 1;
929#endif
930
931 subdomain_args *args = new subdomain_args[N];
932
d790f7da David Hilvert2008-05-02 18:59:43 -0500933 transformation::elem_bounds_int_t b = elem_bounds.scale_to_bounds(c.accum->height(), c.accum->width());
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000934
a7ee2759
DH
David Hilvert2008-03-17 17:05:06 -0500935// fprintf(stdout, "[%d %d] [%d %d]\n",
936// global_i_min, global_i_max, global_j_min, global_j_max);
e55e5de1 David Hilvert2008-02-14 01:08:00 +0000937
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000938 for (int ti = 0; ti < N; ti++) {
939 args[ti].c = c;
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000940 args[ti].runs = runs;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000941 args[ti].ax_count = ax_count;
942 args[ti].f = f;
d790f7da
DH
David Hilvert2008-05-02 18:59:43 -0500943 args[ti].i_min = b.imin + ((b.imax - b.imin) * ti) / N;
944 args[ti].i_max = b.imin + ((b.imax - b.imin) * (ti + 1)) / N;
945 args[ti].j_min = b.jmin;
946 args[ti].j_max = b.jmax;
eb01b1b8 David Hilvert2007-04-24 05:36:00 +0000947 args[ti].subdomain = ti;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000948#ifdef USE_PTHREAD
949 pthread_attr_init(&thread_attr[ti]);
950 pthread_attr_setdetachstate(&thread_attr[ti], PTHREAD_CREATE_JOINABLE);
951 pthread_create(&threads[ti], &thread_attr[ti], diff_subdomain, &args[ti]);
952#else
953 diff_subdomain(&args[ti]);
954#endif
955 }
956
957 for (int ti = 0; ti < N; ti++) {
958#ifdef USE_PTHREAD
959 pthread_join(threads[ti], NULL);
960#endif
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000961 runs.back().add(args[ti].runs.back());
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000962 }
963
44a1d1de
DH
David Hilvert2009-03-30 19:02:57 +0000964#ifdef USE_PTHREAD
965 free(threads);
966 free(thread_attr);
967#endif
968
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +0000969 delete[] args;
970
971 ui::get()->d2_align_sample_stop();
972
973 }
974
975 private:
976 void rediff() {
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000977 std::vector<diff_trans> t_array;
b971d971 David Hilvert2006-12-26 05:25:00 +0000978
afa6d8f6 David Hilvert2007-05-13 03:19:00 +0000979 for (unsigned int r = 0; r < runs.size(); r++) {
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000980 t_array.push_back(runs[r].offset);
afa6d8f6 David Hilvert2007-05-13 03:19:00 +0000981 }
b971d971 David Hilvert2006-12-26 05:25:00 +0000982
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000983 runs.clear();
eb01b1b8 David Hilvert2007-04-24 05:36:00 +0000984
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000985 for (unsigned int r = 0; r < t_array.size(); r++)
1b980378 David Hilvert2008-07-18 18:30:40 +0000986 diff(si, t_array[r], ax_count, frame);
86c0d2ba dhilvert2006-10-25 14:42:00 +0000987 }
988
400c7826 David Hilvert2007-04-20 07:06:00 +0000989
1732c1c4 David Hilvert2007-04-30 02:42:00 +0000990 public:
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000991 int better() {
992 assert(runs.size() >= 2);
993 assert(runs[0].offset.scale() == runs[1].offset.scale());
86c0d2ba dhilvert2006-10-25 14:42:00 +0000994
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000995 return (runs[1].get_error() < runs[0].get_error()
996 || (!finite(runs[0].get_error()) && finite(runs[1].get_error())));
08151f52 dhilvert2006-10-25 17:36:00 +0000997 }
998
e0577945
DH
David Hilvert2008-07-19 22:11:55 +0000999 int better_defined() {
1000 assert(runs.size() >= 2);
1001 assert(runs[0].offset.scale() == runs[1].offset.scale());
1002
1003 return (runs[1].get_error() < runs[0].get_error());
1004 }
1005
f8864302 David Hilvert2008-04-11 18:15:57 +00001006 diff_stat_generic(transformation::elem_bounds_t e)
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001007 : runs(), old_runs(), perturb_multipliers() {
1008 elem_bounds = e;
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001009 }
1010
1011 run_index get_run_index(unsigned int perturb_index) {
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001012 return perturb_index;
30ea890d David Hilvert2007-05-14 20:54:00 +00001013 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001014
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001015 run &get_run(unsigned int perturb_index) {
1016 run_index index = get_run_index(perturb_index);
dc426169 David Hilvert2007-04-25 06:50:00 +00001017
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001018 assert(old_runs.count(index));
1019 return old_runs[index];
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001020 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001021
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001022 void rescale(ale_pos scale, scale_cluster _si) {
1023 assert(runs.size() == 1);
86c0d2ba dhilvert2006-10-25 14:42:00 +00001024
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001025 si = _si;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001026
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001027 runs[0].rescale(scale);
1028
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001029 rediff();
1030 }
1031
f8864302 David Hilvert2008-04-11 18:15:57 +00001032 ~diff_stat_generic() {
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001033 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001034
f8864302 David Hilvert2008-04-11 18:15:57 +00001035 diff_stat_generic &operator=(const diff_stat_generic &dst) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001036 /*
1037 * Copy run information.
1038 */
1039 runs = dst.runs;
82db7fe6 David Hilvert2007-05-05 18:29:00 +00001040 old_runs = dst.old_runs;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001041
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001042 /*
1043 * Copy diff variables
1044 */
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001045 si = dst.si;
1046 ax_count = dst.ax_count;
1047 frame = dst.frame;
50a9f51d David Hilvert2007-05-03 05:16:00 +00001048 perturb_multipliers = dst.perturb_multipliers;
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001049 elem_bounds = dst.elem_bounds;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001050
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001051 return *this;
1052 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001053
f8864302 David Hilvert2008-04-11 18:15:57 +00001054 diff_stat_generic(const diff_stat_generic &dst) : runs(), old_runs(),
ca7b6c30 David Hilvert2007-05-06 02:42:00 +00001055 perturb_multipliers() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001056 operator=(dst);
1057 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001058
1ed23c0d
DH
David Hilvert2008-03-09 11:23:00 +00001059 void set_elem_bounds(transformation::elem_bounds_t e) {
1060 elem_bounds = e;
1061 }
1062
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001063 ale_accum get_result() {
1064 assert(runs.size() == 1);
1065 return runs[0].result;
1066 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001067
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001068 ale_accum get_divisor() {
1069 assert(runs.size() == 1);
1070 return runs[0].divisor;
1071 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001072
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001073 diff_trans get_offset() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001074 assert(runs.size() == 1);
1075 return runs[0].offset;
1076 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001077
f8864302 David Hilvert2008-04-11 18:15:57 +00001078 int operator!=(diff_stat_generic &param) {
65886ff7 David Hilvert2007-09-04 02:10:00 +00001079 return (get_error() != param.get_error());
86c0d2ba dhilvert2006-10-25 14:42:00 +00001080 }
08151f52 dhilvert2006-10-25 17:36:00 +00001081
f8864302 David Hilvert2008-04-11 18:15:57 +00001082 int operator==(diff_stat_generic &param) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001083 return !(operator!=(param));
1084 }
08151f52 dhilvert2006-10-25 17:36:00 +00001085
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001086 ale_pos get_error_perturb() {
1087 assert(runs.size() == 1);
1088 return runs[0].get_error_perturb();
08151f52 dhilvert2006-10-25 17:36:00 +00001089 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001090
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001091 ale_accum get_error() const {
1092 assert(runs.size() == 1);
1093 return runs[0].get_error();
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001094 }
dda1bf79 dhilvert2006-10-22 18:40:00 +00001095
30ea890d David Hilvert2007-05-14 20:54:00 +00001096 public:
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001097 /*
1098 * Get the set of transformations produced by a given perturbation
1099 */
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001100 void get_perturb_set(std::vector<diff_trans> *set,
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001101 ale_pos adj_p, ale_pos adj_o, ale_pos adj_b,
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001102 ale_pos *current_bd, ale_pos *modified_bd,
1103 std::vector<ale_pos> multipliers = std::vector<ale_pos>()) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001104
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001105 assert(runs.size() == 1);
dda1bf79 dhilvert2006-10-22 18:40:00 +00001106
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001107 diff_trans test_t(diff_trans::eu_identity());
dda1bf79 dhilvert2006-10-22 18:40:00 +00001108
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001109 /*
1110 * Translational or euclidean transformation
1111 */
2aa417e6 dhilvert2005-01-07 06:44:00 +00001112
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001113 for (unsigned int i = 0; i < 2; i++)
1114 for (unsigned int s = 0; s < 2; s++) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001115
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001116 if (!multipliers.size())
1117 multipliers.push_back(1);
dc426169 David Hilvert2007-04-25 06:50:00 +00001118
b2e7131e David Hilvert2007-05-02 08:35:00 +00001119 assert(finite(multipliers[0]));
5d53e401 David Hilvert2007-05-02 03:12:00 +00001120
b2e7131e David Hilvert2007-05-02 08:35:00 +00001121 test_t = get_offset();
dc426169 David Hilvert2007-04-25 06:50:00 +00001122
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001123 // test_t.eu_modify(i, (s ? -adj_p : adj_p) * multipliers[0]);
1124 test_t.translate((i ? point(1, 0) : point(0, 1))
1125 * (s ? -adj_p : adj_p)
1126 * multipliers[0]);
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001127
1128 test_t.snap(adj_p / 2);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001129
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001130 set->push_back(test_t);
1131 multipliers.erase(multipliers.begin());
46f9776a dhilvert2005-01-07 06:44:00 +00001132
b2e7131e David Hilvert2007-05-02 08:35:00 +00001133 }
4707675e dhilvert2006-10-19 10:24:00 +00001134
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001135 if (alignment_class > 0)
1136 for (unsigned int s = 0; s < 2; s++) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001137
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001138 if (!multipliers.size())
1139 multipliers.push_back(1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001140
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001141 assert(multipliers.size());
1142 assert(finite(multipliers[0]));
5d53e401 David Hilvert2007-05-02 03:12:00 +00001143
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001144 if (!(adj_o * multipliers[0] < rot_max))
1145 return;
4707675e dhilvert2006-10-19 10:24:00 +00001146
b2e7131e David Hilvert2007-05-02 08:35:00 +00001147 ale_pos adj_s = (s ? 1 : -1) * adj_o * multipliers[0];
5d53e401 David Hilvert2007-05-02 03:12:00 +00001148
b2e7131e David Hilvert2007-05-02 08:35:00 +00001149 test_t = get_offset();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001150
30ea890d David Hilvert2007-05-14 20:54:00 +00001151 run_index ori = get_run_index(set->size());
b2e7131e David Hilvert2007-05-02 08:35:00 +00001152 point centroid = point::undefined();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001153
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001154 if (!old_runs.count(ori))
1155 ori = get_run_index(0);
5d53e401 David Hilvert2007-05-02 03:12:00 +00001156
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001157 if (!centroid.finite() && old_runs.count(ori)) {
1158 centroid = old_runs[ori].get_error_centroid();
5d53e401 David Hilvert2007-05-02 03:12:00 +00001159
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001160 if (!centroid.finite())
1161 centroid = old_runs[ori].get_centroid();
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001162
1163 centroid *= test_t.scale()
1164 / old_runs[ori].offset.scale();
b2e7131e David Hilvert2007-05-02 08:35:00 +00001165 }
5d53e401 David Hilvert2007-05-02 03:12:00 +00001166
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001167 if (!centroid.finite() && !test_t.is_projective()) {
1168 test_t.eu_modify(2, adj_s);
1169 } else if (!centroid.finite()) {
1170 centroid = point(si.input->height() / 2,
1171 si.input->width() / 2);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001172
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001173 test_t.rotate(centroid + si.accum->offset(),
1174 adj_s);
1175 } else {
1176 test_t.rotate(centroid + si.accum->offset(),
1177 adj_s);
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001178 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001179
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001180 test_t.snap(adj_p / 2);
1181
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001182 set->push_back(test_t);
1183 multipliers.erase(multipliers.begin());
1184 }
1185
1186 if (alignment_class == 2) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001187
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001188 /*
1189 * Projective transformation
1190 */
30afe4b6 dhilvert2005-01-07 06:42:00 +00001191
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001192 for (unsigned int i = 0; i < 4; i++)
1193 for (unsigned int j = 0; j < 2; j++)
1194 for (unsigned int s = 0; s < 2; s++) {
1195
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001196 if (!multipliers.size())
1197 multipliers.push_back(1);
1198
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001199 assert(multipliers.size());
1200 assert(finite(multipliers[0]));
46f9776a dhilvert2005-01-07 06:44:00 +00001201
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001202 ale_pos adj_s = (s ? -1 : 1) * adj_p * multipliers [0];
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001203
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001204 test_t = get_offset();
46f9776a dhilvert2005-01-07 06:44:00 +00001205
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001206 if (perturb_type == 0)
73f0dc5c David Hilvert2008-08-18 17:37:54 -05001207 test_t.gpt_modify_bounded(j, i, adj_s, elem_bounds.scale_to_bounds(si.accum->height(), si.accum->width()));
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001208 else if (perturb_type == 1)
1209 test_t.gr_modify(j, i, adj_s);
1210 else
1211 assert(0);
dc426169 David Hilvert2007-04-25 06:50:00 +00001212
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001213 test_t.snap(adj_p / 2);
1214
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001215 set->push_back(test_t);
1216 multipliers.erase(multipliers.begin());
1217 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001218
b2e7131e David Hilvert2007-05-02 08:35:00 +00001219 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001220
49a3a0b4 David Hilvert2007-04-01 07:13:00 +00001221 /*
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001222 * Barrel distortion
49a3a0b4
DH
David Hilvert2007-04-01 07:13:00 +00001223 */
1224
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001225 if (bda_mult != 0 && adj_b != 0) {
7a696eb1 David Hilvert2007-04-01 06:41:00 +00001226
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001227 for (unsigned int d = 0; d < get_offset().bd_count(); d++)
1228 for (unsigned int s = 0; s < 2; s++) {
1229
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001230 if (!multipliers.size())
1231 multipliers.push_back(1);
1232
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001233 assert (multipliers.size());
1234 assert (finite(multipliers[0]));
1235
1236 ale_pos adj_s = (s ? -1 : 1) * adj_b * multipliers[0];
1237
1238 if (bda_rate > 0 && fabs(modified_bd[d] + adj_s - current_bd[d]) > bda_rate)
1239 continue;
1240
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001241 diff_trans test_t = get_offset();
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001242
1243 test_t.bd_modify(d, adj_s);
1244
1245 set->push_back(test_t);
1246 }
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001247 }
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001248 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001249
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001250 void confirm() {
1251 assert(runs.size() == 2);
1252 runs[0] = runs[1];
1253 runs.pop_back();
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001254 }
1255
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001256 void discard() {
1257 assert(runs.size() == 2);
1258 runs.pop_back();
1259 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001260
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001261 void perturb_test(ale_pos perturb, ale_pos adj_p, ale_pos adj_o, ale_pos adj_b,
2077ce22 David Hilvert2007-05-13 09:23:00 +00001262 ale_pos *current_bd, ale_pos *modified_bd, int stable) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001263
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001264 assert(runs.size() == 1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001265
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001266 std::vector<diff_trans> t_set;
4707675e dhilvert2006-10-19 10:24:00 +00001267
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001268 if (perturb_multipliers.size() == 0) {
1269 get_perturb_set(&t_set, adj_p, adj_o, adj_b,
1270 current_bd, modified_bd);
1271
1272 for (unsigned int i = 0; i < t_set.size(); i++) {
f8864302 David Hilvert2008-04-11 18:15:57 +00001273 diff_stat_generic test = *this;
50a9f51d David Hilvert2007-05-03 05:16:00 +00001274
1b980378 David Hilvert2008-07-18 18:30:40 +00001275 test.diff(si, t_set[i], ax_count, frame);
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001276
1277 test.confirm();
1278
42772195 David Hilvert2007-10-21 15:36:00 +00001279 if (finite(test.get_error_perturb()))
82db7fe6
DH
David Hilvert2007-05-05 18:29:00 +00001280 perturb_multipliers.push_back(adj_p / test.get_error_perturb());
1281 else
1282 perturb_multipliers.push_back(1);
1283
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001284 }
1285
1286 t_set.clear();
1287 }
1288
5d53e401 David Hilvert2007-05-02 03:12:00 +00001289 get_perturb_set(&t_set, adj_p, adj_o, adj_b, current_bd, modified_bd,
50a9f51d David Hilvert2007-05-03 05:16:00 +00001290 perturb_multipliers);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001291
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001292 int found_unreliable = 1;
1293 std::vector<int> tested(t_set.size(), 0);
dc426169 David Hilvert2007-04-25 06:50:00 +00001294
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001295 for (unsigned int i = 0; i < t_set.size(); i++) {
1296 run_index ori = get_run_index(i);
1297
1298 /*
1299 * Check for stability
1300 */
1301 if (stable
1302 && old_runs.count(ori)
1303 && old_runs[ori].offset == t_set[i])
1304 tested[i] = 1;
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001305 }
1306
1307 std::vector<ale_pos> perturb_multipliers_original = perturb_multipliers;
1308
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001309 while (found_unreliable) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001310
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001311 found_unreliable = 0;
08151f52 dhilvert2006-10-25 17:36:00 +00001312
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001313 for (unsigned int i = 0; i < t_set.size(); i++) {
4d806213 dhilvert2006-10-23 17:58:00 +00001314
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001315 if (tested[i])
1316 continue;
b410ef51 dhilvert2006-10-23 15:30:00 +00001317
1b980378 David Hilvert2008-07-18 18:30:40 +00001318 diff(si, t_set[i], ax_count, frame);
7e87bd8e dhilvert2006-10-23 06:39:00 +00001319
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001320 if (!(i < perturb_multipliers.size())
1321 || !finite(perturb_multipliers[i])) {
5d53e401 David Hilvert2007-05-02 03:12:00 +00001322
50a9f51d David Hilvert2007-05-03 05:16:00 +00001323 perturb_multipliers.resize(i + 1);
5d53e401 David Hilvert2007-05-02 03:12:00 +00001324
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001325 if (finite(perturb_multipliers[i])
1326 && finite(adj_p)
1327 && finite(adj_p / runs[1].get_error_perturb())) {
1328 perturb_multipliers[i] =
1329 adj_p / runs[1].get_error_perturb();
5d53e401 David Hilvert2007-05-02 03:12:00 +00001330
8c886617 David Hilvert2007-05-02 08:39:00 +00001331 found_unreliable = 1;
42772195 David Hilvert2007-10-21 15:36:00 +00001332 } else
858b0722 David Hilvert2007-10-03 20:44:00 +00001333 perturb_multipliers[i] = 1;
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001334
1335 continue;
1336 }
1337
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001338 run_index ori = get_run_index(i);
1339
1340 if (old_runs.count(ori) == 0)
1341 old_runs.insert(std::pair<run_index, run>(ori, runs[1]));
1342 else
1343 old_runs[ori] = runs[1];
5d53e401 David Hilvert2007-05-02 03:12:00 +00001344
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001345 if (finite(perturb_multipliers_original[i])
1346 && finite(runs[1].get_error_perturb())
1347 && finite(adj_p)
1348 && finite(perturb_multipliers_original[i] * adj_p / runs[1].get_error_perturb()))
1349 perturb_multipliers[i] = perturb_multipliers_original[i]
1350 * adj_p / runs[1].get_error_perturb();
1351 else
50a9f51d David Hilvert2007-05-03 05:16:00 +00001352 perturb_multipliers[i] = 1;
5d53e401 David Hilvert2007-05-02 03:12:00 +00001353
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001354 tested[i] = 1;
dda1bf79 dhilvert2006-10-22 18:40:00 +00001355
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001356 if (better()
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001357 && runs[1].get_error() < runs[0].get_error()
1358 && perturb_multipliers[i]
1359 / perturb_multipliers_original[i] < 2) {
9e8e62c9
DH
David Hilvert2007-05-13 10:57:00 +00001360 runs[0] = runs[1];
1361 runs.pop_back();
1362 return;
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001363 }
82db7fe6 David Hilvert2007-05-05 18:29:00 +00001364
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001365 }
dda1bf79 dhilvert2006-10-22 18:40:00 +00001366
2077ce22
DH
David Hilvert2007-05-13 09:23:00 +00001367 if (runs.size() > 1)
1368 runs.pop_back();
3aa65890 dhilvert2006-10-25 15:26:00 +00001369
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001370 if (!found_unreliable)
1371 return;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001372 }
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001373 }
08151f52 dhilvert2006-10-25 17:36:00 +00001374
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001375 };
4707675e dhilvert2006-10-19 10:24:00 +00001376
f8864302
DH
David Hilvert2008-04-11 18:15:57 +00001377 typedef diff_stat_generic<trans_single> diff_stat_t;
1378 typedef diff_stat_generic<trans_multi> diff_stat_multi;
1379
4707675e dhilvert2006-10-19 10:24:00 +00001380
30afe4b6 dhilvert2005-01-07 06:42:00 +00001381 /*
1382 * Adjust exposure for an aligned frame B against reference A.
07271611 dhilvert2005-01-07 06:48:00 +00001383 *
1384 * Expects full-LOD images.
1385 *
423af06c
DH
David Hilvert2007-09-10 17:43:00 +00001386 * Note: This method does not use any weighting, by certainty or
1387 * otherwise, in the first exposure registration pass, as any bias of
1388 * weighting according to color may also bias the exposure registration
1389 * result; it does use weighting, including weighting by certainty
1390 * (even if certainty weighting is not specified), in the second pass,
1391 * under the assumption that weighting by certainty improves handling
1392 * of out-of-range highlights, and that bias of exposure measurements
1393 * according to color may generally be less harmful after spatial
1394 * registration has been performed.
30afe4b6 dhilvert2005-01-07 06:42:00 +00001395 */
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001396 class exposure_ratio_iterate : public thread::decompose_domain {
1397 pixel_accum *asums;
1398 pixel_accum *bsums;
1399 pixel_accum *asum;
1400 pixel_accum *bsum;
1401 struct scale_cluster c;
214d014c David Hilvert2008-05-04 22:08:03 -05001402 const transformation &t;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001403 int ax_count;
1404 int pass_number;
1405 protected:
1406 void prepare_subdomains(unsigned int N) {
1407 asums = new pixel_accum[N];
1408 bsums = new pixel_accum[N];
1409 }
1410 void subdomain_algorithm(unsigned int thread,
1411 int i_min, int i_max, int j_min, int j_max) {
1412
1413 point offset = c.accum->offset();
1414
1415 for (mc_iterate m(i_min, i_max, j_min, j_max, thread); !m.done(); m++) {
1416
1417 unsigned int i = (unsigned int) m.get_i();
1418 unsigned int j = (unsigned int) m.get_j();
1419
1420 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
1421 continue;
1422
1423 /*
1424 * Transform
1425 */
1426
1427 struct point q;
1428
1429 q = (c.input_scale < 1.0 && interpolant == NULL)
1430 ? t.scaled_inverse_transform(
1431 point(i + offset[0], j + offset[1]))
1432 : t.unscaled_inverse_transform(
1433 point(i + offset[0], j + offset[1]));
1434
1435 /*
1436 * Check that the transformed coordinates are within
1437 * the boundaries of array c.input, that they are not
1438 * subject to exclusion, and that the weight value in
1439 * the accumulated array is nonzero.
1440 */
1441
1442 if (input_excluded(q[0], q[1], c.ax_parameters, ax_count))
1443 continue;
1444
1445 if (q[0] >= 0
1446 && q[0] <= c.input->height() - 1
1447 && q[1] >= 0
1448 && q[1] <= c.input->width() - 1
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00001449 && ((pixel) c.certainty->get_pixel(i, j)).minabs_norm() != 0) {
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001450 pixel a = c.accum->get_pixel(i, j);
1451 pixel b;
1452
1453 b = c.input->get_bl(q);
1454
1455 pixel weight = ((c.aweight && pass_number)
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00001456 ? (pixel) c.aweight->get_pixel(i, j)
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001457 : pixel(1, 1, 1))
1458 * (pass_number
5c603c78
DH
David Hilvert2007-10-29 04:51:00 +00001459 ? psqrt(c.certainty->get_pixel(i, j)
1460 * c.input_certainty->get_bl(q, 1))
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001461 : pixel(1, 1, 1));
1462
1463 asums[thread] += a * weight;
1464 bsums[thread] += b * weight;
1465 }
1466 }
1467 }
1468
1469 void finish_subdomains(unsigned int N) {
1470 for (unsigned int n = 0; n < N; n++) {
1471 *asum += asums[n];
1472 *bsum += bsums[n];
1473 }
34c6efce
DH
David Hilvert2007-10-23 01:35:00 +00001474 delete[] asums;
1475 delete[] bsums;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001476 }
1477 public:
1478 exposure_ratio_iterate(pixel_accum *_asum,
1479 pixel_accum *_bsum,
1480 struct scale_cluster _c,
214d014c David Hilvert2008-05-04 22:08:03 -05001481 const transformation &_t,
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001482 int _ax_count,
1483 int _pass_number) : decompose_domain(0, _c.accum->height(),
dd761b64
DH
David Hilvert2008-01-26 17:41:00 +00001484 0, _c.accum->width()),
1485 t(_t) {
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001486
1487 asum = _asum;
1488 bsum = _bsum;
1489 c = _c;
214d014c
DH
David Hilvert2008-05-04 22:08:03 -05001490 ax_count = _ax_count;
1491 pass_number = _pass_number;
1492 }
1493
1494 exposure_ratio_iterate(pixel_accum *_asum,
1495 pixel_accum *_bsum,
1496 struct scale_cluster _c,
1497 const transformation &_t,
1498 int _ax_count,
1499 int _pass_number,
1500 transformation::elem_bounds_int_t b) : decompose_domain(b.imin, b.imax,
1501 b.jmin, b.jmax),
1502 t(_t) {
1503
1504 asum = _asum;
1505 bsum = _bsum;
1506 c = _c;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001507 ax_count = _ax_count;
1508 pass_number = _pass_number;
1509 }
1510 };
1511
2aa417e6 dhilvert2005-01-07 06:44:00 +00001512 static void set_exposure_ratio(unsigned int m, struct scale_cluster c,
993fde09 David Hilvert2008-05-05 05:28:56 +00001513 const transformation &t, int ax_count, int pass_number) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001514
3dc20778 dhilvert2005-01-10 23:06:00 +00001515 if (_exp_register == 2) {
1516 /*
1517 * Use metadata only.
1518 */
1519 ale_real gain_multiplier = image_rw::exp(m).get_gain_multiplier();
1520 pixel multiplier = pixel(gain_multiplier, gain_multiplier, gain_multiplier);
1521
1522 image_rw::exp(m).set_multiplier(multiplier);
a9d66b26 dhilvert2005-01-10 23:15:00 +00001523 ui::get()->exp_multiplier(multiplier[0],
1524 multiplier[1],
1525 multiplier[2]);
3d7fd555 dhilvert2005-01-10 23:10:00 +00001526
1527 return;
3dc20778 dhilvert2005-01-10 23:06:00 +00001528 }
1529
70fb02f9 David Hilvert2007-09-21 03:18:00 +00001530 pixel_accum asum(0, 0, 0), bsum(0, 0, 0);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001531
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001532 exposure_ratio_iterate eri(&asum, &bsum, c, t, ax_count, pass_number);
1533 eri.run();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001534
1535 // std::cerr << (asum / bsum) << " ";
07271611 dhilvert2005-01-07 06:48:00 +00001536
1537 pixel_accum new_multiplier;
1538
1539 new_multiplier = asum / bsum * image_rw::exp(m).get_multiplier();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001540
07271611 dhilvert2005-01-07 06:48:00 +00001541 if (finite(new_multiplier[0])
1542 && finite(new_multiplier[1])
1543 && finite(new_multiplier[2])) {
1544 image_rw::exp(m).set_multiplier(new_multiplier);
1545 ui::get()->exp_multiplier(new_multiplier[0],
1546 new_multiplier[1],
1547 new_multiplier[2]);
1548 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001549 }
1550
df55d1a2 dhilvert2006-08-30 07:40:00 +00001551 /*
1552 * Copy all ax parameters.
1553 */
1554 static exclusion *copy_ax_parameters(int local_ax_count, exclusion *source) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001555
df55d1a2 dhilvert2006-08-30 07:40:00 +00001556 exclusion *dest = (exclusion *) malloc(local_ax_count * sizeof(exclusion));
2aa417e6 dhilvert2005-01-07 06:44:00 +00001557
df55d1a2 dhilvert2006-08-30 07:40:00 +00001558 assert (dest);
2aa417e6 dhilvert2005-01-07 06:44:00 +00001559
df55d1a2 dhilvert2006-08-30 07:40:00 +00001560 if (!dest)
07271611 dhilvert2005-01-07 06:48:00 +00001561 ui::get()->memory_error("exclusion regions");
2aa417e6 dhilvert2005-01-07 06:44:00 +00001562
df55d1a2 dhilvert2006-08-30 07:40:00 +00001563 for (int idx = 0; idx < local_ax_count; idx++)
1564 dest[idx] = source[idx];
2aa417e6 dhilvert2005-01-07 06:44:00 +00001565
df55d1a2 dhilvert2006-08-30 07:40:00 +00001566 return dest;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001567 }
1568
df55d1a2 dhilvert2006-08-30 07:40:00 +00001569 /*
1570 * Copy ax parameters according to frame.
1571 */
1572 static exclusion *filter_ax_parameters(int frame, int *local_ax_count) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001573
df55d1a2 dhilvert2006-08-30 07:40:00 +00001574 exclusion *dest = (exclusion *) malloc(ax_count * sizeof(exclusion));
46f9776a dhilvert2005-01-07 06:44:00 +00001575
df55d1a2 dhilvert2006-08-30 07:40:00 +00001576 assert (dest);
46f9776a dhilvert2005-01-07 06:44:00 +00001577
df55d1a2 dhilvert2006-08-30 07:40:00 +00001578 if (!dest)
07271611 dhilvert2005-01-07 06:48:00 +00001579 ui::get()->memory_error("exclusion regions");
46f9776a dhilvert2005-01-07 06:44:00 +00001580
1581 *local_ax_count = 0;
1582
1583 for (int idx = 0; idx < ax_count; idx++) {
df55d1a2 dhilvert2006-08-30 07:40:00 +00001584 if (ax_parameters[idx].x[4] > frame
1585 || ax_parameters[idx].x[5] < frame)
46f9776a dhilvert2005-01-07 06:44:00 +00001586 continue;
1587
df55d1a2 dhilvert2006-08-30 07:40:00 +00001588 dest[*local_ax_count] = ax_parameters[idx];
46f9776a dhilvert2005-01-07 06:44:00 +00001589
1590 (*local_ax_count)++;
1591 }
1592
df55d1a2 dhilvert2006-08-30 07:40:00 +00001593 return dest;
1594 }
46f9776a dhilvert2005-01-07 06:44:00 +00001595
df55d1a2 dhilvert2006-08-30 07:40:00 +00001596 static void scale_ax_parameters(int local_ax_count, exclusion *ax_parameters,
1597 ale_pos ref_scale, ale_pos input_scale) {
1598 for (int i = 0; i < local_ax_count; i++) {
1599 ale_pos scale = (ax_parameters[i].type == exclusion::RENDER)
1600 ? ref_scale
1601 : input_scale;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001602
df55d1a2 dhilvert2006-08-30 07:40:00 +00001603 for (int n = 0; n < 6; n++) {
e1eaf84c David Hilvert2007-07-24 02:50:00 +00001604 ax_parameters[i].x[n] = ax_parameters[i].x[n] * scale;
df55d1a2 dhilvert2006-08-30 07:40:00 +00001605 }
1606 }
46f9776a dhilvert2005-01-07 06:44:00 +00001607 }
1608
2aa417e6 dhilvert2005-01-07 06:44:00 +00001609 /*
1610 * Prepare the next level of detail for ordinary images.
1611 */
1612 static const image *prepare_lod(const image *current) {
1613 if (current == NULL)
1614 return NULL;
46f9776a dhilvert2005-01-07 06:44:00 +00001615
2aa417e6 dhilvert2005-01-07 06:44:00 +00001616 return current->scale_by_half("prepare_lod");
1617 }
46f9776a dhilvert2005-01-07 06:44:00 +00001618
2aa417e6 dhilvert2005-01-07 06:44:00 +00001619 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00001620 * Prepare the next level of detail for definition maps.
1621 */
1622 static const image *prepare_lod_def(const image *current) {
7a19e165
DH
David Hilvert2007-09-10 21:16:00 +00001623 if (current == NULL)
1624 return NULL;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001625
1626 return current->defined_scale_by_half("prepare_lod_def");
1627 }
1628
1629 /*
8f2ed1fd David Hilvert2007-09-07 18:36:00 +00001630 * Initialize scale cluster data structures.
2aa417e6 dhilvert2005-01-07 06:44:00 +00001631 */
8f2ed1fd
DH
David Hilvert2007-09-07 18:36:00 +00001632
1633 static void init_nl_cluster(struct scale_cluster *sc) {
1634 }
1635
2aa417e6 dhilvert2005-01-07 06:44:00 +00001636 /*
1637 * Destroy the first element in the scale cluster data structure.
1638 */
a85f57f9 David Hilvert2007-10-15 17:07:00 +00001639 static void final_clusters(struct scale_cluster *scale_clusters, ale_pos scale_factor,
2aa417e6 dhilvert2005-01-07 06:44:00 +00001640 unsigned int steps) {
1641
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001642 if (scale_clusters[0].input_scale < 1.0) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001643 delete scale_clusters[0].input;
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001644 }
2aa417e6 dhilvert2005-01-07 06:44:00 +00001645
44a1d1de
DH
David Hilvert2009-03-30 19:02:57 +00001646 delete scale_clusters[0].input_certainty;
1647
2aa417e6 dhilvert2005-01-07 06:44:00 +00001648 free((void *)scale_clusters[0].ax_parameters);
1649
1650 for (unsigned int step = 1; step < steps; step++) {
1651 delete scale_clusters[step].accum;
580b5321 David Hilvert2007-09-10 17:35:00 +00001652 delete scale_clusters[step].certainty;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001653 delete scale_clusters[step].aweight;
1654
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001655 if (scale_clusters[step].input_scale < 1.0) {
07271611 dhilvert2005-01-07 06:48:00 +00001656 delete scale_clusters[step].input;
c6e3d33a
DH
David Hilvert2007-10-02 15:57:00 +00001657 delete scale_clusters[step].input_certainty;
1658 }
07271611 dhilvert2005-01-07 06:48:00 +00001659
2aa417e6 dhilvert2005-01-07 06:44:00 +00001660 free((void *)scale_clusters[step].ax_parameters);
1661 }
1662
1663 free(scale_clusters);
46f9776a dhilvert2005-01-07 06:44:00 +00001664 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001665
1666 /*
c052e200 dhilvert2005-05-08 16:16:00 +00001667 * Calculate the centroid of a control point for the set of frames
1668 * having index lower than m. Divide by any scaling of the output.
1669 */
1670 static point unscaled_centroid(unsigned int m, unsigned int p) {
1671 assert(_keep);
1672
1673 point point_sum(0, 0);
1674 ale_accum divisor = 0;
1675
1676 for(unsigned int j = 0; j < m; j++) {
1677 point pp = cp_array[p][j];
1678
1679 if (pp.defined()) {
1680 point_sum += kept_t[j].transform_unscaled(pp)
1681 / kept_t[j].scale();
1682 divisor += 1;
1683 }
1684 }
1685
1686 if (divisor == 0)
1687 return point::undefined();
1688
1689 return point_sum / divisor;
1690 }
1691
1692 /*
1693 * Calculate centroid of this frame, and of all previous frames,
1694 * from points common to both sets.
1695 */
1696 static void centroids(unsigned int m, point *current, point *previous) {
1697 /*
1698 * Calculate the translation
1699 */
1700 point other_centroid(0, 0);
1701 point this_centroid(0, 0);
1702 ale_pos divisor = 0;
1703
1704 for (unsigned int i = 0; i < cp_count; i++) {
1705 point other_c = unscaled_centroid(m, i);
1706 point this_c = cp_array[i][m];
1707
1708 if (!other_c.defined() || !this_c.defined())
1709 continue;
1710
1711 other_centroid += other_c;
1712 this_centroid += this_c;
1713 divisor += 1;
1714
1715 }
1716
1717 if (divisor == 0) {
1718 *current = point::undefined();
1719 *previous = point::undefined();
1720 return;
1721 }
1722
1723 *current = this_centroid / divisor;
1724 *previous = other_centroid / divisor;
1725 }
1726
1727 /*
b386e644 dhilvert2005-04-30 09:28:00 +00001728 * Calculate the RMS error of control points for frame m, with
1729 * transformation t, against control points for earlier frames.
1730 */
e812ee44 David Hilvert2007-10-18 18:24:00 +00001731 static ale_pos cp_rms_error(unsigned int m, transformation t) {
b386e644 dhilvert2005-04-30 09:28:00 +00001732 assert (_keep);
1733
1734 ale_accum err = 0;
1735 ale_accum divisor = 0;
1736
1737 for (unsigned int i = 0; i < cp_count; i++)
1738 for (unsigned int j = 0; j < m; j++) {
1739 const point *p = cp_array[i];
936ff6ec dhilvert2005-05-07 20:02:00 +00001740 point p_ref = kept_t[j].transform_unscaled(p[j]);
1741 point p_cur = t.transform_unscaled(p[m]);
b386e644 dhilvert2005-04-30 09:28:00 +00001742
1743 if (!p_ref.defined() || !p_cur.defined())
1744 continue;
1745
1746 err += p_ref.lengthtosq(p_cur);
1747 divisor += 1;
1748 }
1749
e812ee44 David Hilvert2007-10-18 18:24:00 +00001750 return (ale_pos) sqrt(err / divisor);
b386e644 dhilvert2005-04-30 09:28:00 +00001751 }
1752
6126fb3c David Hilvert2007-04-03 08:15:00 +00001753
59e5857b David Hilvert2007-05-08 12:15:00 +00001754 static void test_global(diff_stat_t *here, scale_cluster si, transformation t,
a7882498 David Hilvert2007-10-16 19:48:00 +00001755 int local_ax_count, int m, ale_accum local_gs_mo, ale_pos perturb) {
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00001756
1757 diff_stat_t test(*here);
1758
1b980378 David Hilvert2008-07-18 18:30:40 +00001759 test.diff(si, t.get_current_element(), local_ax_count, m);
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00001760
1761 unsigned int ovl = overlap(si, t, local_ax_count);
1762
1763 if (ovl >= local_gs_mo && test.better()) {
1764 test.confirm();
1765 *here = test;
1766 ui::get()->set_match(here->get_error());
1767 ui::get()->set_offset(here->get_offset());
1768 } else {
1769 test.discard();
1770 }
1771
1772 }
1773
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001774 /*
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001775 * Get the set of global transformations for a given density
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001776 */
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00001777 static void test_globals(diff_stat_t *here,
1778 scale_cluster si, transformation t, int local_gs, ale_pos adj_p,
a7882498 David Hilvert2007-10-16 19:48:00 +00001779 int local_ax_count, int m, ale_accum local_gs_mo, ale_pos perturb) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001780
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001781 transformation offset = t;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001782
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001783 point min, max;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001784
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001785 transformation offset_p = offset;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001786
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001787 if (!offset_p.is_projective())
1788 offset_p.eu_to_gpt();
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001789
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001790 min = max = offset_p.gpt_get(0);
1791 for (int p_index = 1; p_index < 4; p_index++) {
1792 point p = offset_p.gpt_get(p_index);
1793 if (p[0] < min[0])
1794 min[0] = p[0];
1795 if (p[1] < min[1])
1796 min[1] = p[1];
1797 if (p[0] > max[0])
1798 max[0] = p[0];
1799 if (p[1] > max[1])
1800 max[1] = p[1];
1801 }
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001802
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001803 point inner_min_t = -min;
1804 point inner_max_t = -max + point(si.accum->height(), si.accum->width());
1805 point outer_min_t = -max + point(adj_p - 1, adj_p - 1);
1806 point outer_max_t = point(si.accum->height(), si.accum->width()) - point(adj_p, adj_p);
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001807
02eb92ab David Hilvert2007-05-08 07:11:00 +00001808 if (local_gs == 1 || local_gs == 3 || local_gs == 4 || local_gs == 6) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001809
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001810 /*
1811 * Inner
1812 */
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001813
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001814 for (ale_pos i = inner_min_t[0]; i <= inner_max_t[0]; i += adj_p)
1815 for (ale_pos j = inner_min_t[1]; j <= inner_max_t[1]; j += adj_p) {
1816 transformation test_t = offset;
1817 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001818 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001819 }
1820 }
1821
02eb92ab David Hilvert2007-05-08 07:11:00 +00001822 if (local_gs == 2 || local_gs == 3 || local_gs == -1 || local_gs == 6) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001823
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001824 /*
1825 * Outer
1826 */
1827
1828 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
1829 for (ale_pos j = outer_min_t[1]; j < inner_min_t[1]; j += adj_p) {
1830 transformation test_t = offset;
1831 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001832 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001833 }
1834 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
1835 for (ale_pos j = outer_max_t[1]; j > inner_max_t[1]; j -= adj_p) {
1836 transformation test_t = offset;
1837 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001838 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001839 }
1840 for (ale_pos i = outer_min_t[0]; i < inner_min_t[0]; i += adj_p)
1841 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
1842 transformation test_t = offset;
1843 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001844 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001845 }
1846 for (ale_pos i = outer_max_t[0]; i > inner_max_t[0]; i -= adj_p)
1847 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
1848 transformation test_t = offset;
1849 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001850 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
f2d60fe2
DH
David Hilvert2007-04-13 23:28:00 +00001851 }
1852 }
cc71efb2
DH
David Hilvert2007-04-08 16:37:00 +00001853 }
1854
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00001855 static void get_translational_set(std::vector<transformation> *set,
1856 transformation t, ale_pos adj_p) {
1857
1858 ale_pos adj_s;
1859
1860 transformation offset = t;
dd761b64 David Hilvert2008-01-26 17:41:00 +00001861 transformation test_t(transformation::eu_identity());
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00001862
1863 for (int i = 0; i < 2; i++)
1864 for (adj_s = -adj_p; adj_s <= adj_p; adj_s += 2 * adj_p) {
1865
1866 test_t = offset;
1867
5b7749b0 David Hilvert2007-04-26 04:36:00 +00001868 test_t.translate(i ? point(adj_s, 0) : point(0, adj_s));
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00001869
1870 set->push_back(test_t);
1871 }
1872 }
1873
cd621c15 David Hilvert2007-07-23 20:38:00 +00001874 static int threshold_ok(ale_accum error) {
34add5e1 David Hilvert2007-10-17 21:47:00 +00001875 if ((1 - error) * (ale_accum) 100 >= match_threshold)
cd621c15
DH
David Hilvert2007-07-23 20:38:00 +00001876 return 1;
1877
1878 if (!(match_threshold >= 0))
1879 return 1;
1880
1881 return 0;
1882 }
228e156a David Hilvert2007-04-22 23:17:00 +00001883
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00001884 static diff_stat_t _align_element(ale_pos perturb, ale_pos local_lower,
1885 scale_cluster *scale_clusters, diff_stat_t here,
1886 ale_pos adj_p, ale_pos adj_o, ale_pos adj_b,
1887 ale_pos *current_bd, ale_pos *modified_bd,
1888 astate_t *astate, int lod, scale_cluster si) {
1889
1890 /*
1891 * Run initial tests to get perturbation multipliers and error
1892 * centroids.
1893 */
1894
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001895 std::vector<d2::trans_single> t_set;
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00001896
1897 here.get_perturb_set(&t_set, adj_p, adj_o, adj_b, current_bd, modified_bd);
1898
1899 int stable_count = 0;
1900
1901 while (perturb >= local_lower) {
fc8ecb0a
DH
David Hilvert2008-05-24 21:32:43 +00001902
1903 ui::get()->alignment_dims(scale_clusters[lod].accum->height(), scale_clusters[lod].accum->width(),
1904 scale_clusters[lod].input->height(), scale_clusters[lod].input->width());
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00001905
1906 /*
1907 * Orientational adjustment value in degrees.
1908 *
1909 * Since rotational perturbation is now specified as an
1910 * arclength, we have to convert.
1911 */
1912
1913 ale_pos adj_o = 2 * (double) perturb
1914 / sqrt(pow(scale_clusters[0].input->height(), 2)
1915 + pow(scale_clusters[0].input->width(), 2))
1916 * 180
1917 / M_PI;
1918
1919 /*
1920 * Barrel distortion adjustment value
1921 */
1922
1923 ale_pos adj_b = perturb * bda_mult;
1924
648ade15 David Hilvert2008-07-03 03:49:22 +00001925 trans_single old_offset = here.get_offset();
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00001926
1927 here.perturb_test(perturb, adj_p, adj_o, adj_b, current_bd, modified_bd,
1928 stable_count);
1929
648ade15 David Hilvert2008-07-03 03:49:22 +00001930 if (here.get_offset() == old_offset)
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00001931 stable_count++;
1932 else
1933 stable_count = 0;
1934
1935 if (stable_count == 3) {
1936
1937 stable_count = 0;
1938
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001939 perturb *= 0.5;
3e3f229f David Hilvert2008-02-13 16:42:00 +00001940
5bb67119 David Hilvert2008-05-31 02:43:37 +00001941 if (lod > 0
a9f7d778 David Hilvert2008-05-31 06:39:31 +00001942 && lod > lrint(log(perturb) / log(2)) - lod_preferred) {
3e3f229f David Hilvert2008-02-13 16:42:00 +00001943
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001944 /*
1945 * Work with images twice as large
1946 */
3e3f229f David Hilvert2008-02-13 16:42:00 +00001947
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001948 lod--;
1949 si = scale_clusters[lod];
3e3f229f David Hilvert2008-02-13 16:42:00 +00001950
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001951 /*
1952 * Rescale the transforms.
1953 */
3e3f229f David Hilvert2008-02-13 16:42:00 +00001954
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001955 ale_pos rescale_factor = (double) scale_factor
1956 / (double) pow(2, lod)
1957 / (double) here.get_offset().scale();
3e3f229f David Hilvert2008-02-13 16:42:00 +00001958
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001959 here.rescale(rescale_factor, si);
3e3f229f David Hilvert2008-02-13 16:42:00 +00001960
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001961 } else {
6a39b1c3 David Hilvert2008-05-31 06:21:26 +00001962 adj_p = perturb / pow(2, lod);
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001963 }
3e3f229f David Hilvert2008-02-13 16:42:00 +00001964
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001965 /*
1966 * Announce changes
1967 */
3e3f229f David Hilvert2008-02-13 16:42:00 +00001968
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001969 ui::get()->alignment_perturbation_level(perturb, lod);
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00001970 }
1971
1972 ui::get()->set_match(here.get_error());
1973 ui::get()->set_offset(here.get_offset());
1974 }
1975
1976 if (lod > 0) {
1977 ale_pos rescale_factor = (double) scale_factor
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00001978 / (double) here.get_offset().scale();
1979
1980 here.rescale(rescale_factor, scale_clusters[0]);
1981 }
1982
1983 return here;
1984 }
1985
228e156a David Hilvert2007-04-22 23:17:00 +00001986 /*
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00001987 * Check for satisfaction of the certainty threshold.
1988 */
1989 static int ma_cert_satisfied(const scale_cluster &c, const transformation &t, unsigned int i) {
d790f7da David Hilvert2008-05-02 18:59:43 -05001990 transformation::elem_bounds_int_t b = t.elem_bounds().scale_to_bounds(c.accum->height(), c.accum->width());
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00001991 ale_accum sum[3] = {0, 0, 0};
1992
d790f7da
DH
David Hilvert2008-05-02 18:59:43 -05001993 for (unsigned int ii = b.imin; ii < b.imax; ii++)
1994 for (unsigned int jj = b.jmin; jj < b.jmax; jj++) {
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00001995 pixel p = c.accum->get_pixel(ii, jj);
1996 sum[0] += p[0];
1997 sum[1] += p[1];
1998 sum[2] += p[2];
1999 }
2000
d790f7da David Hilvert2008-05-02 18:59:43 -05002001 unsigned int count = (b.jmax - b.jmin) * (b.imax - b.imin);
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00002002
2003 for (int k = 0; k < 3; k++)
2004 if (sum[k] / count < _ma_cert)
2005 return 0;
2006
2007 return 1;
2008 }
2009
1b980378
DH
David Hilvert2008-07-18 18:30:40 +00002010 static diff_stat_t check_ancestor_path(const trans_multi &offset, const scale_cluster &si, diff_stat_t here, int local_ax_count, int frame) {
2011
2012 if (offset.get_current_index() > 0)
2013 for (int i = offset.parent_index(offset.get_current_index()); i >= 0; i = (i > 0) ? (int) offset.parent_index(i) : -1) {
2014 trans_single t = offset.get_element(i);
2015 t.rescale(offset.get_current_element().scale());
2016
2017 here.diff(si, t, local_ax_count, frame);
2018
e0577945 David Hilvert2008-07-19 22:11:55 +00002019 if (here.better_defined())
1b980378
DH
David Hilvert2008-07-18 18:30:40 +00002020 here.confirm();
2021 else
2022 here.discard();
2023 }
2024
2025 return here;
2026 }
2027
46f9776a dhilvert2005-01-07 06:44:00 +00002028#ifdef USE_FFTW
2029 /*
2030 * High-pass filter for frequency weights
2031 */
2032 static void hipass(int rows, int cols, fftw_complex *inout) {
2033 for (int i = 0; i < rows * vert_freq_cut; i++)
2034 for (int j = 0; j < cols; j++)
2035 for (int k = 0; k < 2; k++)
2036 inout[i * cols + j][k] = 0;
2037 for (int i = 0; i < rows; i++)
2038 for (int j = 0; j < cols * horiz_freq_cut; j++)
2039 for (int k = 0; k < 2; k++)
2040 inout[i * cols + j][k] = 0;
2041 for (int i = 0; i < rows; i++)
2042 for (int j = 0; j < cols; j++)
2043 for (int k = 0; k < 2; k++)
2044 if (i / (double) rows + j / (double) cols < 2 * avg_freq_cut)
2045 inout[i * cols + j][k] = 0;
2046 }
2047#endif
2048
2aa417e6 dhilvert2005-01-07 06:44:00 +00002049
2050 /*
2051 * Reset alignment weights
2052 */
2053 static void reset_weights() {
07271611 dhilvert2005-01-07 06:48:00 +00002054 if (alignment_weights != NULL)
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002055 ale_image_release(alignment_weights);
07271611 dhilvert2005-01-07 06:48:00 +00002056
2057 alignment_weights = NULL;
2aa417e6 dhilvert2005-01-07 06:44:00 +00002058 }
2059
2060 /*
2061 * Initialize alignment weights
2062 */
2063 static void init_weights() {
2064 if (alignment_weights != NULL)
2065 return;
2066
3617b771 David Hilvert2009-05-31 15:07:14 +00002067 alignment_weights = ale_new_image(accel::context(), ALE_IMAGE_RGB, ale_image_get_type(reference_image));
2aa417e6 dhilvert2005-01-07 06:44:00 +00002068
2069 assert (alignment_weights);
2070
e28f8ff7 David Hilvert2009-06-02 22:23:44 +00002071 assert (!ale_resize_image(alignment_weights, 0, 0, ale_image_get_width(reference_image), ale_image_get_height(reference_image)));
3617b771 David Hilvert2009-05-31 15:07:14 +00002072
e28f8ff7 David Hilvert2009-06-02 22:23:44 +00002073 ale_image_map_0(alignment_weights, "SET_PIXEL(p, PIXEL(1, 1, 1))");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002074 }
2075
46f9776a dhilvert2005-01-07 06:44:00 +00002076 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002077 * Update alignment weights with weight map
2078 */
2079 static void map_update() {
2080
2081 if (weight_map == NULL)
2082 return;
2083
2084 init_weights();
2085
c17dab23 David Hilvert2009-06-04 15:49:20 +00002086 ale_image_map_2(alignment_weights, alignment_weights, weight_map, " \
af765c9b David Hilvert2009-06-12 19:51:02 +00002087 SET_PIXEL(p, GET_PIXEL(0, p) * GET_PIXEL_BG(1, p))");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002088 }
2089
2090 /*
2091 * Update alignment weights with algorithmic weights
46f9776a dhilvert2005-01-07 06:44:00 +00002092 */
2093 static void wmx_update() {
2094#ifdef USE_UNIX
2095
2096 static exposure *exp_def = new exposure_default();
2097 static exposure *exp_bool = new exposure_boolean();
2098
46f9776a dhilvert2005-01-07 06:44:00 +00002099 if (wmx_file == NULL || wmx_exec == NULL || wmx_defs == NULL)
2100 return;
2101
33a3cc28
DH
David Hilvert2009-06-03 19:51:46 +00002102 unsigned int rows = ale_image_get_height(reference_image);
2103 unsigned int cols = ale_image_get_width(reference_image);
46f9776a dhilvert2005-01-07 06:44:00 +00002104
2105 image_rw::write_image(wmx_file, reference_image);
ac4577d5 David Hilvert2009-06-14 19:02:25 +00002106 image_rw::write_image(wmx_defs, reference_image, exp_bool->get_gamma(), 0, 0, 1);
46f9776a dhilvert2005-01-07 06:44:00 +00002107
2108 /* execute ... */
2109 int exit_status = 1;
2110 if (!fork()) {
2111 execlp(wmx_exec, wmx_exec, wmx_file, wmx_defs, NULL);
07271611 dhilvert2005-01-07 06:48:00 +00002112 ui::get()->exec_failure(wmx_exec, wmx_file, wmx_defs);
46f9776a dhilvert2005-01-07 06:44:00 +00002113 }
2114
2115 wait(&exit_status);
2116
07271611 dhilvert2005-01-07 06:48:00 +00002117 if (exit_status)
2118 ui::get()->fork_failure("d2::align");
46f9776a dhilvert2005-01-07 06:44:00 +00002119
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002120 ale_image wmx_weights = image_rw::read_image(wmx_file, exp_def);
46f9776a dhilvert2005-01-07 06:44:00 +00002121
35c1c6e3
DH
David Hilvert2009-06-14 21:17:14 +00002122 ale_image_set_x_offset(wmx_weights, ale_image_get_x_offset(reference_image));
2123 ale_image_set_y_offset(wmx_weights, ale_image_get_y_offset(reference_image));
5073b97e David Hilvert2009-06-14 20:59:56 +00002124
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002125 if (ale_image_get_height(wmx_weights) != rows || ale_image_get_width(wmx_weights) != cols)
07271611 dhilvert2005-01-07 06:48:00 +00002126 ui::get()->error("algorithmic weighting must not change image size");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002127
2128 if (alignment_weights == NULL)
2129 alignment_weights = wmx_weights;
2130 else
5073b97e
DH
David Hilvert2009-06-14 20:59:56 +00002131 ale_image_map_2(alignment_weights, alignment_weights, wmx_weights, "\
2132 SET_PIXEL(p, GET_PIXEL(0, p) * GET_PIXEL(1, p))");
46f9776a dhilvert2005-01-07 06:44:00 +00002133#endif
2134 }
2135
2136 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002137 * Update alignment weights with frequency weights
46f9776a dhilvert2005-01-07 06:44:00 +00002138 */
2139 static void fw_update() {
2140#ifdef USE_FFTW
46f9776a dhilvert2005-01-07 06:44:00 +00002141 if (horiz_freq_cut == 0
2142 && vert_freq_cut == 0
2143 && avg_freq_cut == 0)
2144 return;
2145
2aa417e6 dhilvert2005-01-07 06:44:00 +00002146 /*
2147 * Required for correct operation of --fwshow
2148 */
2149
2150 assert (alignment_weights == NULL);
2151
46f9776a dhilvert2005-01-07 06:44:00 +00002152 int rows = reference_image->height();
2153 int cols = reference_image->width();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002154 int colors = reference_image->depth();
46f9776a dhilvert2005-01-07 06:44:00 +00002155
7cc12274 David Hilvert2007-12-11 04:50:00 +00002156 alignment_weights = new_image_ale_real(rows, cols,
2aa417e6 dhilvert2005-01-07 06:44:00 +00002157 colors, "alignment_weights");
46f9776a dhilvert2005-01-07 06:44:00 +00002158
2159 fftw_complex *inout = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * rows * cols);
2160
2161 assert (inout);
2162
2163 fftw_plan pf = fftw_plan_dft_2d(rows, cols,
2164 inout, inout,
2165 FFTW_FORWARD, FFTW_ESTIMATE);
2166
2167 fftw_plan pb = fftw_plan_dft_2d(rows, cols,
2168 inout, inout,
2169 FFTW_BACKWARD, FFTW_ESTIMATE);
2170
2aa417e6 dhilvert2005-01-07 06:44:00 +00002171 for (int k = 0; k < colors; k++) {
46f9776a dhilvert2005-01-07 06:44:00 +00002172 for (int i = 0; i < rows * cols; i++) {
2173 inout[i][0] = reference_image->get_pixel(i / cols, i % cols)[k];
2174 inout[i][1] = 0;
2175 }
2176
2177 fftw_execute(pf);
2178 hipass(rows, cols, inout);
2179 fftw_execute(pb);
2180
2181 for (int i = 0; i < rows * cols; i++) {
2182#if 0
2aa417e6 dhilvert2005-01-07 06:44:00 +00002183 alignment_weights->pix(i / cols, i % cols)[k] = fabs(inout[i][0] / (rows * cols));
46f9776a dhilvert2005-01-07 06:44:00 +00002184#else
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00002185 alignment_weights->set_chan(i / cols, i % cols, k,
46f9776a dhilvert2005-01-07 06:44:00 +00002186 sqrt(pow(inout[i][0] / (rows * cols), 2)
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00002187 + pow(inout[i][1] / (rows * cols), 2)));
46f9776a dhilvert2005-01-07 06:44:00 +00002188#endif
2189 }
2190 }
2191
2192 fftw_destroy_plan(pf);
2193 fftw_destroy_plan(pb);
2194 fftw_free(inout);
2195
2196 if (fw_output != NULL)
2aa417e6 dhilvert2005-01-07 06:44:00 +00002197 image_rw::write_image(fw_output, alignment_weights);
46f9776a dhilvert2005-01-07 06:44:00 +00002198#endif
2199 }
2200
30afe4b6 dhilvert2005-01-07 06:42:00 +00002201 /*
2202 * Update alignment to frame N.
2203 */
2204 static void update_to(int n) {
0e4ec247 David Hilvert2007-03-13 04:51:00 +00002205
30afe4b6 dhilvert2005-01-07 06:42:00 +00002206 assert (n <= latest + 1);
0a432b63 David Hilvert2007-03-13 08:03:00 +00002207 assert (n >= 0);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002208
e580d9d3 David Hilvert2007-12-19 16:59:00 +00002209 static astate_t astate;
f65325e3 David Hilvert2007-03-15 06:24:00 +00002210
724b1c71
DH
David Hilvert2008-07-01 15:20:56 +00002211 ui::get()->set_frame_num(n);
2212
46f9776a dhilvert2005-01-07 06:44:00 +00002213 if (latest < 0) {
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002214
2215 /*
2216 * Handle the initial frame
2217 */
2218
0467efe3 David Hilvert2008-04-09 21:14:38 +00002219 astate.set_input_frame(image_rw::open(n));
0a432b63 David Hilvert2007-03-13 08:03:00 +00002220
0467efe3 David Hilvert2008-04-09 21:14:38 +00002221 const image *i = astate.get_input_frame();
46f9776a dhilvert2005-01-07 06:44:00 +00002222 int is_default;
2223 transformation result = alignment_class == 2
2224 ? transformation::gpt_identity(i, scale_factor)
2225 : transformation::eu_identity(i, scale_factor);
2226 result = tload_first(tload, alignment_class == 2, result, &is_default);
2227 tsave_first(tsave, result, alignment_class == 2);
46f9776a dhilvert2005-01-07 06:44:00 +00002228
2229 if (_keep > 0) {
dd761b64 David Hilvert2008-01-26 17:41:00 +00002230 kept_t = transformation::new_eu_identity_array(image_rw::count());
46f9776a dhilvert2005-01-07 06:44:00 +00002231 kept_ok = (int *) malloc(image_rw::count()
2232 * sizeof(int));
2233 assert (kept_t);
2234 assert (kept_ok);
2235
07271611 dhilvert2005-01-07 06:48:00 +00002236 if (!kept_t || !kept_ok)
2237 ui::get()->memory_error("alignment");
46f9776a dhilvert2005-01-07 06:44:00 +00002238
2239 kept_ok[0] = 1;
2240 kept_t[0] = result;
2241 }
2242
2243 latest = 0;
2244 latest_ok = 1;
2245 latest_t = result;
2246
0467efe3 David Hilvert2008-04-09 21:14:38 +00002247 astate.set_default(result);
46f9776a dhilvert2005-01-07 06:44:00 +00002248 orig_t = result;
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002249
2250 image_rw::close(n);
46f9776a dhilvert2005-01-07 06:44:00 +00002251 }
2252
bbc7699c David Hilvert2007-04-02 03:05:00 +00002253 for (int i = latest + 1; i <= n; i++) {
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002254
2255 /*
2256 * Handle supplemental frames.
2257 */
2258
46f9776a dhilvert2005-01-07 06:44:00 +00002259 assert (reference != NULL);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002260
07271611 dhilvert2005-01-07 06:48:00 +00002261 ui::get()->set_arender_current();
46f9776a dhilvert2005-01-07 06:44:00 +00002262 reference->sync(i - 1);
07271611 dhilvert2005-01-07 06:48:00 +00002263 ui::get()->clear_arender_current();
46f9776a dhilvert2005-01-07 06:44:00 +00002264 reference_image = reference->get_image();
2265 reference_defined = reference->get_defined();
30afe4b6 dhilvert2005-01-07 06:42:00 +00002266
f2fc9b99 David Hilvert2008-02-14 17:35:00 +00002267 if (i == 1)
0467efe3 David Hilvert2008-04-09 21:14:38 +00002268 astate.default_set_original_bounds(reference_image);
f2fc9b99 David Hilvert2008-02-14 17:35:00 +00002269
2aa417e6 dhilvert2005-01-07 06:44:00 +00002270 reset_weights();
46f9776a dhilvert2005-01-07 06:44:00 +00002271 fw_update();
2272 wmx_update();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002273 map_update();
30afe4b6 dhilvert2005-01-07 06:42:00 +00002274
46f9776a dhilvert2005-01-07 06:44:00 +00002275 assert (reference_image != NULL);
2276 assert (reference_defined != NULL);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002277
0467efe3 David Hilvert2008-04-09 21:14:38 +00002278 astate.set_input_frame(image_rw::open(i));
0a432b63 David Hilvert2007-03-13 08:03:00 +00002279
e580d9d3 David Hilvert2007-12-19 16:59:00 +00002280 _align(i, _gs, &astate);
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002281
2282 image_rw::close(n);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002283 }
2284 }
2285
2286public:
2287
2288 /*
04382119 dhilvert2005-04-29 09:23:00 +00002289 * Set the control point count
2290 */
2291 static void set_cp_count(unsigned int n) {
2292 assert (cp_array == NULL);
2293
2294 cp_count = n;
2295 cp_array = (const point **) malloc(n * sizeof(const point *));
2296 }
2297
2298 /*
2299 * Set control points.
2300 */
2301 static void set_cp(unsigned int i, const point *p) {
2302 cp_array[i] = p;
2303 }
2304
2305 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002306 * Register exposure
2307 */
2308 static void exp_register() {
2309 _exp_register = 1;
2310 }
2311
2312 /*
3dc20778 dhilvert2005-01-10 23:06:00 +00002313 * Register exposure only based on metadata
2314 */
2315 static void exp_meta_only() {
2316 _exp_register = 2;
2317 }
2318
2319 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002320 * Don't register exposure
2321 */
2322 static void exp_noregister() {
2323 _exp_register = 0;
2324 }
2325
2326 /*
2327 * Set alignment class to translation only. Only adjust the x and y
2328 * position of images. Do not rotate input images or perform
2329 * projective transformations.
2330 */
2331 static void class_translation() {
2332 alignment_class = 0;
2333 }
2334
2335 /*
2336 * Set alignment class to Euclidean transformations only. Adjust the x
2337 * and y position of images and the orientation of the image about the
2338 * image center.
2339 */
2340 static void class_euclidean() {
2341 alignment_class = 1;
2342 }
2343
2344 /*
2345 * Set alignment class to perform general projective transformations.
2346 * See the file gpt.h for more information about general projective
2347 * transformations.
2348 */
2349 static void class_projective() {
2350 alignment_class = 2;
2351 }
2352
2353 /*
2354 * Set the default initial alignment to the identity transformation.
2355 */
2356 static void initial_default_identity() {
2357 default_initial_alignment_type = 0;
2358 }
2359
2360 /*
2361 * Set the default initial alignment to the most recently matched
2362 * frame's final transformation.
2363 */
2364 static void initial_default_follow() {
2365 default_initial_alignment_type = 1;
2366 }
2367
2368 /*
f09b7254 dhilvert2005-01-07 06:44:00 +00002369 * Perturb output coordinates.
2370 */
2371 static void perturb_output() {
2372 perturb_type = 0;
2373 }
2374
2375 /*
2376 * Perturb source coordinates.
2377 */
2378 static void perturb_source() {
2379 perturb_type = 1;
2380 }
2381
2382 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002383 * Frames under threshold align optimally
2384 */
2385 static void fail_optimal() {
2386 is_fail_default = 0;
2387 }
2388
2389 /*
2390 * Frames under threshold keep their default alignments.
2391 */
2392 static void fail_default() {
2393 is_fail_default = 1;
2394 }
2395
2396 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002397 * Align images with an error contribution from each color channel.
2398 */
2399 static void all() {
2400 channel_alignment_type = 0;
2401 }
2402
2403 /*
2404 * Align images with an error contribution only from the green channel.
2405 * Other color channels do not affect alignment.
2406 */
2407 static void green() {
2408 channel_alignment_type = 1;
2409 }
2410
2411 /*
2412 * Align images using a summation of channels. May be useful when
2413 * dealing with images that have high frequency color ripples due to
2414 * color aliasing.
2415 */
2416 static void sum() {
2417 channel_alignment_type = 2;
2418 }
2419
2420 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002421 * Error metric exponent
2422 */
2423
2424 static void set_metric_exponent(float me) {
2425 metric_exponent = me;
2426 }
2427
2428 /*
2429 * Match threshold
2430 */
2431
2432 static void set_match_threshold(float mt) {
2433 match_threshold = mt;
2434 }
2435
2436 /*
2437 * Perturbation lower and upper bounds.
2438 */
2439
f09b7254 dhilvert2005-01-07 06:44:00 +00002440 static void set_perturb_lower(ale_pos pl, int plp) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002441 perturb_lower = pl;
f09b7254 dhilvert2005-01-07 06:44:00 +00002442 perturb_lower_percent = plp;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002443 }
2444
f09b7254 dhilvert2005-01-07 06:44:00 +00002445 static void set_perturb_upper(ale_pos pu, int pup) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002446 perturb_upper = pu;
f09b7254 dhilvert2005-01-07 06:44:00 +00002447 perturb_upper_percent = pup;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002448 }
2449
2450 /*
2451 * Maximum rotational perturbation.
2452 */
2453
2454 static void set_rot_max(int rm) {
2455
2456 /*
2457 * Obtain the largest power of two not larger than rm.
2458 */
2459
2460 rot_max = pow(2, floor(log(rm) / log(2)));
2461 }
2462
2463 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002464 * Barrel distortion adjustment multiplier
2465 */
2466
2467 static void set_bda_mult(ale_pos m) {
2468 bda_mult = m;
2469 }
2470
2471 /*
2472 * Barrel distortion maximum rate of change
2473 */
2474
2475 static void set_bda_rate(ale_pos m) {
2476 bda_rate = m;
2477 }
2478
2479 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002480 * Level-of-detail
2481 */
2482
5292ffa7
DH
David Hilvert2008-05-28 01:17:53 +00002483 static void set_lod_preferred(int lm) {
2484 lod_preferred = lm;
2485 }
2486
2487 /*
2488 * Minimum dimension for reduced level-of-detail.
2489 */
2490
2491 static void set_min_dimension(int md) {
2492 min_dimension = md;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002493 }
2494
2495 /*
2496 * Set the scale factor
2497 */
2498 static void set_scale(ale_pos s) {
2499 scale_factor = s;
2500 }
2501
2502 /*
2503 * Set reference rendering to align against
2504 */
2505 static void set_reference(render *r) {
2506 reference = r;
2507 }
2508
2509 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002510 * Set the interpolant
2511 */
2512 static void set_interpolant(filter::scaled_filter *f) {
2513 interpolant = f;
2514 }
2515
2516 /*
2517 * Set alignment weights image
2518 */
2aa417e6 dhilvert2005-01-07 06:44:00 +00002519 static void set_weight_map(const image *i) {
2520 weight_map = i;
46f9776a dhilvert2005-01-07 06:44:00 +00002521 }
2522
2523 /*
2524 * Set frequency cuts
2525 */
2526 static void set_frequency_cut(double h, double v, double a) {
2527 horiz_freq_cut = h;
2528 vert_freq_cut = v;
2529 avg_freq_cut = a;
2530 }
2531
2532 /*
2533 * Set algorithmic alignment weighting
2534 */
2535 static void set_wmx(const char *e, const char *f, const char *d) {
2536 wmx_exec = e;
2537 wmx_file = f;
2538 wmx_defs = d;
2539 }
2540
2541 /*
2542 * Show frequency weights
2543 */
2544 static void set_fl_show(const char *filename) {
2545 fw_output = filename;
2546 }
2547
2548 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002549 * Set transformation file loader.
2550 */
2551 static void set_tload(tload_t *tl) {
2552 tload = tl;
2553 }
2554
2555 /*
2556 * Set transformation file saver.
2557 */
2558 static void set_tsave(tsave_t *ts) {
2559 tsave = ts;
2560 }
2561
2562 /*
2563 * Get match statistics for frame N.
30afe4b6 dhilvert2005-01-07 06:42:00 +00002564 */
2565 static int match(int n) {
2566 update_to(n);
2567
46f9776a dhilvert2005-01-07 06:44:00 +00002568 if (n == latest)
30afe4b6 dhilvert2005-01-07 06:42:00 +00002569 return latest_ok;
2570 else if (_keep)
2571 return kept_ok[n];
46f9776a dhilvert2005-01-07 06:44:00 +00002572 else {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002573 assert(0);
46f9776a dhilvert2005-01-07 06:44:00 +00002574 exit(1);
2575 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00002576 }
2577
2578 /*
2579 * Message that old alignment data should be kept.
2580 */
2581 static void keep() {
46f9776a dhilvert2005-01-07 06:44:00 +00002582 assert (latest == -1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002583 _keep = 1;
2584 }
2585
2586 /*
2587 * Get alignment for frame N.
30afe4b6 dhilvert2005-01-07 06:42:00 +00002588 */
2589 static transformation of(int n) {
2590 update_to(n);
46f9776a dhilvert2005-01-07 06:44:00 +00002591 if (n == latest)
30afe4b6 dhilvert2005-01-07 06:42:00 +00002592 return latest_t;
2593 else if (_keep)
2594 return kept_t[n];
2595 else {
2596 assert(0);
2597 exit(1);
2598 }
2599 }
2600
2601 /*
bddc9e4d David Hilvert2007-10-01 19:50:00 +00002602 * Use Monte Carlo alignment sampling with argument N.
1c2f7405 David Hilvert2007-09-20 16:58:00 +00002603 */
bddc9e4d
DH
David Hilvert2007-10-01 19:50:00 +00002604 static void mc(ale_pos n) {
2605 _mc = n;
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +00002606 }
2607
2608 /*
07271611 dhilvert2005-01-07 06:48:00 +00002609 * Set the certainty-weighted flag.
2610 */
2611 static void certainty_weighted(int flag) {
2612 certainty_weights = flag;
2613 }
2614
2615 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002616 * Set the global search type.
2617 */
2618 static void gs(const char *type) {
7bcfe5db dhilvert2005-01-07 06:44:00 +00002619 if (!strcmp(type, "local")) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00002620 _gs = 0;
2621 } else if (!strcmp(type, "inner")) {
2622 _gs = 1;
2623 } else if (!strcmp(type, "outer")) {
2624 _gs = 2;
2625 } else if (!strcmp(type, "all")) {
2626 _gs = 3;
2627 } else if (!strcmp(type, "central")) {
2628 _gs = 4;
842afc18
DH
David Hilvert2007-05-08 06:55:00 +00002629 } else if (!strcmp(type, "defaults")) {
2630 _gs = 6;
04382119 dhilvert2005-04-29 09:23:00 +00002631 } else if (!strcmp(type, "points")) {
2632 _gs = 5;
b386e644 dhilvert2005-04-30 09:28:00 +00002633 keep();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002634 } else {
07271611 dhilvert2005-01-07 06:48:00 +00002635 ui::get()->error("bad global search type");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002636 }
2637 }
2638
2639 /*
4949c031 dhilvert2005-01-07 06:44:00 +00002640 * Set the minimum overlap for global searching
2641 */
326c35b1 David Hilvert2007-04-19 21:28:00 +00002642 static void gs_mo(ale_pos value, int _gs_mo_percent) {
4949c031 dhilvert2005-01-07 06:44:00 +00002643 _gs_mo = value;
326c35b1 David Hilvert2007-04-19 21:28:00 +00002644 gs_mo_percent = _gs_mo_percent;
4949c031 dhilvert2005-01-07 06:44:00 +00002645 }
2646
2647 /*
903df240
DH
David Hilvert2008-04-24 14:36:35 +00002648 * Set mutli-alignment certainty lower bound.
2649 */
2650 static void set_ma_cert(ale_real value) {
2651 _ma_cert = value;
2652 }
2653
2654 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002655 * Set alignment exclusion regions
2656 */
df55d1a2 dhilvert2006-08-30 07:40:00 +00002657 static void set_exclusion(exclusion *_ax_parameters, int _ax_count) {
46f9776a dhilvert2005-01-07 06:44:00 +00002658 ax_count = _ax_count;
2659 ax_parameters = _ax_parameters;
2660 }
2661
2662 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002663 * Get match summary statistics.
2664 */
2665 static ale_accum match_summary() {
34add5e1 David Hilvert2007-10-17 21:47:00 +00002666 return match_sum / (ale_accum) match_count;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002667 }
2668};
2669
f8864302
DH
David Hilvert2008-04-11 18:15:57 +00002670template<class diff_trans>
2671void *d2::align::diff_stat_generic<diff_trans>::diff_subdomain(void *args) {
2672
2673 subdomain_args *sargs = (subdomain_args *) args;
2674
2675 struct scale_cluster c = sargs->c;
2676 std::vector<run> runs = sargs->runs;
2677 int ax_count = sargs->ax_count;
2678 int f = sargs->f;
2679 int i_min = sargs->i_min;
2680 int i_max = sargs->i_max;
2681 int j_min = sargs->j_min;
2682 int j_max = sargs->j_max;
2683 int subdomain = sargs->subdomain;
2684
2685 assert (reference_image);
2686
2687 point offset = c.accum->offset();
2688
2689 for (mc_iterate m(i_min, i_max, j_min, j_max, subdomain); !m.done(); m++) {
2690
2691 int i = m.get_i();
2692 int j = m.get_j();
2693
2694 /*
2695 * Check reference frame definition.
2696 */
2697
2698 if (!((pixel) c.accum->get_pixel(i, j)).finite()
2699 || !(((pixel) c.certainty->get_pixel(i, j)).minabs_norm() > 0))
2700 continue;
2701
2702 /*
2703 * Check for exclusion in render coordinates.
2704 */
2705
2706 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
2707 continue;
2708
2709 /*
2710 * Transform
2711 */
2712
2713 struct point q, r = point::undefined();
2714
2715 q = (c.input_scale < 1.0 && interpolant == NULL)
2716 ? runs.back().offset.scaled_inverse_transform(
2717 point(i + offset[0], j + offset[1]))
2718 : runs.back().offset.unscaled_inverse_transform(
2719 point(i + offset[0], j + offset[1]));
2720
2721 if (runs.size() == 2) {
2722 r = (c.input_scale < 1.0)
2723 ? runs.front().offset.scaled_inverse_transform(
2724 point(i + offset[0], j + offset[1]))
2725 : runs.front().offset.unscaled_inverse_transform(
2726 point(i + offset[0], j + offset[1]));
2727 }
2728
2729 ale_pos ti = q[0];
2730 ale_pos tj = q[1];
2731
2732 /*
2733 * Check that the transformed coordinates are within
2734 * the boundaries of array c.input and that they
2735 * are not subject to exclusion.
2736 *
2737 * Also, check that the weight value in the accumulated array
2738 * is nonzero, unless we know it is nonzero by virtue of the
2739 * fact that it falls within the region of the original frame
2740 * (e.g. when we're not increasing image extents).
2741 */
2742
2743 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
2744 continue;
2745
2746 if (input_excluded(r[0], r[1], c.ax_parameters, ax_count))
2747 r = point::undefined();
2748
2749 /*
2750 * Check the boundaries of the input frame
2751 */
2752
2753 if (!(ti >= 0
2754 && ti <= c.input->height() - 1
2755 && tj >= 0
2756 && tj <= c.input->width() - 1))
2757 continue;
2758
2759 if (!(r[0] >= 0
2760 && r[0] <= c.input->height() - 1
2761 && r[1] >= 0
2762 && r[1] <= c.input->width() - 1))
2763 r = point::undefined();
2764
2765 sargs->runs.back().sample(f, c, i, j, q, r, runs.front());
2766 }
2767
2768 return NULL;
2769}
2770
30afe4b6 dhilvert2005-01-07 06:42:00 +00002771#endif