d2/align: Outline plans for split in following functionality between ALE and 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 /*
f922c1c4
DH
David Hilvert2009-06-22 00:04:12 +000040 * Alignment properties
41 */
42
43 static ale_align_properties align_properties() {
44 static ale_align_properties data = NULL;
45
46 if (data == NULL)
47 data = ale_new_align_properties();
48
49 assert(data);
50
51 return data;
52 }
53
54 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +000055 * Private data members
56 */
57
58 static ale_pos scale_factor;
59
60 /*
46f9776a dhilvert2005-01-07 06:44:00 +000061 * Original frame transformation
62 */
63 static transformation orig_t;
64
65 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +000066 * Keep data older than latest
67 */
68 static int _keep;
69 static transformation *kept_t;
70 static int *kept_ok;
71
72 /*
73 * Transformation file handlers
74 */
75
76 static tload_t *tload;
77 static tsave_t *tsave;
78
79 /*
04382119 dhilvert2005-04-29 09:23:00 +000080 * Control point variables
81 */
82
83 static const point **cp_array;
84 static unsigned int cp_count;
85
86 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +000087 * Reference rendering to align against
88 */
89
90 static render *reference;
46f9776a dhilvert2005-01-07 06:44:00 +000091 static filter::scaled_filter *interpolant;
3617b771 David Hilvert2009-05-31 15:07:14 +000092 static ale_image reference_image;
30afe4b6 dhilvert2005-01-07 06:42:00 +000093
46f9776a dhilvert2005-01-07 06:44:00 +000094 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +000095 * Per-pixel alignment weight map
46f9776a dhilvert2005-01-07 06:44:00 +000096 */
97
2f4c0699 David Hilvert2009-06-03 19:47:53 +000098 static ale_image weight_map;
46f9776a dhilvert2005-01-07 06:44:00 +000099
100 /*
101 * Frequency-dependent alignment weights
102 */
103
104 static double horiz_freq_cut;
105 static double vert_freq_cut;
106 static double avg_freq_cut;
46f9776a dhilvert2005-01-07 06:44:00 +0000107 static const char *fw_output;
108
109 /*
110 * Algorithmic alignment weighting
111 */
112
113 static const char *wmx_exec;
114 static const char *wmx_file;
115 static const char *wmx_defs;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000116
117 /*
19b07c65 David Hilvert2007-09-11 18:07:00 +0000118 * Non-certainty alignment weights
2aa417e6 dhilvert2005-01-07 06:44:00 +0000119 */
120
c2d1a70e David Hilvert2009-05-30 15:37:04 +0000121 static ale_image alignment_weights;
46f9776a dhilvert2005-01-07 06:44:00 +0000122
30afe4b6 dhilvert2005-01-07 06:42:00 +0000123 /*
124 * Latest transformation.
125 */
126
127 static transformation latest_t;
128
129 /*
130 * Flag indicating whether the latest transformation
131 * resulted in a match.
132 */
133
134 static int latest_ok;
135
136 /*
137 * Frame number most recently aligned.
138 */
139
140 static int latest;
141
142 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000143 * Exposure registration
144 *
145 * 0. Preserve the original exposure of images.
146 *
147 * 1. Match exposure between images.
3dc20778 dhilvert2005-01-10 23:06:00 +0000148 *
149 * 2. Use only image metadata for registering exposure.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000150 */
151
152 static int _exp_register;
153
154 /*
155 * Alignment class.
156 *
157 * 0. Translation only. Only adjust the x and y position of images.
158 * Do not rotate input images or perform projective transformations.
159 *
160 * 1. Euclidean transformations only. Adjust the x and y position
161 * of images and the orientation of the image about the image center.
162 *
163 * 2. Perform general projective transformations. See the file gpt.h
164 * for more information about general projective transformations.
165 */
166
167 static int alignment_class;
168
169 /*
0a432b63 David Hilvert2007-03-13 08:03:00 +0000170 * Default initial alignment type.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000171 *
172 * 0. Identity transformation.
173 *
174 * 1. Most recently accepted frame's final transformation.
175 */
176
177 static int default_initial_alignment_type;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000178
179 /*
f09b7254 dhilvert2005-01-07 06:44:00 +0000180 * Projective group behavior
181 *
182 * 0. Perturb in output coordinates.
183 *
184 * 1. Perturb in source coordinates
185 */
186
187 static int perturb_type;
188
189 /*
46f9776a dhilvert2005-01-07 06:44:00 +0000190 * Alignment for failed frames -- default or optimal?
191 *
192 * A frame that does not meet the match threshold can be assigned the
193 * best alignment found, or can be assigned its alignment default.
194 */
195
196 static int is_fail_default;
197
198 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000199 * Alignment code.
200 *
201 * 0. Align images with an error contribution from each color channel.
202 *
203 * 1. Align images with an error contribution only from the green channel.
204 * Other color channels do not affect alignment.
205 *
206 * 2. Align images using a summation of channels. May be useful when dealing
207 * with images that have high frequency color ripples due to color aliasing.
208 */
209
210 static int channel_alignment_type;
211
212 /*
213 * Error metric exponent
214 */
215
42772195 David Hilvert2007-10-21 15:36:00 +0000216 static ale_real metric_exponent;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000217
218 /*
219 * Match threshold
220 */
221
222 static float match_threshold;
223
224 /*
225 * Perturbation lower and upper bounds.
226 */
227
228 static ale_pos perturb_lower;
f09b7254 dhilvert2005-01-07 06:44:00 +0000229 static int perturb_lower_percent;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000230 static ale_pos perturb_upper;
f09b7254 dhilvert2005-01-07 06:44:00 +0000231 static int perturb_upper_percent;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000232
233 /*
5292ffa7 David Hilvert2008-05-28 01:17:53 +0000234 * Preferred level-of-detail scale factor is 2^lod_preferred/perturb.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000235 */
236
5292ffa7
DH
David Hilvert2008-05-28 01:17:53 +0000237 static int lod_preferred;
238
239 /*
240 * Minimum dimension for reduced LOD.
241 */
242
243 static int min_dimension;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000244
245 /*
246 * Maximum rotational perturbation
247 */
248
249 static ale_pos rot_max;
250
251 /*
46f9776a dhilvert2005-01-07 06:44:00 +0000252 * Barrel distortion alignment multiplier
253 */
254
255 static ale_pos bda_mult;
256
257 /*
258 * Barrel distortion maximum adjustment rate
259 */
260
261 static ale_pos bda_rate;
262
263 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000264 * Alignment match sum
265 */
266
267 static ale_accum match_sum;
268
269 /*
270 * Alignment match count.
271 */
272
273 static int match_count;
274
275 /*
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000276 * Monte Carlo parameter
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +0000277 */
278
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000279 static ale_pos _mc;
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +0000280
281 /*
07271611 dhilvert2005-01-07 06:48:00 +0000282 * Certainty weight flag
283 *
284 * 0. Don't use certainty weights for alignment.
285 *
286 * 1. Use certainty weights for alignment.
287 */
288
289 static int certainty_weights;
290
291 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +0000292 * Global search parameter
293 *
7bcfe5db dhilvert2005-01-07 06:44:00 +0000294 * 0. Local: Local search only.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000295 * 1. Inner: Alignment reference image inner region
296 * 2. Outer: Alignment reference image outer region
7bcfe5db dhilvert2005-01-07 06:44:00 +0000297 * 3. All: Alignment reference image inner and outer regions.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000298 * 4. Central: Inner if possible; else, best of inner and outer.
04382119 dhilvert2005-04-29 09:23:00 +0000299 * 5. Points: Align by control points.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000300 */
301
302 static int _gs;
303
304 /*
4949c031 dhilvert2005-01-07 06:44:00 +0000305 * Minimum overlap for global searches
306 */
307
a7882498 David Hilvert2007-10-16 19:48:00 +0000308 static ale_accum _gs_mo;
326c35b1 David Hilvert2007-04-19 21:28:00 +0000309 static int gs_mo_percent;
4949c031 dhilvert2005-01-07 06:44:00 +0000310
311 /*
903df240
DH
David Hilvert2008-04-24 14:36:35 +0000312 * Minimum certainty for multi-alignment element registration.
313 */
314
315 static ale_real _ma_cert;
316
317 /*
46f9776a dhilvert2005-01-07 06:44:00 +0000318 * Exclusion regions
319 */
320
df55d1a2 dhilvert2006-08-30 07:40:00 +0000321 static exclusion *ax_parameters;
46f9776a dhilvert2005-01-07 06:44:00 +0000322 static int ax_count;
323
324 /*
8bba3df9
DH
David Hilvert2009-07-21 18:14:07 +0000325 * XXX: note that following in the case of non-primary elements must be
326 * split, so that Libale performs adjustments according to the
327 * immediate change in the parent element (likely depending on the
328 * alignment properties specified); for this and other reasons, it
329 * would be desirable to rewrite following logic more concisely, using,
330 * e.g., the recently-introduced ale_eval to facilitate abstraction, so
331 * that the split in functionality can be performed more cleanly.
3c9742dc
DH
David Hilvert2009-07-21 21:12:51 +0000332 *
333 * The split in following should probably assign to ALE functionality
334 * like this:
335 *
336 * Working one's way up the hierarchy,
337 *
338 * * If file data is available for both prev. and current transf's,
339 * -> use established 'delta --follow semantics' described below
340 * * If file data is available for only current transf.,
341 * -> adjust file current according to parent adjustment rel. to file.
342 * * else (2 cases)
343 * -> use parent calc. adj. by any prev. final against its parent.
344 *
345 * And assign to libale functionality like this:
346 *
347 * * correct each element based on an estimated error from alignment-
348 * calculated change in the parent element.
8bba3df9
DH
David Hilvert2009-07-21 18:14:07 +0000349 */
350
351 /*
352 * Alignment state
353 *
354 * This structure contains alignment state information. The change
355 * between the non-default old initial alignment and old final
356 * alignment is used to adjust the non-default current initial
357 * alignment. If either the old or new initial alignment is a default
358 * alignment, the old --follow semantics are preserved.
359 */
360
361 class astate_t {
362 ale_trans old_initial_alignment;
363 ale_trans old_final_alignment;
364 ale_trans default_initial_alignment;
365 int old_is_default;
366 std::vector<int> is_default;
367 ale_image input_frame;
368
369 public:
370 astate_t() :
371 is_default(1) {
372
373 old_initial_alignment = ale_new_trans(accel::context(), NULL);
374 old_final_alignment = ale_new_trans(accel::context(), NULL);
375 default_initial_alignment = ale_new_trans(accel::context(), NULL);
376
377 input_frame = NULL;
378 is_default[0] = 1;
379 old_is_default = 1;
380 }
381
382 ale_image get_input_frame() const {
383 return input_frame;
384 }
385
386 void set_is_default(unsigned int index, int value) {
387
388 /*
389 * Expand the array, if necessary.
390 */
391 if (index == is_default.size());
392 is_default.resize(index + 1);
393
394 assert (index < is_default.size());
395 is_default[index] = value;
396 }
397
398 int get_is_default(unsigned int index) {
399 assert (index < is_default.size());
400 return is_default[index];
401 }
402
403 ale_trans get_default() {
404 return default_initial_alignment;
405 }
406
407 void set_default(ale_trans t) {
408 default_initial_alignment = t;
409 }
410
411 void default_set_original_bounds(ale_image i) {
412 ale_trans_set_original_bounds(default_initial_alignment, i);
413 }
414
415 void set_final(ale_trans t) {
416 old_final_alignment = t;
417 }
418
419 void set_input_frame(ale_image i) {
420 input_frame = i;
421 }
422
423 /*
424 * Implement new delta --follow semantics.
425 *
426 * If we have a transformation T such that
427 *
428 * prev_final == T(prev_init)
429 *
430 * Then we also have
431 *
432 * current_init_follow == T(current_init)
433 *
434 * We can calculate T as follows:
435 *
436 * T == prev_final(prev_init^-1)
437 *
438 * Where ^-1 is the inverse operator.
439 */
440 static trans_single follow(trans_single a, trans_single b, trans_single c) {
441 trans_single cc = c;
442
443 if (alignment_class == 0) {
444 /*
445 * Translational transformations
446 */
447
448 ale_pos t0 = -a.eu_get(0) + b.eu_get(0);
449 ale_pos t1 = -a.eu_get(1) + b.eu_get(1);
450
451 cc.eu_modify(0, t0);
452 cc.eu_modify(1, t1);
453
454 } else if (alignment_class == 1) {
455 /*
456 * Euclidean transformations
457 */
458
459 ale_pos t2 = -a.eu_get(2) + b.eu_get(2);
460
461 cc.eu_modify(2, t2);
462
463 point p( c.scaled_height()/2 + c.eu_get(0) - a.eu_get(0),
464 c.scaled_width()/2 + c.eu_get(1) - a.eu_get(1) );
465
466 p = b.transform_scaled(p);
467
468 cc.eu_modify(0, p[0] - c.scaled_height()/2 - c.eu_get(0));
469 cc.eu_modify(1, p[1] - c.scaled_width()/2 - c.eu_get(1));
470
471 } else if (alignment_class == 2) {
472 /*
473 * Projective transformations
474 */
475
476 point p[4];
477
478 p[0] = b.transform_scaled(a
479 . scaled_inverse_transform(c.transform_scaled(point( 0 , 0 ))));
480 p[1] = b.transform_scaled(a
481 . scaled_inverse_transform(c.transform_scaled(point(c.scaled_height(), 0 ))));
482 p[2] = b.transform_scaled(a
483 . scaled_inverse_transform(c.transform_scaled(point(c.scaled_height(), c.scaled_width()))));
484 p[3] = b.transform_scaled(a
485 . scaled_inverse_transform(c.transform_scaled(point( 0 , c.scaled_width()))));
486
487 cc.gpt_set(p);
488 }
489
490 return cc;
491 }
492
493 /*
494 * For multi-alignment following, we use the following approach, not
495 * guaranteed to work with large changes in scene or perspective, but
496 * which should be somewhat flexible:
497 *
498 * For
499 *
500 * t[][] calculated final alignments
501 * s[][] alignments as loaded from file
502 * previous frame n
503 * current frame n+1
504 * fundamental (primary) 0
505 * non-fundamental (non-primary) m!=0
506 * parent element m'
507 * follow(a, b, c) applying the (a, b) delta T=b(a^-1) to c
508 *
509 * following in the case of missing file data might be generated by
510 *
511 * t[n+1][0] = t[n][0]
512 * t[n+1][m!=0] = follow(t[n][m'], t[n+1][m'], t[n][m])
513 *
514 * cases with all noted file data present might be generated by
515 *
516 * t[n+1][0] = follow(s[n][0], t[n][0], s[n+1][0])
517 * t[n+1][m!=0] = follow(s[n+1][m'], t[n+1][m'], s[n+1][m])
518 *
519 * For non-following behavior, or where assigning the above is
520 * impossible, we assign the following default
521 *
522 * t[n+1][0] = Identity
523 * t[n+1][m!=0] = t[n+1][m']
524 */
525
526 void init_frame_alignment_primary(transformation *offset, int lod, ale_pos perturb) {
527
528 if (perturb > 0 && !old_is_default && !get_is_default(0)
529 && default_initial_alignment_type == 1) {
530
531 /*
532 * Apply following logic for the primary element.
533 */
534
535 ui::get()->following();
536
537 trans_single new_offset = follow(old_initial_alignment.get_element(0),
538 old_final_alignment.get_element(0),
539 offset->get_element(0));
540
541 old_initial_alignment = *offset;
542
543 offset->set_element(0, new_offset);
544
545 ui::get()->set_offset(new_offset);
546 } else {
547 old_initial_alignment = *offset;
548 }
549
550 is_default.resize(old_initial_alignment.stack_depth());
551 }
552
553 void init_frame_alignment_nonprimary(transformation *offset,
554 int lod, ale_pos perturb, unsigned int index) {
555
556 assert (index > 0);
557
558 unsigned int parent_index = offset->parent_index(index);
559
560 if (perturb > 0
561 && !get_is_default(parent_index)
562 && !get_is_default(index)
563 && default_initial_alignment_type == 1) {
564
565 /*
566 * Apply file-based following logic for the
567 * given element.
568 */
569
570 ui::get()->following();
571
572 trans_single new_offset = follow(old_initial_alignment.get_element(parent_index),
573 offset->get_element(parent_index),
574 offset->get_element(index));
575
576 old_initial_alignment.set_element(index, offset->get_element(index));
577 offset->set_element(index, new_offset);
578
579 ui::get()->set_offset(new_offset);
580
581 return;
582 }
583
584 offset->get_coordinate(parent_index);
585
586
587 if (perturb > 0
588 && old_final_alignment.exists(offset->get_coordinate(parent_index))
589 && old_final_alignment.exists(offset->get_current_coordinate())
590 && default_initial_alignment_type == 1) {
591
592 /*
593 * Apply nonfile-based following logic for
594 * the given element.
595 */
596
597 ui::get()->following();
598
599 /*
600 * XXX: Although it is different, the below
601 * should be equivalent to the comment
602 * description.
603 */
604
605 trans_single a = old_final_alignment.get_element(offset->get_coordinate(parent_index));
606 trans_single b = old_final_alignment.get_element(offset->get_current_coordinate());
607 trans_single c = offset->get_element(parent_index);
608
609 trans_single new_offset = follow(a, b, c);
610
611 offset->set_element(index, new_offset);
612 ui::get()->set_offset(new_offset);
613
614 return;
615 }
616
617 /*
618 * Handle other cases.
619 */
620
621 if (get_is_default(index)) {
622 offset->set_element(index, offset->get_element(parent_index));
623 ui::get()->set_offset(offset->get_element(index));
624 }
625 }
626
627 void init_default() {
628
629 if (default_initial_alignment_type == 0) {
630
631 /*
632 * Follow the transformation of the original frame,
633 * setting new image dimensions.
634 */
635
636 // astate->default_initial_alignment = orig_t;
637 default_initial_alignment.set_current_element(orig_t.get_element(0));
638 default_initial_alignment.set_dimensions(input_frame);
639
640 } else if (default_initial_alignment_type == 1)
641
642 /*
643 * Follow previous transformation, setting new image
644 * dimensions.
645 */
646
647 default_initial_alignment.set_dimensions(input_frame);
648
649 else
650 assert(0);
651
652 old_is_default = get_is_default(0);
653 }
654 };
655
656
657 /*
773018a3 David Hilvert2007-09-07 15:14:00 +0000658 * Types for scale clusters.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000659 */
660
773018a3
DH
David Hilvert2007-09-07 15:14:00 +0000661 struct nl_scale_cluster {
662 const image *accum_max;
663 const image *accum_min;
580b5321
DH
David Hilvert2007-09-10 17:35:00 +0000664 const image *certainty_max;
665 const image *certainty_min;
773018a3
DH
David Hilvert2007-09-07 15:14:00 +0000666 const image *aweight_max;
667 const image *aweight_min;
668 exclusion *ax_parameters;
669
670 ale_pos input_scale;
e7f30dec
DH
David Hilvert2007-09-21 19:25:00 +0000671 const image *input_certainty_max;
672 const image *input_certainty_min;
773018a3
DH
David Hilvert2007-09-07 15:14:00 +0000673 const image *input_max;
674 const image *input_min;
675 };
676
2aa417e6 dhilvert2005-01-07 06:44:00 +0000677 struct scale_cluster {
678 const image *accum;
580b5321 David Hilvert2007-09-10 17:35:00 +0000679 const image *certainty;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000680 const image *aweight;
df55d1a2 dhilvert2006-08-30 07:40:00 +0000681 exclusion *ax_parameters;
07271611 dhilvert2005-01-07 06:48:00 +0000682
683 ale_pos input_scale;
e7f30dec David Hilvert2007-09-21 19:25:00 +0000684 const image *input_certainty;
07271611 dhilvert2005-01-07 06:48:00 +0000685 const image *input;
46cc7d96
DH
David Hilvert2007-09-07 17:18:00 +0000686
687 nl_scale_cluster *nl_scale_clusters;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000688 };
689
690 /*
df55d1a2 dhilvert2006-08-30 07:40:00 +0000691 * Check for exclusion region coverage in the reference
692 * array.
693 */
694 static int ref_excluded(int i, int j, point offset, exclusion *params, int param_count) {
695 for (int idx = 0; idx < param_count; idx++)
696 if (params[idx].type == exclusion::RENDER
697 && i + offset[0] >= params[idx].x[0]
698 && i + offset[0] <= params[idx].x[1]
699 && j + offset[1] >= params[idx].x[2]
700 && j + offset[1] <= params[idx].x[3])
701 return 1;
702
703 return 0;
704 }
705
706 /*
707 * Check for exclusion region coverage in the input
708 * array.
709 */
710 static int input_excluded(ale_pos ti, ale_pos tj, exclusion *params, int param_count) {
711 for (int idx = 0; idx < param_count; idx++)
712 if (params[idx].type == exclusion::FRAME
713 && ti >= params[idx].x[0]
714 && ti <= params[idx].x[1]
715 && tj >= params[idx].x[2]
716 && tj <= params[idx].x[3])
717 return 1;
718
719 return 0;
720 }
721
722 /*
4949c031 dhilvert2005-01-07 06:44:00 +0000723 * Overlap function. Determines the number of pixels in areas where
724 * the arrays overlap. Uses the reference array's notion of pixel
725 * positions.
726 */
727 static unsigned int overlap(struct scale_cluster c, transformation t, int ax_count) {
728 assert (reference_image);
729
730 unsigned int result = 0;
731
732 point offset = c.accum->offset();
733
734 for (unsigned int i = 0; i < c.accum->height(); i++)
735 for (unsigned int j = 0; j < c.accum->width(); j++) {
736
df55d1a2 dhilvert2006-08-30 07:40:00 +0000737 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
4949c031 dhilvert2005-01-07 06:44:00 +0000738 continue;
739
740 /*
741 * Transform
742 */
743
744 struct point q;
745
07271611 dhilvert2005-01-07 06:48:00 +0000746 q = (c.input_scale < 1.0 && interpolant == NULL)
747 ? t.scaled_inverse_transform(
748 point(i + offset[0], j + offset[1]))
749 : t.unscaled_inverse_transform(
4949c031 dhilvert2005-01-07 06:44:00 +0000750 point(i + offset[0], j + offset[1]));
751
752 ale_pos ti = q[0];
753 ale_pos tj = q[1];
754
755 /*
756 * Check that the transformed coordinates are within
757 * the boundaries of array c.input, and check that the
758 * weight value in the accumulated array is nonzero,
759 * unless we know it is nonzero by virtue of the fact
760 * that it falls within the region of the original
761 * frame (e.g. when we're not increasing image
df55d1a2 dhilvert2006-08-30 07:40:00 +0000762 * extents). Also check for frame exclusion.
4949c031 dhilvert2005-01-07 06:44:00 +0000763 */
764
df55d1a2 dhilvert2006-08-30 07:40:00 +0000765 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
766 continue;
767
4949c031 dhilvert2005-01-07 06:44:00 +0000768 if (ti >= 0
769 && ti <= c.input->height() - 1
770 && tj >= 0
771 && tj <= c.input->width() - 1
580b5321 David Hilvert2007-09-10 17:35:00 +0000772 && c.certainty->get_pixel(i, j)[0] != 0)
4949c031 dhilvert2005-01-07 06:44:00 +0000773 result++;
774 }
775
776 return result;
777 }
778
779 /*
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000780 * Monte carlo iteration class.
781 *
782 * Monte Carlo alignment has been used for statistical comparisons in
783 * spatial registration, and is now used for tonal registration
784 * and final match calculation.
785 */
786
787 /*
788 * We use a random process for which the expected number of sampled
789 * pixels is +/- .000003 from the coverage in the range [.005,.995] for
790 * an image with 100,000 pixels. (The actual number may still deviate
791 * from the expected number by more than this amount, however.) The
792 * method is as follows:
793 *
794 * We have coverage == USE/ALL, or (expected # pixels to use)/(# total
795 * pixels). We derive from this SKIP/USE.
796 *
797 * SKIP/USE == (SKIP/ALL)/(USE/ALL) == (1 - (USE/ALL))/(USE/ALL)
798 *
799 * Once we have SKIP/USE, we know the expected number of pixels to skip
800 * in each iteration. We use a random selection process that provides
801 * SKIP/USE close to this calculated value.
802 *
803 * If we can draw uniformly to select the number of pixels to skip, we
804 * do. In this case, the maximum number of pixels to skip is twice the
805 * expected number.
806 *
807 * If we cannot draw uniformly, we still assign equal probability to
808 * each of the integer values in the interval [0, 2 * (SKIP/USE)], but
809 * assign an unequal amount to the integer value ceil(2 * SKIP/USE) +
810 * 1.
811 */
812
813 /*
814 * When reseeding the random number generator, we want the same set of
815 * pixels to be used in cases where two alignment options are compared.
816 * If we wanted to avoid bias from repeatedly utilizing the same seed,
817 * we could seed with the number of the frame most recently aligned:
818 *
819 * srand(latest);
820 *
821 * However, in cursory tests, it seems okay to just use the default
822 * seed of 1, and so we do this, since it is simpler; both of these
823 * approaches to reseeding achieve better results than not reseeding.
824 * (1 is the default seed according to the GNU Manual Page for
825 * rand(3).)
826 *
827 * For subdomain calculations, we vary the seed by adding the subdomain
828 * index.
829 */
830
831 class mc_iterate {
832 ale_pos mc_max;
833 unsigned int index;
834 unsigned int index_max;
835 int i_min;
836 int i_max;
837 int j_min;
838 int j_max;
839
840 rng_t rng;
841
63f46ff7 David Hilvert2007-09-21 00:03:00 +0000842 public:
f0af1fea
DH
David Hilvert2007-09-20 23:22:00 +0000843 mc_iterate(int _i_min, int _i_max, int _j_min, int _j_max, unsigned int subdomain)
844 : rng() {
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000845
846 ale_pos coverage;
847
848 i_min = _i_min;
849 i_max = _i_max;
850 j_min = _j_min;
851 j_max = _j_max;
852
a0c28c9a
DH
David Hilvert2008-03-23 15:55:54 -0500853 if (i_max < i_min || j_max < j_min)
854 index_max = 0;
855 else
856 index_max = (i_max - i_min) * (j_max - j_min);
699711e2 David Hilvert2007-09-20 21:03:00 +0000857
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000858 if (index_max < 500 || _mc > 100 || _mc <= 0)
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000859 coverage = 1;
860 else
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000861 coverage = _mc / 100;
699711e2 David Hilvert2007-09-20 21:03:00 +0000862
a85f57f9 David Hilvert2007-10-15 17:07:00 +0000863 double su = (1 - coverage) / coverage;
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000864
865 mc_max = (floor(2*su) * (1 + floor(2*su)) + 2*su)
866 / (2 + 2 * floor(2*su) - 2*su);
867
868 rng.seed(1 + subdomain);
869
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000870#define FIXED16 3
871#if ALE_COORDINATES == FIXED16
872 /*
873 * XXX: This calculation might not yield the correct
874 * expected value.
875 */
e4a3555e
DH
David Hilvert2007-10-24 22:37:00 +0000876 index = -1 + (int) ceil(((ale_pos) mc_max+1)
877 / (ale_pos) ( (1 + 0xffffff)
878 / (1 + (rng.get() & 0xffffff))));
793fc1a6 David Hilvert2007-10-25 16:36:00 +0000879#else
ff364936 David Hilvert2007-10-26 23:35:00 +0000880 index = -1 + (int) ceil((ale_accum) (mc_max+1)
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000881 * ( (1 + ((ale_accum) (rng.get())) )
882 / (1 + ((ale_accum) RAND_MAX)) ));
883#endif
884#undef FIXED16
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000885 }
886
887 int get_i() {
888 return index / (j_max - j_min) + i_min;
889 }
890
891 int get_j() {
892 return index % (j_max - j_min) + j_min;
893 }
894
63f46ff7 David Hilvert2007-09-21 00:03:00 +0000895 void operator++(int whats_this_for) {
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000896#define FIXED16 3
897#if ALE_COORDINATES == FIXED16
e4a3555e
DH
David Hilvert2007-10-24 22:37:00 +0000898 index += (int) ceil(((ale_pos) mc_max+1)
899 / (ale_pos) ( (1 + 0xffffff)
900 / (1 + (rng.get() & 0xffffff))));
793fc1a6 David Hilvert2007-10-25 16:36:00 +0000901#else
ff364936 David Hilvert2007-10-26 23:35:00 +0000902 index += (int) ceil((ale_accum) (mc_max+1)
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000903 * ( (1 + ((ale_accum) (rng.get())) )
904 / (1 + ((ale_accum) RAND_MAX)) ));
905#endif
906#undef FIXED16
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000907 }
908
909 int done() {
910 return (index >= index_max);
911 }
912 };
913
914 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000915 * Not-quite-symmetric difference function. Determines the difference in areas
4949c031 dhilvert2005-01-07 06:44:00 +0000916 * where the arrays overlap. Uses the reference array's notion of pixel positions.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000917 *
918 * For the purposes of determining the difference, this function divides each
919 * pixel value by the corresponding image's average pixel magnitude, unless we
920 * are:
921 *
922 * a) Extending the boundaries of the image, or
923 *
924 * b) following the previous frame's transform
925 *
926 * If we are doing monte-carlo pixel sampling for alignment, we
927 * typically sample a subset of available pixels; otherwise, we sample
928 * all pixels.
929 *
930 */
4707675e dhilvert2006-10-19 10:24:00 +0000931
f8864302
DH
David Hilvert2008-04-11 18:15:57 +0000932 template<class diff_trans>
933 class diff_stat_generic {
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000934
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000935 transformation::elem_bounds_t elem_bounds;
e492922d David Hilvert2007-05-09 05:53:00 +0000936
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000937 struct run {
938
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000939 diff_trans offset;
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000940
941 ale_accum result;
942 ale_accum divisor;
943
944 point max, min;
945 ale_accum centroid[2], centroid_divisor;
946 ale_accum de_centroid[2], de_centroid_v, de_sum;
947
5d53e401 David Hilvert2007-05-02 03:12:00 +0000948 void init() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000949
950 result = 0;
951 divisor = 0;
e492922d David Hilvert2007-05-09 05:53:00 +0000952
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000953 min = point::posinf();
954 max = point::neginf();
955
956 centroid[0] = 0;
957 centroid[1] = 0;
958 centroid_divisor = 0;
959
960 de_centroid[0] = 0;
961 de_centroid[1] = 0;
962
963 de_centroid_v = 0;
964
965 de_sum = 0;
966 }
967
1b980378 David Hilvert2008-07-18 18:30:40 +0000968 void init(diff_trans _offset) {
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +0000969 offset = _offset;
970 init();
971 }
972
973 /*
974 * Required for STL sanity.
975 */
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000976 run() : offset(diff_trans::eu_identity()) {
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +0000977 init();
978 }
979
1b980378
DH
David Hilvert2008-07-18 18:30:40 +0000980 run(diff_trans _offset) : offset(_offset) {
981 init(_offset);
e492922d
DH
David Hilvert2007-05-09 05:53:00 +0000982 }
983
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000984 void add(const run &_run) {
985 result += _run.result;
986 divisor += _run.divisor;
987
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000988 for (int d = 0; d < 2; d++) {
989 if (min[d] > _run.min[d])
990 min[d] = _run.min[d];
991 if (max[d] < _run.max[d])
992 max[d] = _run.max[d];
993 centroid[d] += _run.centroid[d];
994 de_centroid[d] += _run.de_centroid[d];
995 }
996
997 centroid_divisor += _run.centroid_divisor;
998 de_centroid_v += _run.de_centroid_v;
999 de_sum += _run.de_sum;
1000 }
1001
283c3ecc David Hilvert2008-01-26 01:36:00 +00001002 run(const run &_run) : offset(_run.offset) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001003
1004 /*
1005 * Initialize
1006 */
1b980378 David Hilvert2008-07-18 18:30:40 +00001007 init(_run.offset);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001008
1009 /*
1010 * Add
1011 */
1012 add(_run);
1013 }
1014
1015 run &operator=(const run &_run) {
1016
1017 /*
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001018 * Initialize
1019 */
1b980378 David Hilvert2008-07-18 18:30:40 +00001020 init(_run.offset);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001021
1022 /*
1023 * Add
1024 */
1025 add(_run);
1026
1027 return *this;
1028 }
1029
1030 ~run() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001031 }
1032
1033 ale_accum get_error() const {
c9968081 David Hilvert2007-10-24 02:54:00 +00001034 return pow(result / divisor, 1/(ale_accum) metric_exponent);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001035 }
1036
368d214e
DH
David Hilvert2007-05-09 07:57:00 +00001037 void sample(int f, scale_cluster c, int i, int j, point t, point u,
1038 const run &comparison) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001039
1040 pixel pa = c.accum->get_pixel(i, j);
1041
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001042 ale_real this_result[2] = { 0, 0 };
1043 ale_real this_divisor[2] = { 0, 0 };
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001044
f064b1a9
DH
David Hilvert2007-09-21 21:21:00 +00001045 pixel p[2];
1046 pixel weight[2];
1047 weight[0] = pixel(1, 1, 1);
1048 weight[1] = pixel(1, 1, 1);
1049
ca7acd56 David Hilvert2008-06-05 23:43:51 +00001050 pixel tm = offset.get_tonal_multiplier(point(i, j) + c.accum->offset());
28e6b6f7 David Hilvert2008-06-05 02:36:34 +00001051
1e559234 David Hilvert2007-09-11 19:34:00 +00001052 if (interpolant != NULL) {
4132897c
DH
David Hilvert2007-10-26 18:13:00 +00001053 interpolant->filtered(i, j, &p[0], &weight[0], 1, f);
1054
fa3844c7 David Hilvert2007-10-26 18:39:00 +00001055 if (weight[0].min_norm() > ale_real_weight_floor) {
4132897c
DH
David Hilvert2007-10-26 18:13:00 +00001056 p[0] /= weight[0];
1057 } else {
1058 return;
1059 }
1060
1e559234 David Hilvert2007-09-11 19:34:00 +00001061 } else {
e7f30dec David Hilvert2007-09-21 19:25:00 +00001062 p[0] = c.input->get_bl(t);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001063 }
1064
28e6b6f7 David Hilvert2008-06-05 02:36:34 +00001065 p[0] *= tm;
64e05da1 David Hilvert2008-05-05 16:21:18 -05001066
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001067 if (u.defined()) {
19b07c65 David Hilvert2007-09-11 18:07:00 +00001068 p[1] = c.input->get_bl(u);
28e6b6f7 David Hilvert2008-06-05 02:36:34 +00001069 p[1] *= tm;
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001070 }
1071
1072
1073 /*
1074 * Handle certainty.
1075 */
1076
f064b1a9 David Hilvert2007-09-21 21:21:00 +00001077 if (certainty_weights == 1) {
32ec9768
DH
David Hilvert2007-09-21 23:14:00 +00001078
1079 /*
1080 * For speed, use arithmetic interpolation (get_bl(.))
1081 * instead of geometric (get_bl(., 1))
1082 */
1083
1084 weight[0] *= c.input_certainty->get_bl(t);
c4fb894c David Hilvert2007-09-21 22:44:00 +00001085 if (u.defined())
32ec9768 David Hilvert2007-09-21 23:14:00 +00001086 weight[1] *= c.input_certainty->get_bl(u);
e7f30dec
DH
David Hilvert2007-09-21 19:25:00 +00001087 weight[0] *= c.certainty->get_pixel(i, j);
1088 weight[1] *= c.certainty->get_pixel(i, j);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001089 }
1090
1091 if (c.aweight != NULL) {
1092 weight[0] *= c.aweight->get_pixel(i, j);
1093 weight[1] *= c.aweight->get_pixel(i, j);
1094 }
1095
1096 /*
1097 * Update sampling area statistics
1098 */
1099
1100 if (min[0] > i)
1101 min[0] = i;
1102 if (min[1] > j)
1103 min[1] = j;
1104 if (max[0] < i)
1105 max[0] = i;
1106 if (max[1] < j)
1107 max[1] = j;
1108
1109 centroid[0] += (weight[0][0] + weight[0][1] + weight[0][2]) * i;
1110 centroid[1] += (weight[0][0] + weight[0][1] + weight[0][2]) * j;
1111 centroid_divisor += (weight[0][0] + weight[0][1] + weight[0][2]);
1112
1113 /*
1114 * Determine alignment type.
1115 */
1116
1117 for (int m = 0; m < (u.defined() ? 2 : 1); m++)
1118 if (channel_alignment_type == 0) {
1119 /*
1120 * Align based on all channels.
1121 */
1122
1123
1124 for (int k = 0; k < 3; k++) {
1125 ale_real achan = pa[k];
1126 ale_real bchan = p[m][k];
1127
1128 this_result[m] += weight[m][k] * pow(fabs(achan - bchan), metric_exponent);
1129 this_divisor[m] += weight[m][k] * pow(achan > bchan ? achan : bchan, metric_exponent);
1130 }
1131 } else if (channel_alignment_type == 1) {
1132 /*
1133 * Align based on the green channel.
1134 */
1135
1136 ale_real achan = pa[1];
1137 ale_real bchan = p[m][1];
1138
1139 this_result[m] = weight[m][1] * pow(fabs(achan - bchan), metric_exponent);
1140 this_divisor[m] = weight[m][1] * pow(achan > bchan ? achan : bchan, metric_exponent);
1141 } else if (channel_alignment_type == 2) {
1142 /*
1143 * Align based on the sum of all channels.
1144 */
1145
1146 ale_real asum = 0;
1147 ale_real bsum = 0;
1148 ale_real wsum = 0;
1149
1150 for (int k = 0; k < 3; k++) {
1151 asum += pa[k];
1152 bsum += p[m][k];
1153 wsum += weight[m][k] / 3;
1154 }
1155
1156 this_result[m] = wsum * pow(fabs(asum - bsum), metric_exponent);
1157 this_divisor[m] = wsum * pow(asum > bsum ? asum : bsum, metric_exponent);
1158 }
1159
1160 if (u.defined()) {
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001161// ale_real de = fabs(this_result[0] / this_divisor[0]
1162// - this_result[1] / this_divisor[1]);
1163 ale_real de = fabs(this_result[0] - this_result[1]);
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001164
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001165 de_centroid[0] += de * (ale_real) i;
1166 de_centroid[1] += de * (ale_real) j;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001167
42772195 David Hilvert2007-10-21 15:36:00 +00001168 de_centroid_v += de * (ale_real) t.lengthto(u);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001169
1170 de_sum += de;
1171 }
1172
1173 result += (this_result[0]);
1174 divisor += (this_divisor[0]);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001175 }
1176
1177 void rescale(ale_pos scale) {
1178 offset.rescale(scale);
1179
1180 de_centroid[0] *= scale;
1181 de_centroid[1] *= scale;
1182 de_centroid_v *= scale;
1183 }
1184
1185 point get_centroid() {
1186 point result = point(centroid[0] / centroid_divisor, centroid[1] / centroid_divisor);
1187
1188 assert (finite(centroid[0])
1189 && finite(centroid[1])
1190 && (result.defined() || centroid_divisor == 0));
1191
1192 return result;
1193 }
1194
1195 point get_error_centroid() {
1196 point result = point(de_centroid[0] / de_sum, de_centroid[1] / de_sum);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001197 return result;
1198 }
1199
1200
1201 ale_pos get_error_perturb() {
1202 ale_pos result = de_centroid_v / de_sum;
1203
1204 return result;
1205 }
1206
1207 };
1208
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001209 /*
1210 * When non-empty, runs.front() is best, runs.back() is
1211 * testing.
1212 */
1213
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001214 std::vector<run> runs;
1215
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001216 /*
1217 * old_runs stores the latest available perturbation set for
1218 * each multi-alignment element.
1219 */
1220
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001221 typedef int run_index;
30ea890d David Hilvert2007-05-14 20:54:00 +00001222 std::map<run_index, run> old_runs;
5d53e401 David Hilvert2007-05-02 03:12:00 +00001223
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001224 static void *diff_subdomain(void *args);
1225
1226 struct subdomain_args {
1227 struct scale_cluster c;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001228 std::vector<run> runs;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001229 int ax_count;
1230 int f;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001231 int i_min, i_max, j_min, j_max;
1232 int subdomain;
1233 };
1234
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001235 struct scale_cluster si;
1236 int ax_count;
1237 int frame;
1238
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001239 std::vector<ale_pos> perturb_multipliers;
1240
30ea890d David Hilvert2007-05-14 20:54:00 +00001241public:
1b980378 David Hilvert2008-07-18 18:30:40 +00001242 void diff(struct scale_cluster c, const diff_trans &t,
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001243 int _ax_count, int f) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001244
1245 if (runs.size() == 2)
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001246 runs.pop_back();
1247
1b980378 David Hilvert2008-07-18 18:30:40 +00001248 runs.push_back(run(t));
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001249
1250 si = c;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001251 ax_count = _ax_count;
1252 frame = f;
1253
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001254 ui::get()->d2_align_sample_start();
1255
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001256 if (interpolant != NULL) {
1257
1258 /*
1259 * XXX: This has not been tested, and may be completely
1260 * wrong.
1261 */
1262
1263 transformation tt = transformation::eu_identity();
1264 tt.set_current_element(t);
1265 interpolant->set_parameters(tt, c.input, c.accum->offset());
1266 }
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001267
1268 int N;
1269#ifdef USE_PTHREAD
1270 N = thread::count();
1271
1272 pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t) * N);
1273 pthread_attr_t *thread_attr = (pthread_attr_t *) malloc(sizeof(pthread_attr_t) * N);
1274
1275#else
1276 N = 1;
1277#endif
1278
1279 subdomain_args *args = new subdomain_args[N];
1280
d790f7da David Hilvert2008-05-02 18:59:43 -05001281 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 +00001282
a7ee2759
DH
David Hilvert2008-03-17 17:05:06 -05001283// fprintf(stdout, "[%d %d] [%d %d]\n",
1284// global_i_min, global_i_max, global_j_min, global_j_max);
e55e5de1 David Hilvert2008-02-14 01:08:00 +00001285
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001286 for (int ti = 0; ti < N; ti++) {
1287 args[ti].c = c;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001288 args[ti].runs = runs;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001289 args[ti].ax_count = ax_count;
1290 args[ti].f = f;
d790f7da
DH
David Hilvert2008-05-02 18:59:43 -05001291 args[ti].i_min = b.imin + ((b.imax - b.imin) * ti) / N;
1292 args[ti].i_max = b.imin + ((b.imax - b.imin) * (ti + 1)) / N;
1293 args[ti].j_min = b.jmin;
1294 args[ti].j_max = b.jmax;
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001295 args[ti].subdomain = ti;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001296#ifdef USE_PTHREAD
1297 pthread_attr_init(&thread_attr[ti]);
1298 pthread_attr_setdetachstate(&thread_attr[ti], PTHREAD_CREATE_JOINABLE);
1299 pthread_create(&threads[ti], &thread_attr[ti], diff_subdomain, &args[ti]);
1300#else
1301 diff_subdomain(&args[ti]);
1302#endif
1303 }
1304
1305 for (int ti = 0; ti < N; ti++) {
1306#ifdef USE_PTHREAD
1307 pthread_join(threads[ti], NULL);
1308#endif
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001309 runs.back().add(args[ti].runs.back());
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001310 }
1311
44a1d1de
DH
David Hilvert2009-03-30 19:02:57 +00001312#ifdef USE_PTHREAD
1313 free(threads);
1314 free(thread_attr);
1315#endif
1316
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001317 delete[] args;
1318
1319 ui::get()->d2_align_sample_stop();
1320
1321 }
1322
1323 private:
1324 void rediff() {
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001325 std::vector<diff_trans> t_array;
b971d971 David Hilvert2006-12-26 05:25:00 +00001326
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001327 for (unsigned int r = 0; r < runs.size(); r++) {
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001328 t_array.push_back(runs[r].offset);
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001329 }
b971d971 David Hilvert2006-12-26 05:25:00 +00001330
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001331 runs.clear();
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001332
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001333 for (unsigned int r = 0; r < t_array.size(); r++)
1b980378 David Hilvert2008-07-18 18:30:40 +00001334 diff(si, t_array[r], ax_count, frame);
86c0d2ba dhilvert2006-10-25 14:42:00 +00001335 }
1336
400c7826 David Hilvert2007-04-20 07:06:00 +00001337
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001338 public:
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001339 int better() {
1340 assert(runs.size() >= 2);
1341 assert(runs[0].offset.scale() == runs[1].offset.scale());
86c0d2ba dhilvert2006-10-25 14:42:00 +00001342
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001343 return (runs[1].get_error() < runs[0].get_error()
1344 || (!finite(runs[0].get_error()) && finite(runs[1].get_error())));
08151f52 dhilvert2006-10-25 17:36:00 +00001345 }
1346
e0577945
DH
David Hilvert2008-07-19 22:11:55 +00001347 int better_defined() {
1348 assert(runs.size() >= 2);
1349 assert(runs[0].offset.scale() == runs[1].offset.scale());
1350
1351 return (runs[1].get_error() < runs[0].get_error());
1352 }
1353
f8864302 David Hilvert2008-04-11 18:15:57 +00001354 diff_stat_generic(transformation::elem_bounds_t e)
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001355 : runs(), old_runs(), perturb_multipliers() {
1356 elem_bounds = e;
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001357 }
1358
1359 run_index get_run_index(unsigned int perturb_index) {
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001360 return perturb_index;
30ea890d David Hilvert2007-05-14 20:54:00 +00001361 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001362
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001363 run &get_run(unsigned int perturb_index) {
1364 run_index index = get_run_index(perturb_index);
dc426169 David Hilvert2007-04-25 06:50:00 +00001365
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001366 assert(old_runs.count(index));
1367 return old_runs[index];
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001368 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001369
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001370 void rescale(ale_pos scale, scale_cluster _si) {
1371 assert(runs.size() == 1);
86c0d2ba dhilvert2006-10-25 14:42:00 +00001372
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001373 si = _si;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001374
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001375 runs[0].rescale(scale);
1376
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001377 rediff();
1378 }
1379
f8864302 David Hilvert2008-04-11 18:15:57 +00001380 ~diff_stat_generic() {
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001381 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001382
f8864302 David Hilvert2008-04-11 18:15:57 +00001383 diff_stat_generic &operator=(const diff_stat_generic &dst) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001384 /*
1385 * Copy run information.
1386 */
1387 runs = dst.runs;
82db7fe6 David Hilvert2007-05-05 18:29:00 +00001388 old_runs = dst.old_runs;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001389
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001390 /*
1391 * Copy diff variables
1392 */
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001393 si = dst.si;
1394 ax_count = dst.ax_count;
1395 frame = dst.frame;
50a9f51d David Hilvert2007-05-03 05:16:00 +00001396 perturb_multipliers = dst.perturb_multipliers;
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001397 elem_bounds = dst.elem_bounds;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001398
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001399 return *this;
1400 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001401
f8864302 David Hilvert2008-04-11 18:15:57 +00001402 diff_stat_generic(const diff_stat_generic &dst) : runs(), old_runs(),
ca7b6c30 David Hilvert2007-05-06 02:42:00 +00001403 perturb_multipliers() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001404 operator=(dst);
1405 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001406
1ed23c0d
DH
David Hilvert2008-03-09 11:23:00 +00001407 void set_elem_bounds(transformation::elem_bounds_t e) {
1408 elem_bounds = e;
1409 }
1410
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001411 ale_accum get_result() {
1412 assert(runs.size() == 1);
1413 return runs[0].result;
1414 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001415
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001416 ale_accum get_divisor() {
1417 assert(runs.size() == 1);
1418 return runs[0].divisor;
1419 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001420
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001421 diff_trans get_offset() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001422 assert(runs.size() == 1);
1423 return runs[0].offset;
1424 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001425
f8864302 David Hilvert2008-04-11 18:15:57 +00001426 int operator!=(diff_stat_generic &param) {
65886ff7 David Hilvert2007-09-04 02:10:00 +00001427 return (get_error() != param.get_error());
86c0d2ba dhilvert2006-10-25 14:42:00 +00001428 }
08151f52 dhilvert2006-10-25 17:36:00 +00001429
f8864302 David Hilvert2008-04-11 18:15:57 +00001430 int operator==(diff_stat_generic &param) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001431 return !(operator!=(param));
1432 }
08151f52 dhilvert2006-10-25 17:36:00 +00001433
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001434 ale_pos get_error_perturb() {
1435 assert(runs.size() == 1);
1436 return runs[0].get_error_perturb();
08151f52 dhilvert2006-10-25 17:36:00 +00001437 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001438
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001439 ale_accum get_error() const {
1440 assert(runs.size() == 1);
1441 return runs[0].get_error();
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001442 }
dda1bf79 dhilvert2006-10-22 18:40:00 +00001443
30ea890d David Hilvert2007-05-14 20:54:00 +00001444 public:
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001445 /*
1446 * Get the set of transformations produced by a given perturbation
1447 */
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001448 void get_perturb_set(std::vector<diff_trans> *set,
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001449 ale_pos adj_p, ale_pos adj_o, ale_pos adj_b,
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001450 ale_pos *current_bd, ale_pos *modified_bd,
1451 std::vector<ale_pos> multipliers = std::vector<ale_pos>()) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001452
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001453 assert(runs.size() == 1);
dda1bf79 dhilvert2006-10-22 18:40:00 +00001454
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001455 diff_trans test_t(diff_trans::eu_identity());
dda1bf79 dhilvert2006-10-22 18:40:00 +00001456
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001457 /*
1458 * Translational or euclidean transformation
1459 */
2aa417e6 dhilvert2005-01-07 06:44:00 +00001460
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001461 for (unsigned int i = 0; i < 2; i++)
1462 for (unsigned int s = 0; s < 2; s++) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001463
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001464 if (!multipliers.size())
1465 multipliers.push_back(1);
dc426169 David Hilvert2007-04-25 06:50:00 +00001466
b2e7131e David Hilvert2007-05-02 08:35:00 +00001467 assert(finite(multipliers[0]));
5d53e401 David Hilvert2007-05-02 03:12:00 +00001468
b2e7131e David Hilvert2007-05-02 08:35:00 +00001469 test_t = get_offset();
dc426169 David Hilvert2007-04-25 06:50:00 +00001470
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001471 // test_t.eu_modify(i, (s ? -adj_p : adj_p) * multipliers[0]);
1472 test_t.translate((i ? point(1, 0) : point(0, 1))
1473 * (s ? -adj_p : adj_p)
1474 * multipliers[0]);
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001475
1476 test_t.snap(adj_p / 2);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001477
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001478 set->push_back(test_t);
1479 multipliers.erase(multipliers.begin());
46f9776a dhilvert2005-01-07 06:44:00 +00001480
b2e7131e David Hilvert2007-05-02 08:35:00 +00001481 }
4707675e dhilvert2006-10-19 10:24:00 +00001482
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001483 if (alignment_class > 0)
1484 for (unsigned int s = 0; s < 2; s++) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001485
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001486 if (!multipliers.size())
1487 multipliers.push_back(1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001488
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001489 assert(multipliers.size());
1490 assert(finite(multipliers[0]));
5d53e401 David Hilvert2007-05-02 03:12:00 +00001491
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001492 if (!(adj_o * multipliers[0] < rot_max))
1493 return;
4707675e dhilvert2006-10-19 10:24:00 +00001494
b2e7131e David Hilvert2007-05-02 08:35:00 +00001495 ale_pos adj_s = (s ? 1 : -1) * adj_o * multipliers[0];
5d53e401 David Hilvert2007-05-02 03:12:00 +00001496
b2e7131e David Hilvert2007-05-02 08:35:00 +00001497 test_t = get_offset();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001498
30ea890d David Hilvert2007-05-14 20:54:00 +00001499 run_index ori = get_run_index(set->size());
b2e7131e David Hilvert2007-05-02 08:35:00 +00001500 point centroid = point::undefined();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001501
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001502 if (!old_runs.count(ori))
1503 ori = get_run_index(0);
5d53e401 David Hilvert2007-05-02 03:12:00 +00001504
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001505 if (!centroid.finite() && old_runs.count(ori)) {
1506 centroid = old_runs[ori].get_error_centroid();
5d53e401 David Hilvert2007-05-02 03:12:00 +00001507
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001508 if (!centroid.finite())
1509 centroid = old_runs[ori].get_centroid();
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001510
1511 centroid *= test_t.scale()
1512 / old_runs[ori].offset.scale();
b2e7131e David Hilvert2007-05-02 08:35:00 +00001513 }
5d53e401 David Hilvert2007-05-02 03:12:00 +00001514
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001515 if (!centroid.finite() && !test_t.is_projective()) {
1516 test_t.eu_modify(2, adj_s);
1517 } else if (!centroid.finite()) {
1518 centroid = point(si.input->height() / 2,
1519 si.input->width() / 2);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001520
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001521 test_t.rotate(centroid + si.accum->offset(),
1522 adj_s);
1523 } else {
1524 test_t.rotate(centroid + si.accum->offset(),
1525 adj_s);
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001526 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001527
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001528 test_t.snap(adj_p / 2);
1529
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001530 set->push_back(test_t);
1531 multipliers.erase(multipliers.begin());
1532 }
1533
1534 if (alignment_class == 2) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001535
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001536 /*
1537 * Projective transformation
1538 */
30afe4b6 dhilvert2005-01-07 06:42:00 +00001539
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001540 for (unsigned int i = 0; i < 4; i++)
1541 for (unsigned int j = 0; j < 2; j++)
1542 for (unsigned int s = 0; s < 2; s++) {
1543
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001544 if (!multipliers.size())
1545 multipliers.push_back(1);
1546
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001547 assert(multipliers.size());
1548 assert(finite(multipliers[0]));
46f9776a dhilvert2005-01-07 06:44:00 +00001549
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001550 ale_pos adj_s = (s ? -1 : 1) * adj_p * multipliers [0];
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001551
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001552 test_t = get_offset();
46f9776a dhilvert2005-01-07 06:44:00 +00001553
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001554 if (perturb_type == 0)
73f0dc5c David Hilvert2008-08-18 17:37:54 -05001555 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 +00001556 else if (perturb_type == 1)
1557 test_t.gr_modify(j, i, adj_s);
1558 else
1559 assert(0);
dc426169 David Hilvert2007-04-25 06:50:00 +00001560
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001561 test_t.snap(adj_p / 2);
1562
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001563 set->push_back(test_t);
1564 multipliers.erase(multipliers.begin());
1565 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001566
b2e7131e David Hilvert2007-05-02 08:35:00 +00001567 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001568
49a3a0b4 David Hilvert2007-04-01 07:13:00 +00001569 /*
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001570 * Barrel distortion
49a3a0b4
DH
David Hilvert2007-04-01 07:13:00 +00001571 */
1572
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001573 if (bda_mult != 0 && adj_b != 0) {
7a696eb1 David Hilvert2007-04-01 06:41:00 +00001574
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001575 for (unsigned int d = 0; d < get_offset().bd_count(); d++)
1576 for (unsigned int s = 0; s < 2; s++) {
1577
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001578 if (!multipliers.size())
1579 multipliers.push_back(1);
1580
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001581 assert (multipliers.size());
1582 assert (finite(multipliers[0]));
1583
1584 ale_pos adj_s = (s ? -1 : 1) * adj_b * multipliers[0];
1585
1586 if (bda_rate > 0 && fabs(modified_bd[d] + adj_s - current_bd[d]) > bda_rate)
1587 continue;
1588
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001589 diff_trans test_t = get_offset();
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001590
1591 test_t.bd_modify(d, adj_s);
1592
1593 set->push_back(test_t);
1594 }
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001595 }
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001596 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001597
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001598 void confirm() {
1599 assert(runs.size() == 2);
1600 runs[0] = runs[1];
1601 runs.pop_back();
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001602 }
1603
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001604 void discard() {
1605 assert(runs.size() == 2);
1606 runs.pop_back();
1607 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001608
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001609 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 +00001610 ale_pos *current_bd, ale_pos *modified_bd, int stable) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001611
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001612 assert(runs.size() == 1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001613
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001614 std::vector<diff_trans> t_set;
4707675e dhilvert2006-10-19 10:24:00 +00001615
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001616 if (perturb_multipliers.size() == 0) {
1617 get_perturb_set(&t_set, adj_p, adj_o, adj_b,
1618 current_bd, modified_bd);
1619
1620 for (unsigned int i = 0; i < t_set.size(); i++) {
f8864302 David Hilvert2008-04-11 18:15:57 +00001621 diff_stat_generic test = *this;
50a9f51d David Hilvert2007-05-03 05:16:00 +00001622
1b980378 David Hilvert2008-07-18 18:30:40 +00001623 test.diff(si, t_set[i], ax_count, frame);
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001624
1625 test.confirm();
1626
42772195 David Hilvert2007-10-21 15:36:00 +00001627 if (finite(test.get_error_perturb()))
82db7fe6
DH
David Hilvert2007-05-05 18:29:00 +00001628 perturb_multipliers.push_back(adj_p / test.get_error_perturb());
1629 else
1630 perturb_multipliers.push_back(1);
1631
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001632 }
1633
1634 t_set.clear();
1635 }
1636
5d53e401 David Hilvert2007-05-02 03:12:00 +00001637 get_perturb_set(&t_set, adj_p, adj_o, adj_b, current_bd, modified_bd,
50a9f51d David Hilvert2007-05-03 05:16:00 +00001638 perturb_multipliers);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001639
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001640 int found_unreliable = 1;
1641 std::vector<int> tested(t_set.size(), 0);
dc426169 David Hilvert2007-04-25 06:50:00 +00001642
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001643 for (unsigned int i = 0; i < t_set.size(); i++) {
1644 run_index ori = get_run_index(i);
1645
1646 /*
1647 * Check for stability
1648 */
1649 if (stable
1650 && old_runs.count(ori)
1651 && old_runs[ori].offset == t_set[i])
1652 tested[i] = 1;
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001653 }
1654
1655 std::vector<ale_pos> perturb_multipliers_original = perturb_multipliers;
1656
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001657 while (found_unreliable) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001658
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001659 found_unreliable = 0;
08151f52 dhilvert2006-10-25 17:36:00 +00001660
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001661 for (unsigned int i = 0; i < t_set.size(); i++) {
4d806213 dhilvert2006-10-23 17:58:00 +00001662
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001663 if (tested[i])
1664 continue;
b410ef51 dhilvert2006-10-23 15:30:00 +00001665
1b980378 David Hilvert2008-07-18 18:30:40 +00001666 diff(si, t_set[i], ax_count, frame);
7e87bd8e dhilvert2006-10-23 06:39:00 +00001667
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001668 if (!(i < perturb_multipliers.size())
1669 || !finite(perturb_multipliers[i])) {
5d53e401 David Hilvert2007-05-02 03:12:00 +00001670
50a9f51d David Hilvert2007-05-03 05:16:00 +00001671 perturb_multipliers.resize(i + 1);
5d53e401 David Hilvert2007-05-02 03:12:00 +00001672
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001673 if (finite(perturb_multipliers[i])
1674 && finite(adj_p)
1675 && finite(adj_p / runs[1].get_error_perturb())) {
1676 perturb_multipliers[i] =
1677 adj_p / runs[1].get_error_perturb();
5d53e401 David Hilvert2007-05-02 03:12:00 +00001678
8c886617 David Hilvert2007-05-02 08:39:00 +00001679 found_unreliable = 1;
42772195 David Hilvert2007-10-21 15:36:00 +00001680 } else
858b0722 David Hilvert2007-10-03 20:44:00 +00001681 perturb_multipliers[i] = 1;
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001682
1683 continue;
1684 }
1685
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001686 run_index ori = get_run_index(i);
1687
1688 if (old_runs.count(ori) == 0)
1689 old_runs.insert(std::pair<run_index, run>(ori, runs[1]));
1690 else
1691 old_runs[ori] = runs[1];
5d53e401 David Hilvert2007-05-02 03:12:00 +00001692
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001693 if (finite(perturb_multipliers_original[i])
1694 && finite(runs[1].get_error_perturb())
1695 && finite(adj_p)
1696 && finite(perturb_multipliers_original[i] * adj_p / runs[1].get_error_perturb()))
1697 perturb_multipliers[i] = perturb_multipliers_original[i]
1698 * adj_p / runs[1].get_error_perturb();
1699 else
50a9f51d David Hilvert2007-05-03 05:16:00 +00001700 perturb_multipliers[i] = 1;
5d53e401 David Hilvert2007-05-02 03:12:00 +00001701
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001702 tested[i] = 1;
dda1bf79 dhilvert2006-10-22 18:40:00 +00001703
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001704 if (better()
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001705 && runs[1].get_error() < runs[0].get_error()
1706 && perturb_multipliers[i]
1707 / perturb_multipliers_original[i] < 2) {
9e8e62c9
DH
David Hilvert2007-05-13 10:57:00 +00001708 runs[0] = runs[1];
1709 runs.pop_back();
1710 return;
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001711 }
82db7fe6 David Hilvert2007-05-05 18:29:00 +00001712
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001713 }
dda1bf79 dhilvert2006-10-22 18:40:00 +00001714
2077ce22
DH
David Hilvert2007-05-13 09:23:00 +00001715 if (runs.size() > 1)
1716 runs.pop_back();
3aa65890 dhilvert2006-10-25 15:26:00 +00001717
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001718 if (!found_unreliable)
1719 return;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001720 }
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001721 }
08151f52 dhilvert2006-10-25 17:36:00 +00001722
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001723 };
4707675e dhilvert2006-10-19 10:24:00 +00001724
f8864302
DH
David Hilvert2008-04-11 18:15:57 +00001725 typedef diff_stat_generic<trans_single> diff_stat_t;
1726 typedef diff_stat_generic<trans_multi> diff_stat_multi;
1727
4707675e dhilvert2006-10-19 10:24:00 +00001728
30afe4b6 dhilvert2005-01-07 06:42:00 +00001729 /*
1730 * Adjust exposure for an aligned frame B against reference A.
07271611 dhilvert2005-01-07 06:48:00 +00001731 *
1732 * Expects full-LOD images.
1733 *
423af06c
DH
David Hilvert2007-09-10 17:43:00 +00001734 * Note: This method does not use any weighting, by certainty or
1735 * otherwise, in the first exposure registration pass, as any bias of
1736 * weighting according to color may also bias the exposure registration
1737 * result; it does use weighting, including weighting by certainty
1738 * (even if certainty weighting is not specified), in the second pass,
1739 * under the assumption that weighting by certainty improves handling
1740 * of out-of-range highlights, and that bias of exposure measurements
1741 * according to color may generally be less harmful after spatial
1742 * registration has been performed.
30afe4b6 dhilvert2005-01-07 06:42:00 +00001743 */
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001744 class exposure_ratio_iterate : public thread::decompose_domain {
1745 pixel_accum *asums;
1746 pixel_accum *bsums;
1747 pixel_accum *asum;
1748 pixel_accum *bsum;
1749 struct scale_cluster c;
214d014c David Hilvert2008-05-04 22:08:03 -05001750 const transformation &t;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001751 int ax_count;
1752 int pass_number;
1753 protected:
1754 void prepare_subdomains(unsigned int N) {
1755 asums = new pixel_accum[N];
1756 bsums = new pixel_accum[N];
1757 }
1758 void subdomain_algorithm(unsigned int thread,
1759 int i_min, int i_max, int j_min, int j_max) {
1760
1761 point offset = c.accum->offset();
1762
1763 for (mc_iterate m(i_min, i_max, j_min, j_max, thread); !m.done(); m++) {
1764
1765 unsigned int i = (unsigned int) m.get_i();
1766 unsigned int j = (unsigned int) m.get_j();
1767
1768 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
1769 continue;
1770
1771 /*
1772 * Transform
1773 */
1774
1775 struct point q;
1776
1777 q = (c.input_scale < 1.0 && interpolant == NULL)
1778 ? t.scaled_inverse_transform(
1779 point(i + offset[0], j + offset[1]))
1780 : t.unscaled_inverse_transform(
1781 point(i + offset[0], j + offset[1]));
1782
1783 /*
1784 * Check that the transformed coordinates are within
1785 * the boundaries of array c.input, that they are not
1786 * subject to exclusion, and that the weight value in
1787 * the accumulated array is nonzero.
1788 */
1789
1790 if (input_excluded(q[0], q[1], c.ax_parameters, ax_count))
1791 continue;
1792
1793 if (q[0] >= 0
1794 && q[0] <= c.input->height() - 1
1795 && q[1] >= 0
1796 && q[1] <= c.input->width() - 1
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00001797 && ((pixel) c.certainty->get_pixel(i, j)).minabs_norm() != 0) {
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001798 pixel a = c.accum->get_pixel(i, j);
1799 pixel b;
1800
1801 b = c.input->get_bl(q);
1802
1803 pixel weight = ((c.aweight && pass_number)
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00001804 ? (pixel) c.aweight->get_pixel(i, j)
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001805 : pixel(1, 1, 1))
1806 * (pass_number
5c603c78
DH
David Hilvert2007-10-29 04:51:00 +00001807 ? psqrt(c.certainty->get_pixel(i, j)
1808 * c.input_certainty->get_bl(q, 1))
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001809 : pixel(1, 1, 1));
1810
1811 asums[thread] += a * weight;
1812 bsums[thread] += b * weight;
1813 }
1814 }
1815 }
1816
1817 void finish_subdomains(unsigned int N) {
1818 for (unsigned int n = 0; n < N; n++) {
1819 *asum += asums[n];
1820 *bsum += bsums[n];
1821 }
34c6efce
DH
David Hilvert2007-10-23 01:35:00 +00001822 delete[] asums;
1823 delete[] bsums;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001824 }
1825 public:
1826 exposure_ratio_iterate(pixel_accum *_asum,
1827 pixel_accum *_bsum,
1828 struct scale_cluster _c,
214d014c David Hilvert2008-05-04 22:08:03 -05001829 const transformation &_t,
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001830 int _ax_count,
1831 int _pass_number) : decompose_domain(0, _c.accum->height(),
dd761b64
DH
David Hilvert2008-01-26 17:41:00 +00001832 0, _c.accum->width()),
1833 t(_t) {
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001834
1835 asum = _asum;
1836 bsum = _bsum;
1837 c = _c;
214d014c
DH
David Hilvert2008-05-04 22:08:03 -05001838 ax_count = _ax_count;
1839 pass_number = _pass_number;
1840 }
1841
1842 exposure_ratio_iterate(pixel_accum *_asum,
1843 pixel_accum *_bsum,
1844 struct scale_cluster _c,
1845 const transformation &_t,
1846 int _ax_count,
1847 int _pass_number,
1848 transformation::elem_bounds_int_t b) : decompose_domain(b.imin, b.imax,
1849 b.jmin, b.jmax),
1850 t(_t) {
1851
1852 asum = _asum;
1853 bsum = _bsum;
1854 c = _c;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001855 ax_count = _ax_count;
1856 pass_number = _pass_number;
1857 }
1858 };
1859
2aa417e6 dhilvert2005-01-07 06:44:00 +00001860 static void set_exposure_ratio(unsigned int m, struct scale_cluster c,
993fde09 David Hilvert2008-05-05 05:28:56 +00001861 const transformation &t, int ax_count, int pass_number) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001862
3dc20778 dhilvert2005-01-10 23:06:00 +00001863 if (_exp_register == 2) {
1864 /*
1865 * Use metadata only.
1866 */
1867 ale_real gain_multiplier = image_rw::exp(m).get_gain_multiplier();
1868 pixel multiplier = pixel(gain_multiplier, gain_multiplier, gain_multiplier);
1869
1870 image_rw::exp(m).set_multiplier(multiplier);
a9d66b26 dhilvert2005-01-10 23:15:00 +00001871 ui::get()->exp_multiplier(multiplier[0],
1872 multiplier[1],
1873 multiplier[2]);
3d7fd555 dhilvert2005-01-10 23:10:00 +00001874
1875 return;
3dc20778 dhilvert2005-01-10 23:06:00 +00001876 }
1877
70fb02f9 David Hilvert2007-09-21 03:18:00 +00001878 pixel_accum asum(0, 0, 0), bsum(0, 0, 0);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001879
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001880 exposure_ratio_iterate eri(&asum, &bsum, c, t, ax_count, pass_number);
1881 eri.run();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001882
1883 // std::cerr << (asum / bsum) << " ";
07271611 dhilvert2005-01-07 06:48:00 +00001884
1885 pixel_accum new_multiplier;
1886
1887 new_multiplier = asum / bsum * image_rw::exp(m).get_multiplier();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001888
07271611 dhilvert2005-01-07 06:48:00 +00001889 if (finite(new_multiplier[0])
1890 && finite(new_multiplier[1])
1891 && finite(new_multiplier[2])) {
1892 image_rw::exp(m).set_multiplier(new_multiplier);
1893 ui::get()->exp_multiplier(new_multiplier[0],
1894 new_multiplier[1],
1895 new_multiplier[2]);
1896 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001897 }
1898
df55d1a2 dhilvert2006-08-30 07:40:00 +00001899 /*
1900 * Copy all ax parameters.
1901 */
1902 static exclusion *copy_ax_parameters(int local_ax_count, exclusion *source) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001903
df55d1a2 dhilvert2006-08-30 07:40:00 +00001904 exclusion *dest = (exclusion *) malloc(local_ax_count * sizeof(exclusion));
2aa417e6 dhilvert2005-01-07 06:44:00 +00001905
df55d1a2 dhilvert2006-08-30 07:40:00 +00001906 assert (dest);
2aa417e6 dhilvert2005-01-07 06:44:00 +00001907
df55d1a2 dhilvert2006-08-30 07:40:00 +00001908 if (!dest)
07271611 dhilvert2005-01-07 06:48:00 +00001909 ui::get()->memory_error("exclusion regions");
2aa417e6 dhilvert2005-01-07 06:44:00 +00001910
df55d1a2 dhilvert2006-08-30 07:40:00 +00001911 for (int idx = 0; idx < local_ax_count; idx++)
1912 dest[idx] = source[idx];
2aa417e6 dhilvert2005-01-07 06:44:00 +00001913
df55d1a2 dhilvert2006-08-30 07:40:00 +00001914 return dest;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001915 }
1916
df55d1a2 dhilvert2006-08-30 07:40:00 +00001917 /*
1918 * Copy ax parameters according to frame.
1919 */
1920 static exclusion *filter_ax_parameters(int frame, int *local_ax_count) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001921
df55d1a2 dhilvert2006-08-30 07:40:00 +00001922 exclusion *dest = (exclusion *) malloc(ax_count * sizeof(exclusion));
46f9776a dhilvert2005-01-07 06:44:00 +00001923
df55d1a2 dhilvert2006-08-30 07:40:00 +00001924 assert (dest);
46f9776a dhilvert2005-01-07 06:44:00 +00001925
df55d1a2 dhilvert2006-08-30 07:40:00 +00001926 if (!dest)
07271611 dhilvert2005-01-07 06:48:00 +00001927 ui::get()->memory_error("exclusion regions");
46f9776a dhilvert2005-01-07 06:44:00 +00001928
1929 *local_ax_count = 0;
1930
1931 for (int idx = 0; idx < ax_count; idx++) {
df55d1a2 dhilvert2006-08-30 07:40:00 +00001932 if (ax_parameters[idx].x[4] > frame
1933 || ax_parameters[idx].x[5] < frame)
46f9776a dhilvert2005-01-07 06:44:00 +00001934 continue;
1935
df55d1a2 dhilvert2006-08-30 07:40:00 +00001936 dest[*local_ax_count] = ax_parameters[idx];
46f9776a dhilvert2005-01-07 06:44:00 +00001937
1938 (*local_ax_count)++;
1939 }
1940
df55d1a2 dhilvert2006-08-30 07:40:00 +00001941 return dest;
1942 }
46f9776a dhilvert2005-01-07 06:44:00 +00001943
df55d1a2 dhilvert2006-08-30 07:40:00 +00001944 static void scale_ax_parameters(int local_ax_count, exclusion *ax_parameters,
1945 ale_pos ref_scale, ale_pos input_scale) {
1946 for (int i = 0; i < local_ax_count; i++) {
1947 ale_pos scale = (ax_parameters[i].type == exclusion::RENDER)
1948 ? ref_scale
1949 : input_scale;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001950
df55d1a2 dhilvert2006-08-30 07:40:00 +00001951 for (int n = 0; n < 6; n++) {
e1eaf84c David Hilvert2007-07-24 02:50:00 +00001952 ax_parameters[i].x[n] = ax_parameters[i].x[n] * scale;
df55d1a2 dhilvert2006-08-30 07:40:00 +00001953 }
1954 }
46f9776a dhilvert2005-01-07 06:44:00 +00001955 }
1956
2aa417e6 dhilvert2005-01-07 06:44:00 +00001957 /*
1958 * Prepare the next level of detail for ordinary images.
1959 */
1960 static const image *prepare_lod(const image *current) {
1961 if (current == NULL)
1962 return NULL;
46f9776a dhilvert2005-01-07 06:44:00 +00001963
2aa417e6 dhilvert2005-01-07 06:44:00 +00001964 return current->scale_by_half("prepare_lod");
1965 }
46f9776a dhilvert2005-01-07 06:44:00 +00001966
2aa417e6 dhilvert2005-01-07 06:44:00 +00001967 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00001968 * Prepare the next level of detail for definition maps.
1969 */
1970 static const image *prepare_lod_def(const image *current) {
7a19e165
DH
David Hilvert2007-09-10 21:16:00 +00001971 if (current == NULL)
1972 return NULL;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001973
1974 return current->defined_scale_by_half("prepare_lod_def");
1975 }
1976
1977 /*
8f2ed1fd David Hilvert2007-09-07 18:36:00 +00001978 * Initialize scale cluster data structures.
2aa417e6 dhilvert2005-01-07 06:44:00 +00001979 */
8f2ed1fd
DH
David Hilvert2007-09-07 18:36:00 +00001980
1981 static void init_nl_cluster(struct scale_cluster *sc) {
1982 }
1983
2aa417e6 dhilvert2005-01-07 06:44:00 +00001984 /*
1985 * Destroy the first element in the scale cluster data structure.
1986 */
a85f57f9 David Hilvert2007-10-15 17:07:00 +00001987 static void final_clusters(struct scale_cluster *scale_clusters, ale_pos scale_factor,
2aa417e6 dhilvert2005-01-07 06:44:00 +00001988 unsigned int steps) {
1989
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001990 if (scale_clusters[0].input_scale < 1.0) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001991 delete scale_clusters[0].input;
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001992 }
2aa417e6 dhilvert2005-01-07 06:44:00 +00001993
44a1d1de
DH
David Hilvert2009-03-30 19:02:57 +00001994 delete scale_clusters[0].input_certainty;
1995
2aa417e6 dhilvert2005-01-07 06:44:00 +00001996 free((void *)scale_clusters[0].ax_parameters);
1997
1998 for (unsigned int step = 1; step < steps; step++) {
1999 delete scale_clusters[step].accum;
580b5321 David Hilvert2007-09-10 17:35:00 +00002000 delete scale_clusters[step].certainty;
2aa417e6 dhilvert2005-01-07 06:44:00 +00002001 delete scale_clusters[step].aweight;
2002
c6e3d33a David Hilvert2007-10-02 15:57:00 +00002003 if (scale_clusters[step].input_scale < 1.0) {
07271611 dhilvert2005-01-07 06:48:00 +00002004 delete scale_clusters[step].input;
c6e3d33a
DH
David Hilvert2007-10-02 15:57:00 +00002005 delete scale_clusters[step].input_certainty;
2006 }
07271611 dhilvert2005-01-07 06:48:00 +00002007
2aa417e6 dhilvert2005-01-07 06:44:00 +00002008 free((void *)scale_clusters[step].ax_parameters);
2009 }
2010
2011 free(scale_clusters);
46f9776a dhilvert2005-01-07 06:44:00 +00002012 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00002013
2014 /*
c052e200 dhilvert2005-05-08 16:16:00 +00002015 * Calculate the centroid of a control point for the set of frames
2016 * having index lower than m. Divide by any scaling of the output.
2017 */
2018 static point unscaled_centroid(unsigned int m, unsigned int p) {
2019 assert(_keep);
2020
2021 point point_sum(0, 0);
2022 ale_accum divisor = 0;
2023
2024 for(unsigned int j = 0; j < m; j++) {
2025 point pp = cp_array[p][j];
2026
2027 if (pp.defined()) {
2028 point_sum += kept_t[j].transform_unscaled(pp)
2029 / kept_t[j].scale();
2030 divisor += 1;
2031 }
2032 }
2033
2034 if (divisor == 0)
2035 return point::undefined();
2036
2037 return point_sum / divisor;
2038 }
2039
2040 /*
2041 * Calculate centroid of this frame, and of all previous frames,
2042 * from points common to both sets.
2043 */
2044 static void centroids(unsigned int m, point *current, point *previous) {
2045 /*
2046 * Calculate the translation
2047 */
2048 point other_centroid(0, 0);
2049 point this_centroid(0, 0);
2050 ale_pos divisor = 0;
2051
2052 for (unsigned int i = 0; i < cp_count; i++) {
2053 point other_c = unscaled_centroid(m, i);
2054 point this_c = cp_array[i][m];
2055
2056 if (!other_c.defined() || !this_c.defined())
2057 continue;
2058
2059 other_centroid += other_c;
2060 this_centroid += this_c;
2061 divisor += 1;
2062
2063 }
2064
2065 if (divisor == 0) {
2066 *current = point::undefined();
2067 *previous = point::undefined();
2068 return;
2069 }
2070
2071 *current = this_centroid / divisor;
2072 *previous = other_centroid / divisor;
2073 }
2074
2075 /*
b386e644 dhilvert2005-04-30 09:28:00 +00002076 * Calculate the RMS error of control points for frame m, with
2077 * transformation t, against control points for earlier frames.
2078 */
e812ee44 David Hilvert2007-10-18 18:24:00 +00002079 static ale_pos cp_rms_error(unsigned int m, transformation t) {
b386e644 dhilvert2005-04-30 09:28:00 +00002080 assert (_keep);
2081
2082 ale_accum err = 0;
2083 ale_accum divisor = 0;
2084
2085 for (unsigned int i = 0; i < cp_count; i++)
2086 for (unsigned int j = 0; j < m; j++) {
2087 const point *p = cp_array[i];
936ff6ec dhilvert2005-05-07 20:02:00 +00002088 point p_ref = kept_t[j].transform_unscaled(p[j]);
2089 point p_cur = t.transform_unscaled(p[m]);
b386e644 dhilvert2005-04-30 09:28:00 +00002090
2091 if (!p_ref.defined() || !p_cur.defined())
2092 continue;
2093
2094 err += p_ref.lengthtosq(p_cur);
2095 divisor += 1;
2096 }
2097
e812ee44 David Hilvert2007-10-18 18:24:00 +00002098 return (ale_pos) sqrt(err / divisor);
b386e644 dhilvert2005-04-30 09:28:00 +00002099 }
2100
6126fb3c David Hilvert2007-04-03 08:15:00 +00002101
59e5857b David Hilvert2007-05-08 12:15:00 +00002102 static void test_global(diff_stat_t *here, scale_cluster si, transformation t,
a7882498 David Hilvert2007-10-16 19:48:00 +00002103 int local_ax_count, int m, ale_accum local_gs_mo, ale_pos perturb) {
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00002104
2105 diff_stat_t test(*here);
2106
1b980378 David Hilvert2008-07-18 18:30:40 +00002107 test.diff(si, t.get_current_element(), local_ax_count, m);
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00002108
2109 unsigned int ovl = overlap(si, t, local_ax_count);
2110
2111 if (ovl >= local_gs_mo && test.better()) {
2112 test.confirm();
2113 *here = test;
2114 ui::get()->set_match(here->get_error());
2115 ui::get()->set_offset(here->get_offset());
2116 } else {
2117 test.discard();
2118 }
2119
2120 }
2121
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002122 /*
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002123 * Get the set of global transformations for a given density
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002124 */
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00002125 static void test_globals(diff_stat_t *here,
2126 scale_cluster si, transformation t, int local_gs, ale_pos adj_p,
a7882498 David Hilvert2007-10-16 19:48:00 +00002127 int local_ax_count, int m, ale_accum local_gs_mo, ale_pos perturb) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002128
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002129 transformation offset = t;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002130
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002131 point min, max;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002132
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002133 transformation offset_p = offset;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002134
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002135 if (!offset_p.is_projective())
2136 offset_p.eu_to_gpt();
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002137
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002138 min = max = offset_p.gpt_get(0);
2139 for (int p_index = 1; p_index < 4; p_index++) {
2140 point p = offset_p.gpt_get(p_index);
2141 if (p[0] < min[0])
2142 min[0] = p[0];
2143 if (p[1] < min[1])
2144 min[1] = p[1];
2145 if (p[0] > max[0])
2146 max[0] = p[0];
2147 if (p[1] > max[1])
2148 max[1] = p[1];
2149 }
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002150
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002151 point inner_min_t = -min;
2152 point inner_max_t = -max + point(si.accum->height(), si.accum->width());
2153 point outer_min_t = -max + point(adj_p - 1, adj_p - 1);
2154 point outer_max_t = point(si.accum->height(), si.accum->width()) - point(adj_p, adj_p);
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002155
02eb92ab David Hilvert2007-05-08 07:11:00 +00002156 if (local_gs == 1 || local_gs == 3 || local_gs == 4 || local_gs == 6) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002157
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002158 /*
2159 * Inner
2160 */
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002161
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002162 for (ale_pos i = inner_min_t[0]; i <= inner_max_t[0]; i += adj_p)
2163 for (ale_pos j = inner_min_t[1]; j <= inner_max_t[1]; j += adj_p) {
2164 transformation test_t = offset;
2165 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002166 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002167 }
2168 }
2169
02eb92ab David Hilvert2007-05-08 07:11:00 +00002170 if (local_gs == 2 || local_gs == 3 || local_gs == -1 || local_gs == 6) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002171
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002172 /*
2173 * Outer
2174 */
2175
2176 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
2177 for (ale_pos j = outer_min_t[1]; j < inner_min_t[1]; j += adj_p) {
2178 transformation test_t = offset;
2179 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002180 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002181 }
2182 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
2183 for (ale_pos j = outer_max_t[1]; j > inner_max_t[1]; j -= adj_p) {
2184 transformation test_t = offset;
2185 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002186 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002187 }
2188 for (ale_pos i = outer_min_t[0]; i < inner_min_t[0]; i += adj_p)
2189 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
2190 transformation test_t = offset;
2191 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002192 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002193 }
2194 for (ale_pos i = outer_max_t[0]; i > inner_max_t[0]; i -= adj_p)
2195 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
2196 transformation test_t = offset;
2197 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002198 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
f2d60fe2
DH
David Hilvert2007-04-13 23:28:00 +00002199 }
2200 }
cc71efb2
DH
David Hilvert2007-04-08 16:37:00 +00002201 }
2202
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00002203 static void get_translational_set(std::vector<transformation> *set,
2204 transformation t, ale_pos adj_p) {
2205
2206 ale_pos adj_s;
2207
2208 transformation offset = t;
dd761b64 David Hilvert2008-01-26 17:41:00 +00002209 transformation test_t(transformation::eu_identity());
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00002210
2211 for (int i = 0; i < 2; i++)
2212 for (adj_s = -adj_p; adj_s <= adj_p; adj_s += 2 * adj_p) {
2213
2214 test_t = offset;
2215
5b7749b0 David Hilvert2007-04-26 04:36:00 +00002216 test_t.translate(i ? point(adj_s, 0) : point(0, adj_s));
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00002217
2218 set->push_back(test_t);
2219 }
2220 }
2221
cd621c15 David Hilvert2007-07-23 20:38:00 +00002222 static int threshold_ok(ale_accum error) {
34add5e1 David Hilvert2007-10-17 21:47:00 +00002223 if ((1 - error) * (ale_accum) 100 >= match_threshold)
cd621c15
DH
David Hilvert2007-07-23 20:38:00 +00002224 return 1;
2225
2226 if (!(match_threshold >= 0))
2227 return 1;
2228
2229 return 0;
2230 }
228e156a
DH
David Hilvert2007-04-22 23:17:00 +00002231
2232 /*
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00002233 * Check for satisfaction of the certainty threshold.
2234 */
2235 static int ma_cert_satisfied(const scale_cluster &c, const transformation &t, unsigned int i) {
d790f7da David Hilvert2008-05-02 18:59:43 -05002236 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 +00002237 ale_accum sum[3] = {0, 0, 0};
2238
d790f7da
DH
David Hilvert2008-05-02 18:59:43 -05002239 for (unsigned int ii = b.imin; ii < b.imax; ii++)
2240 for (unsigned int jj = b.jmin; jj < b.jmax; jj++) {
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00002241 pixel p = c.accum->get_pixel(ii, jj);
2242 sum[0] += p[0];
2243 sum[1] += p[1];
2244 sum[2] += p[2];
2245 }
2246
d790f7da David Hilvert2008-05-02 18:59:43 -05002247 unsigned int count = (b.jmax - b.jmin) * (b.imax - b.imin);
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00002248
2249 for (int k = 0; k < 3; k++)
2250 if (sum[k] / count < _ma_cert)
2251 return 0;
2252
2253 return 1;
2254 }
2255
1b980378
DH
David Hilvert2008-07-18 18:30:40 +00002256 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) {
2257
2258 if (offset.get_current_index() > 0)
2259 for (int i = offset.parent_index(offset.get_current_index()); i >= 0; i = (i > 0) ? (int) offset.parent_index(i) : -1) {
2260 trans_single t = offset.get_element(i);
2261 t.rescale(offset.get_current_element().scale());
2262
2263 here.diff(si, t, local_ax_count, frame);
2264
e0577945 David Hilvert2008-07-19 22:11:55 +00002265 if (here.better_defined())
1b980378
DH
David Hilvert2008-07-18 18:30:40 +00002266 here.confirm();
2267 else
2268 here.discard();
2269 }
2270
2271 return here;
2272 }
2273
46f9776a dhilvert2005-01-07 06:44:00 +00002274#ifdef USE_FFTW
2275 /*
2276 * High-pass filter for frequency weights
2277 */
2278 static void hipass(int rows, int cols, fftw_complex *inout) {
2279 for (int i = 0; i < rows * vert_freq_cut; i++)
2280 for (int j = 0; j < cols; j++)
2281 for (int k = 0; k < 2; k++)
2282 inout[i * cols + j][k] = 0;
2283 for (int i = 0; i < rows; i++)
2284 for (int j = 0; j < cols * horiz_freq_cut; j++)
2285 for (int k = 0; k < 2; k++)
2286 inout[i * cols + j][k] = 0;
2287 for (int i = 0; i < rows; i++)
2288 for (int j = 0; j < cols; j++)
2289 for (int k = 0; k < 2; k++)
2290 if (i / (double) rows + j / (double) cols < 2 * avg_freq_cut)
2291 inout[i * cols + j][k] = 0;
2292 }
2293#endif
2294
2aa417e6 dhilvert2005-01-07 06:44:00 +00002295
2296 /*
2297 * Reset alignment weights
2298 */
2299 static void reset_weights() {
07271611 dhilvert2005-01-07 06:48:00 +00002300 if (alignment_weights != NULL)
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002301 ale_image_release(alignment_weights);
07271611 dhilvert2005-01-07 06:48:00 +00002302
2303 alignment_weights = NULL;
2aa417e6 dhilvert2005-01-07 06:44:00 +00002304 }
2305
2306 /*
2307 * Initialize alignment weights
2308 */
2309 static void init_weights() {
2310 if (alignment_weights != NULL)
2311 return;
2312
3617b771 David Hilvert2009-05-31 15:07:14 +00002313 alignment_weights = ale_new_image(accel::context(), ALE_IMAGE_RGB, ale_image_get_type(reference_image));
2aa417e6 dhilvert2005-01-07 06:44:00 +00002314
2315 assert (alignment_weights);
2316
e28f8ff7 David Hilvert2009-06-02 22:23:44 +00002317 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 +00002318
bccf19c9 David Hilvert2009-07-18 19:30:20 +00002319 ale_eval("MAP_PIXEL(%0I, p, PIXEL(1, 1, 1))", alignment_weights);
2aa417e6 dhilvert2005-01-07 06:44:00 +00002320 }
2321
46f9776a dhilvert2005-01-07 06:44:00 +00002322 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002323 * Update alignment weights with weight map
2324 */
2325 static void map_update() {
2326
2327 if (weight_map == NULL)
2328 return;
2329
2330 init_weights();
2331
bccf19c9 David Hilvert2009-07-18 19:30:20 +00002332 ale_eval("MAP_PIXEL(%0I, p, GET_PIXEL(%0i, p) * GET_PIXEL_BG(%1i, p))", alignment_weights, weight_map);
2aa417e6 dhilvert2005-01-07 06:44:00 +00002333 }
2334
2335 /*
2336 * Update alignment weights with algorithmic weights
46f9776a dhilvert2005-01-07 06:44:00 +00002337 */
2338 static void wmx_update() {
2339#ifdef USE_UNIX
2340
2341 static exposure *exp_def = new exposure_default();
2342 static exposure *exp_bool = new exposure_boolean();
2343
46f9776a dhilvert2005-01-07 06:44:00 +00002344 if (wmx_file == NULL || wmx_exec == NULL || wmx_defs == NULL)
2345 return;
2346
33a3cc28
DH
David Hilvert2009-06-03 19:51:46 +00002347 unsigned int rows = ale_image_get_height(reference_image);
2348 unsigned int cols = ale_image_get_width(reference_image);
46f9776a dhilvert2005-01-07 06:44:00 +00002349
2350 image_rw::write_image(wmx_file, reference_image);
ac4577d5 David Hilvert2009-06-14 19:02:25 +00002351 image_rw::write_image(wmx_defs, reference_image, exp_bool->get_gamma(), 0, 0, 1);
46f9776a dhilvert2005-01-07 06:44:00 +00002352
2353 /* execute ... */
2354 int exit_status = 1;
2355 if (!fork()) {
2356 execlp(wmx_exec, wmx_exec, wmx_file, wmx_defs, NULL);
07271611 dhilvert2005-01-07 06:48:00 +00002357 ui::get()->exec_failure(wmx_exec, wmx_file, wmx_defs);
46f9776a dhilvert2005-01-07 06:44:00 +00002358 }
2359
2360 wait(&exit_status);
2361
07271611 dhilvert2005-01-07 06:48:00 +00002362 if (exit_status)
2363 ui::get()->fork_failure("d2::align");
46f9776a dhilvert2005-01-07 06:44:00 +00002364
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002365 ale_image wmx_weights = image_rw::read_image(wmx_file, exp_def);
46f9776a dhilvert2005-01-07 06:44:00 +00002366
35c1c6e3
DH
David Hilvert2009-06-14 21:17:14 +00002367 ale_image_set_x_offset(wmx_weights, ale_image_get_x_offset(reference_image));
2368 ale_image_set_y_offset(wmx_weights, ale_image_get_y_offset(reference_image));
5073b97e David Hilvert2009-06-14 20:59:56 +00002369
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002370 if (ale_image_get_height(wmx_weights) != rows || ale_image_get_width(wmx_weights) != cols)
07271611 dhilvert2005-01-07 06:48:00 +00002371 ui::get()->error("algorithmic weighting must not change image size");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002372
2373 if (alignment_weights == NULL)
2374 alignment_weights = wmx_weights;
2375 else
bccf19c9 David Hilvert2009-07-18 19:30:20 +00002376 ale_eval("MAP_PIXEL(%0I, p, GET_PIXEL(%0i, p) * GET_PIXEL(%1i, p))", alignment_weights, wmx_weights);
46f9776a dhilvert2005-01-07 06:44:00 +00002377#endif
2378 }
2379
2380 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002381 * Update alignment weights with frequency weights
46f9776a dhilvert2005-01-07 06:44:00 +00002382 */
2383 static void fw_update() {
2384#ifdef USE_FFTW
46f9776a dhilvert2005-01-07 06:44:00 +00002385 if (horiz_freq_cut == 0
2386 && vert_freq_cut == 0
2387 && avg_freq_cut == 0)
2388 return;
2389
2aa417e6 dhilvert2005-01-07 06:44:00 +00002390 /*
2391 * Required for correct operation of --fwshow
2392 */
2393
2394 assert (alignment_weights == NULL);
2395
46f9776a dhilvert2005-01-07 06:44:00 +00002396 int rows = reference_image->height();
2397 int cols = reference_image->width();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002398 int colors = reference_image->depth();
46f9776a dhilvert2005-01-07 06:44:00 +00002399
7cc12274 David Hilvert2007-12-11 04:50:00 +00002400 alignment_weights = new_image_ale_real(rows, cols,
2aa417e6 dhilvert2005-01-07 06:44:00 +00002401 colors, "alignment_weights");
46f9776a dhilvert2005-01-07 06:44:00 +00002402
2403 fftw_complex *inout = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * rows * cols);
2404
2405 assert (inout);
2406
2407 fftw_plan pf = fftw_plan_dft_2d(rows, cols,
2408 inout, inout,
2409 FFTW_FORWARD, FFTW_ESTIMATE);
2410
2411 fftw_plan pb = fftw_plan_dft_2d(rows, cols,
2412 inout, inout,
2413 FFTW_BACKWARD, FFTW_ESTIMATE);
2414
2aa417e6 dhilvert2005-01-07 06:44:00 +00002415 for (int k = 0; k < colors; k++) {
46f9776a dhilvert2005-01-07 06:44:00 +00002416 for (int i = 0; i < rows * cols; i++) {
2417 inout[i][0] = reference_image->get_pixel(i / cols, i % cols)[k];
2418 inout[i][1] = 0;
2419 }
2420
2421 fftw_execute(pf);
2422 hipass(rows, cols, inout);
2423 fftw_execute(pb);
2424
2425 for (int i = 0; i < rows * cols; i++) {
2426#if 0
2aa417e6 dhilvert2005-01-07 06:44:00 +00002427 alignment_weights->pix(i / cols, i % cols)[k] = fabs(inout[i][0] / (rows * cols));
46f9776a dhilvert2005-01-07 06:44:00 +00002428#else
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00002429 alignment_weights->set_chan(i / cols, i % cols, k,
46f9776a dhilvert2005-01-07 06:44:00 +00002430 sqrt(pow(inout[i][0] / (rows * cols), 2)
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00002431 + pow(inout[i][1] / (rows * cols), 2)));
46f9776a dhilvert2005-01-07 06:44:00 +00002432#endif
2433 }
2434 }
2435
2436 fftw_destroy_plan(pf);
2437 fftw_destroy_plan(pb);
2438 fftw_free(inout);
2439
2440 if (fw_output != NULL)
2aa417e6 dhilvert2005-01-07 06:44:00 +00002441 image_rw::write_image(fw_output, alignment_weights);
46f9776a dhilvert2005-01-07 06:44:00 +00002442#endif
2443 }
2444
30afe4b6 dhilvert2005-01-07 06:42:00 +00002445 /*
2446 * Update alignment to frame N.
2447 */
2448 static void update_to(int n) {
0e4ec247 David Hilvert2007-03-13 04:51:00 +00002449
30afe4b6 dhilvert2005-01-07 06:42:00 +00002450 assert (n <= latest + 1);
0a432b63 David Hilvert2007-03-13 08:03:00 +00002451 assert (n >= 0);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002452
f922c1c4 David Hilvert2009-06-22 00:04:12 +00002453 ale_align_properties astate = align_properties();
f65325e3 David Hilvert2007-03-15 06:24:00 +00002454
724b1c71
DH
David Hilvert2008-07-01 15:20:56 +00002455 ui::get()->set_frame_num(n);
2456
46f9776a dhilvert2005-01-07 06:44:00 +00002457 if (latest < 0) {
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002458
2459 /*
2460 * Handle the initial frame
2461 */
2462
8aaa492c
DH
David Hilvert2009-06-28 01:59:05 +00002463 astate.set_input_frame(image_rw::open(n));
2464
2465 const image *i = astate.get_input_frame();
46f9776a dhilvert2005-01-07 06:44:00 +00002466 int is_default;
2467 transformation result = alignment_class == 2
2468 ? transformation::gpt_identity(i, scale_factor)
2469 : transformation::eu_identity(i, scale_factor);
2470 result = tload_first(tload, alignment_class == 2, result, &is_default);
2471 tsave_first(tsave, result, alignment_class == 2);
46f9776a dhilvert2005-01-07 06:44:00 +00002472
2473 if (_keep > 0) {
dd761b64 David Hilvert2008-01-26 17:41:00 +00002474 kept_t = transformation::new_eu_identity_array(image_rw::count());
46f9776a dhilvert2005-01-07 06:44:00 +00002475 kept_ok = (int *) malloc(image_rw::count()
2476 * sizeof(int));
2477 assert (kept_t);
2478 assert (kept_ok);
2479
07271611 dhilvert2005-01-07 06:48:00 +00002480 if (!kept_t || !kept_ok)
2481 ui::get()->memory_error("alignment");
46f9776a dhilvert2005-01-07 06:44:00 +00002482
2483 kept_ok[0] = 1;
2484 kept_t[0] = result;
2485 }
2486
2487 latest = 0;
2488 latest_ok = 1;
2489 latest_t = result;
2490
0467efe3 David Hilvert2008-04-09 21:14:38 +00002491 astate.set_default(result);
46f9776a dhilvert2005-01-07 06:44:00 +00002492 orig_t = result;
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002493
2494 image_rw::close(n);
46f9776a dhilvert2005-01-07 06:44:00 +00002495 }
2496
bbc7699c David Hilvert2007-04-02 03:05:00 +00002497 for (int i = latest + 1; i <= n; i++) {
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002498
2499 /*
2500 * Handle supplemental frames.
2501 */
2502
46f9776a dhilvert2005-01-07 06:44:00 +00002503 assert (reference != NULL);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002504
07271611 dhilvert2005-01-07 06:48:00 +00002505 ui::get()->set_arender_current();
46f9776a dhilvert2005-01-07 06:44:00 +00002506 reference->sync(i - 1);
07271611 dhilvert2005-01-07 06:48:00 +00002507 ui::get()->clear_arender_current();
46f9776a dhilvert2005-01-07 06:44:00 +00002508 reference_image = reference->get_image();
2509 reference_defined = reference->get_defined();
30afe4b6 dhilvert2005-01-07 06:42:00 +00002510
f2fc9b99 David Hilvert2008-02-14 17:35:00 +00002511 if (i == 1)
0467efe3 David Hilvert2008-04-09 21:14:38 +00002512 astate.default_set_original_bounds(reference_image);
f2fc9b99 David Hilvert2008-02-14 17:35:00 +00002513
2aa417e6 dhilvert2005-01-07 06:44:00 +00002514 reset_weights();
46f9776a dhilvert2005-01-07 06:44:00 +00002515 fw_update();
2516 wmx_update();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002517 map_update();
30afe4b6 dhilvert2005-01-07 06:42:00 +00002518
46f9776a dhilvert2005-01-07 06:44:00 +00002519 assert (reference_image != NULL);
2520 assert (reference_defined != NULL);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002521
0467efe3 David Hilvert2008-04-09 21:14:38 +00002522 astate.set_input_frame(image_rw::open(i));
0a432b63 David Hilvert2007-03-13 08:03:00 +00002523
e580d9d3 David Hilvert2007-12-19 16:59:00 +00002524 _align(i, _gs, &astate);
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002525
2526 image_rw::close(n);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002527 }
2528 }
2529
2530public:
2531
2532 /*
04382119 dhilvert2005-04-29 09:23:00 +00002533 * Set the control point count
2534 */
2535 static void set_cp_count(unsigned int n) {
2536 assert (cp_array == NULL);
2537
2538 cp_count = n;
2539 cp_array = (const point **) malloc(n * sizeof(const point *));
2540 }
2541
2542 /*
2543 * Set control points.
2544 */
2545 static void set_cp(unsigned int i, const point *p) {
2546 cp_array[i] = p;
2547 }
2548
2549 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002550 * Register exposure
2551 */
2552 static void exp_register() {
2553 _exp_register = 1;
2554 }
2555
2556 /*
3dc20778 dhilvert2005-01-10 23:06:00 +00002557 * Register exposure only based on metadata
2558 */
2559 static void exp_meta_only() {
2560 _exp_register = 2;
2561 }
2562
2563 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002564 * Don't register exposure
2565 */
2566 static void exp_noregister() {
2567 _exp_register = 0;
2568 }
2569
2570 /*
2571 * Set alignment class to translation only. Only adjust the x and y
2572 * position of images. Do not rotate input images or perform
2573 * projective transformations.
2574 */
2575 static void class_translation() {
2576 alignment_class = 0;
2577 }
2578
2579 /*
2580 * Set alignment class to Euclidean transformations only. Adjust the x
2581 * and y position of images and the orientation of the image about the
2582 * image center.
2583 */
2584 static void class_euclidean() {
2585 alignment_class = 1;
2586 }
2587
2588 /*
2589 * Set alignment class to perform general projective transformations.
2590 * See the file gpt.h for more information about general projective
2591 * transformations.
2592 */
2593 static void class_projective() {
2594 alignment_class = 2;
2595 }
2596
2597 /*
2598 * Set the default initial alignment to the identity transformation.
2599 */
2600 static void initial_default_identity() {
2601 default_initial_alignment_type = 0;
2602 }
2603
2604 /*
2605 * Set the default initial alignment to the most recently matched
2606 * frame's final transformation.
2607 */
2608 static void initial_default_follow() {
2609 default_initial_alignment_type = 1;
2610 }
2611
2612 /*
f09b7254 dhilvert2005-01-07 06:44:00 +00002613 * Perturb output coordinates.
2614 */
2615 static void perturb_output() {
2616 perturb_type = 0;
2617 }
2618
2619 /*
2620 * Perturb source coordinates.
2621 */
2622 static void perturb_source() {
2623 perturb_type = 1;
2624 }
2625
2626 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002627 * Frames under threshold align optimally
2628 */
2629 static void fail_optimal() {
2630 is_fail_default = 0;
2631 }
2632
2633 /*
2634 * Frames under threshold keep their default alignments.
2635 */
2636 static void fail_default() {
2637 is_fail_default = 1;
2638 }
2639
2640 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002641 * Align images with an error contribution from each color channel.
2642 */
2643 static void all() {
2644 channel_alignment_type = 0;
2645 }
2646
2647 /*
2648 * Align images with an error contribution only from the green channel.
2649 * Other color channels do not affect alignment.
2650 */
2651 static void green() {
2652 channel_alignment_type = 1;
2653 }
2654
2655 /*
2656 * Align images using a summation of channels. May be useful when
2657 * dealing with images that have high frequency color ripples due to
2658 * color aliasing.
2659 */
2660 static void sum() {
2661 channel_alignment_type = 2;
2662 }
2663
2664 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002665 * Error metric exponent
2666 */
2667
2668 static void set_metric_exponent(float me) {
2669 metric_exponent = me;
2670 }
2671
2672 /*
2673 * Match threshold
2674 */
2675
2676 static void set_match_threshold(float mt) {
2677 match_threshold = mt;
2678 }
2679
2680 /*
2681 * Perturbation lower and upper bounds.
2682 */
2683
f09b7254 dhilvert2005-01-07 06:44:00 +00002684 static void set_perturb_lower(ale_pos pl, int plp) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002685 perturb_lower = pl;
f09b7254 dhilvert2005-01-07 06:44:00 +00002686 perturb_lower_percent = plp;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002687 }
2688
f09b7254 dhilvert2005-01-07 06:44:00 +00002689 static void set_perturb_upper(ale_pos pu, int pup) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002690 perturb_upper = pu;
f09b7254 dhilvert2005-01-07 06:44:00 +00002691 perturb_upper_percent = pup;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002692 }
2693
2694 /*
2695 * Maximum rotational perturbation.
2696 */
2697
2698 static void set_rot_max(int rm) {
2699
2700 /*
2701 * Obtain the largest power of two not larger than rm.
2702 */
2703
2704 rot_max = pow(2, floor(log(rm) / log(2)));
2705 }
2706
2707 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002708 * Barrel distortion adjustment multiplier
2709 */
2710
2711 static void set_bda_mult(ale_pos m) {
2712 bda_mult = m;
2713 }
2714
2715 /*
2716 * Barrel distortion maximum rate of change
2717 */
2718
2719 static void set_bda_rate(ale_pos m) {
2720 bda_rate = m;
2721 }
2722
2723 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002724 * Level-of-detail
2725 */
2726
5292ffa7
DH
David Hilvert2008-05-28 01:17:53 +00002727 static void set_lod_preferred(int lm) {
2728 lod_preferred = lm;
2729 }
2730
2731 /*
2732 * Minimum dimension for reduced level-of-detail.
2733 */
2734
2735 static void set_min_dimension(int md) {
2736 min_dimension = md;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002737 }
2738
2739 /*
2740 * Set the scale factor
2741 */
2742 static void set_scale(ale_pos s) {
2743 scale_factor = s;
2744 }
2745
2746 /*
2747 * Set reference rendering to align against
2748 */
2749 static void set_reference(render *r) {
2750 reference = r;
2751 }
2752
2753 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002754 * Set the interpolant
2755 */
2756 static void set_interpolant(filter::scaled_filter *f) {
2757 interpolant = f;
2758 }
2759
2760 /*
2761 * Set alignment weights image
2762 */
2aa417e6 dhilvert2005-01-07 06:44:00 +00002763 static void set_weight_map(const image *i) {
2764 weight_map = i;
46f9776a dhilvert2005-01-07 06:44:00 +00002765 }
2766
2767 /*
2768 * Set frequency cuts
2769 */
2770 static void set_frequency_cut(double h, double v, double a) {
2771 horiz_freq_cut = h;
2772 vert_freq_cut = v;
2773 avg_freq_cut = a;
2774 }
2775
2776 /*
2777 * Set algorithmic alignment weighting
2778 */
2779 static void set_wmx(const char *e, const char *f, const char *d) {
2780 wmx_exec = e;
2781 wmx_file = f;
2782 wmx_defs = d;
2783 }
2784
2785 /*
2786 * Show frequency weights
2787 */
2788 static void set_fl_show(const char *filename) {
2789 fw_output = filename;
2790 }
2791
2792 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002793 * Set transformation file loader.
2794 */
2795 static void set_tload(tload_t *tl) {
2796 tload = tl;
2797 }
2798
2799 /*
2800 * Set transformation file saver.
2801 */
2802 static void set_tsave(tsave_t *ts) {
2803 tsave = ts;
2804 }
2805
2806 /*
2807 * Get match statistics for frame N.
30afe4b6 dhilvert2005-01-07 06:42:00 +00002808 */
2809 static int match(int n) {
2810 update_to(n);
2811
46f9776a dhilvert2005-01-07 06:44:00 +00002812 if (n == latest)
30afe4b6 dhilvert2005-01-07 06:42:00 +00002813 return latest_ok;
2814 else if (_keep)
2815 return kept_ok[n];
46f9776a dhilvert2005-01-07 06:44:00 +00002816 else {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002817 assert(0);
46f9776a dhilvert2005-01-07 06:44:00 +00002818 exit(1);
2819 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00002820 }
2821
2822 /*
2823 * Message that old alignment data should be kept.
2824 */
2825 static void keep() {
46f9776a dhilvert2005-01-07 06:44:00 +00002826 assert (latest == -1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002827 _keep = 1;
2828 }
2829
2830 /*
2831 * Get alignment for frame N.
30afe4b6 dhilvert2005-01-07 06:42:00 +00002832 */
2833 static transformation of(int n) {
2834 update_to(n);
46f9776a dhilvert2005-01-07 06:44:00 +00002835 if (n == latest)
30afe4b6 dhilvert2005-01-07 06:42:00 +00002836 return latest_t;
2837 else if (_keep)
2838 return kept_t[n];
2839 else {
2840 assert(0);
2841 exit(1);
2842 }
2843 }
2844
2845 /*
bddc9e4d David Hilvert2007-10-01 19:50:00 +00002846 * Use Monte Carlo alignment sampling with argument N.
1c2f7405 David Hilvert2007-09-20 16:58:00 +00002847 */
bddc9e4d
DH
David Hilvert2007-10-01 19:50:00 +00002848 static void mc(ale_pos n) {
2849 _mc = n;
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +00002850 }
2851
2852 /*
07271611 dhilvert2005-01-07 06:48:00 +00002853 * Set the certainty-weighted flag.
2854 */
2855 static void certainty_weighted(int flag) {
2856 certainty_weights = flag;
2857 }
2858
2859 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002860 * Set the global search type.
2861 */
2862 static void gs(const char *type) {
7bcfe5db dhilvert2005-01-07 06:44:00 +00002863 if (!strcmp(type, "local")) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00002864 _gs = 0;
2865 } else if (!strcmp(type, "inner")) {
2866 _gs = 1;
2867 } else if (!strcmp(type, "outer")) {
2868 _gs = 2;
2869 } else if (!strcmp(type, "all")) {
2870 _gs = 3;
2871 } else if (!strcmp(type, "central")) {
2872 _gs = 4;
842afc18
DH
David Hilvert2007-05-08 06:55:00 +00002873 } else if (!strcmp(type, "defaults")) {
2874 _gs = 6;
04382119 dhilvert2005-04-29 09:23:00 +00002875 } else if (!strcmp(type, "points")) {
2876 _gs = 5;
b386e644 dhilvert2005-04-30 09:28:00 +00002877 keep();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002878 } else {
07271611 dhilvert2005-01-07 06:48:00 +00002879 ui::get()->error("bad global search type");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002880 }
2881 }
2882
2883 /*
4949c031 dhilvert2005-01-07 06:44:00 +00002884 * Set the minimum overlap for global searching
2885 */
326c35b1 David Hilvert2007-04-19 21:28:00 +00002886 static void gs_mo(ale_pos value, int _gs_mo_percent) {
4949c031 dhilvert2005-01-07 06:44:00 +00002887 _gs_mo = value;
326c35b1 David Hilvert2007-04-19 21:28:00 +00002888 gs_mo_percent = _gs_mo_percent;
4949c031 dhilvert2005-01-07 06:44:00 +00002889 }
2890
2891 /*
903df240
DH
David Hilvert2008-04-24 14:36:35 +00002892 * Set mutli-alignment certainty lower bound.
2893 */
2894 static void set_ma_cert(ale_real value) {
2895 _ma_cert = value;
2896 }
2897
2898 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002899 * Set alignment exclusion regions
2900 */
df55d1a2 dhilvert2006-08-30 07:40:00 +00002901 static void set_exclusion(exclusion *_ax_parameters, int _ax_count) {
46f9776a dhilvert2005-01-07 06:44:00 +00002902 ax_count = _ax_count;
2903 ax_parameters = _ax_parameters;
2904 }
2905
2906 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002907 * Get match summary statistics.
2908 */
2909 static ale_accum match_summary() {
34add5e1 David Hilvert2007-10-17 21:47:00 +00002910 return match_sum / (ale_accum) match_count;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002911 }
2912};
2913
f8864302
DH
David Hilvert2008-04-11 18:15:57 +00002914template<class diff_trans>
2915void *d2::align::diff_stat_generic<diff_trans>::diff_subdomain(void *args) {
2916
2917 subdomain_args *sargs = (subdomain_args *) args;
2918
2919 struct scale_cluster c = sargs->c;
2920 std::vector<run> runs = sargs->runs;
2921 int ax_count = sargs->ax_count;
2922 int f = sargs->f;
2923 int i_min = sargs->i_min;
2924 int i_max = sargs->i_max;
2925 int j_min = sargs->j_min;
2926 int j_max = sargs->j_max;
2927 int subdomain = sargs->subdomain;
2928
2929 assert (reference_image);
2930
2931 point offset = c.accum->offset();
2932
2933 for (mc_iterate m(i_min, i_max, j_min, j_max, subdomain); !m.done(); m++) {
2934
2935 int i = m.get_i();
2936 int j = m.get_j();
2937
2938 /*
2939 * Check reference frame definition.
2940 */
2941
2942 if (!((pixel) c.accum->get_pixel(i, j)).finite()
2943 || !(((pixel) c.certainty->get_pixel(i, j)).minabs_norm() > 0))
2944 continue;
2945
2946 /*
2947 * Check for exclusion in render coordinates.
2948 */
2949
2950 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
2951 continue;
2952
2953 /*
2954 * Transform
2955 */
2956
2957 struct point q, r = point::undefined();
2958
2959 q = (c.input_scale < 1.0 && interpolant == NULL)
2960 ? runs.back().offset.scaled_inverse_transform(
2961 point(i + offset[0], j + offset[1]))
2962 : runs.back().offset.unscaled_inverse_transform(
2963 point(i + offset[0], j + offset[1]));
2964
2965 if (runs.size() == 2) {
2966 r = (c.input_scale < 1.0)
2967 ? runs.front().offset.scaled_inverse_transform(
2968 point(i + offset[0], j + offset[1]))
2969 : runs.front().offset.unscaled_inverse_transform(
2970 point(i + offset[0], j + offset[1]));
2971 }
2972
2973 ale_pos ti = q[0];
2974 ale_pos tj = q[1];
2975
2976 /*
2977 * Check that the transformed coordinates are within
2978 * the boundaries of array c.input and that they
2979 * are not subject to exclusion.
2980 *
2981 * Also, check that the weight value in the accumulated array
2982 * is nonzero, unless we know it is nonzero by virtue of the
2983 * fact that it falls within the region of the original frame
2984 * (e.g. when we're not increasing image extents).
2985 */
2986
2987 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
2988 continue;
2989
2990 if (input_excluded(r[0], r[1], c.ax_parameters, ax_count))
2991 r = point::undefined();
2992
2993 /*
2994 * Check the boundaries of the input frame
2995 */
2996
2997 if (!(ti >= 0
2998 && ti <= c.input->height() - 1
2999 && tj >= 0
3000 && tj <= c.input->width() - 1))
3001 continue;
3002
3003 if (!(r[0] >= 0
3004 && r[0] <= c.input->height() - 1
3005 && r[1] >= 0
3006 && r[1] <= c.input->width() - 1))
3007 r = point::undefined();
3008
3009 sargs->runs.back().sample(f, c, i, j, q, r, runs.front());
3010 }
3011
3012 return NULL;
3013}
3014
30afe4b6 dhilvert2005-01-07 06:42:00 +00003015#endif