d2/align: Remove exclusion-region filtering and scaling logic.
[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 *
32f81001
DH
David Hilvert2009-07-21 21:20:11 +0000347 * * correct each received start element (other than 0th) based on an
348 * estimated error from alignment-calculated change in the parent
349 * element. (I.e., propagate final alignment calculations to
350 * any children's start values.)
8bba3df9
DH
David Hilvert2009-07-21 18:14:07 +0000351 */
352
353 /*
354 * Alignment state
355 *
356 * This structure contains alignment state information. The change
357 * between the non-default old initial alignment and old final
358 * alignment is used to adjust the non-default current initial
359 * alignment. If either the old or new initial alignment is a default
360 * alignment, the old --follow semantics are preserved.
361 */
362
363 class astate_t {
364 ale_trans old_initial_alignment;
365 ale_trans old_final_alignment;
366 ale_trans default_initial_alignment;
367 int old_is_default;
368 std::vector<int> is_default;
369 ale_image input_frame;
370
371 public:
372 astate_t() :
373 is_default(1) {
374
375 old_initial_alignment = ale_new_trans(accel::context(), NULL);
376 old_final_alignment = ale_new_trans(accel::context(), NULL);
377 default_initial_alignment = ale_new_trans(accel::context(), NULL);
378
379 input_frame = NULL;
380 is_default[0] = 1;
381 old_is_default = 1;
382 }
383
384 ale_image get_input_frame() const {
385 return input_frame;
386 }
387
388 void set_is_default(unsigned int index, int value) {
389
390 /*
391 * Expand the array, if necessary.
392 */
393 if (index == is_default.size());
394 is_default.resize(index + 1);
395
396 assert (index < is_default.size());
397 is_default[index] = value;
398 }
399
400 int get_is_default(unsigned int index) {
401 assert (index < is_default.size());
402 return is_default[index];
403 }
404
405 ale_trans get_default() {
406 return default_initial_alignment;
407 }
408
409 void set_default(ale_trans t) {
410 default_initial_alignment = t;
411 }
412
413 void default_set_original_bounds(ale_image i) {
414 ale_trans_set_original_bounds(default_initial_alignment, i);
415 }
416
417 void set_final(ale_trans t) {
418 old_final_alignment = t;
419 }
420
421 void set_input_frame(ale_image i) {
422 input_frame = i;
423 }
424
425 /*
426 * Implement new delta --follow semantics.
427 *
428 * If we have a transformation T such that
429 *
430 * prev_final == T(prev_init)
431 *
432 * Then we also have
433 *
434 * current_init_follow == T(current_init)
435 *
436 * We can calculate T as follows:
437 *
438 * T == prev_final(prev_init^-1)
439 *
440 * Where ^-1 is the inverse operator.
441 */
442 static trans_single follow(trans_single a, trans_single b, trans_single c) {
443 trans_single cc = c;
444
445 if (alignment_class == 0) {
446 /*
447 * Translational transformations
448 */
449
450 ale_pos t0 = -a.eu_get(0) + b.eu_get(0);
451 ale_pos t1 = -a.eu_get(1) + b.eu_get(1);
452
453 cc.eu_modify(0, t0);
454 cc.eu_modify(1, t1);
455
456 } else if (alignment_class == 1) {
457 /*
458 * Euclidean transformations
459 */
460
461 ale_pos t2 = -a.eu_get(2) + b.eu_get(2);
462
463 cc.eu_modify(2, t2);
464
465 point p( c.scaled_height()/2 + c.eu_get(0) - a.eu_get(0),
466 c.scaled_width()/2 + c.eu_get(1) - a.eu_get(1) );
467
468 p = b.transform_scaled(p);
469
470 cc.eu_modify(0, p[0] - c.scaled_height()/2 - c.eu_get(0));
471 cc.eu_modify(1, p[1] - c.scaled_width()/2 - c.eu_get(1));
472
473 } else if (alignment_class == 2) {
474 /*
475 * Projective transformations
476 */
477
478 point p[4];
479
480 p[0] = b.transform_scaled(a
481 . scaled_inverse_transform(c.transform_scaled(point( 0 , 0 ))));
482 p[1] = b.transform_scaled(a
483 . scaled_inverse_transform(c.transform_scaled(point(c.scaled_height(), 0 ))));
484 p[2] = b.transform_scaled(a
485 . scaled_inverse_transform(c.transform_scaled(point(c.scaled_height(), c.scaled_width()))));
486 p[3] = b.transform_scaled(a
487 . scaled_inverse_transform(c.transform_scaled(point( 0 , c.scaled_width()))));
488
489 cc.gpt_set(p);
490 }
491
492 return cc;
493 }
494
495 /*
496 * For multi-alignment following, we use the following approach, not
497 * guaranteed to work with large changes in scene or perspective, but
498 * which should be somewhat flexible:
499 *
500 * For
501 *
502 * t[][] calculated final alignments
503 * s[][] alignments as loaded from file
504 * previous frame n
505 * current frame n+1
506 * fundamental (primary) 0
507 * non-fundamental (non-primary) m!=0
508 * parent element m'
509 * follow(a, b, c) applying the (a, b) delta T=b(a^-1) to c
510 *
511 * following in the case of missing file data might be generated by
512 *
513 * t[n+1][0] = t[n][0]
514 * t[n+1][m!=0] = follow(t[n][m'], t[n+1][m'], t[n][m])
515 *
516 * cases with all noted file data present might be generated by
517 *
518 * t[n+1][0] = follow(s[n][0], t[n][0], s[n+1][0])
519 * t[n+1][m!=0] = follow(s[n+1][m'], t[n+1][m'], s[n+1][m])
520 *
521 * For non-following behavior, or where assigning the above is
522 * impossible, we assign the following default
523 *
524 * t[n+1][0] = Identity
525 * t[n+1][m!=0] = t[n+1][m']
526 */
527
528 void init_frame_alignment_primary(transformation *offset, int lod, ale_pos perturb) {
529
530 if (perturb > 0 && !old_is_default && !get_is_default(0)
531 && default_initial_alignment_type == 1) {
532
533 /*
534 * Apply following logic for the primary element.
535 */
536
537 ui::get()->following();
538
539 trans_single new_offset = follow(old_initial_alignment.get_element(0),
540 old_final_alignment.get_element(0),
541 offset->get_element(0));
542
543 old_initial_alignment = *offset;
544
545 offset->set_element(0, new_offset);
546
547 ui::get()->set_offset(new_offset);
548 } else {
549 old_initial_alignment = *offset;
550 }
551
552 is_default.resize(old_initial_alignment.stack_depth());
553 }
554
555 void init_frame_alignment_nonprimary(transformation *offset,
556 int lod, ale_pos perturb, unsigned int index) {
557
558 assert (index > 0);
559
560 unsigned int parent_index = offset->parent_index(index);
561
562 if (perturb > 0
563 && !get_is_default(parent_index)
564 && !get_is_default(index)
565 && default_initial_alignment_type == 1) {
566
567 /*
568 * Apply file-based following logic for the
569 * given element.
570 */
571
572 ui::get()->following();
573
574 trans_single new_offset = follow(old_initial_alignment.get_element(parent_index),
575 offset->get_element(parent_index),
576 offset->get_element(index));
577
578 old_initial_alignment.set_element(index, offset->get_element(index));
579 offset->set_element(index, new_offset);
580
581 ui::get()->set_offset(new_offset);
582
583 return;
584 }
585
586 offset->get_coordinate(parent_index);
587
588
589 if (perturb > 0
590 && old_final_alignment.exists(offset->get_coordinate(parent_index))
591 && old_final_alignment.exists(offset->get_current_coordinate())
592 && default_initial_alignment_type == 1) {
593
594 /*
595 * Apply nonfile-based following logic for
596 * the given element.
597 */
598
599 ui::get()->following();
600
601 /*
602 * XXX: Although it is different, the below
603 * should be equivalent to the comment
604 * description.
605 */
606
607 trans_single a = old_final_alignment.get_element(offset->get_coordinate(parent_index));
608 trans_single b = old_final_alignment.get_element(offset->get_current_coordinate());
609 trans_single c = offset->get_element(parent_index);
610
611 trans_single new_offset = follow(a, b, c);
612
613 offset->set_element(index, new_offset);
614 ui::get()->set_offset(new_offset);
615
616 return;
617 }
618
619 /*
620 * Handle other cases.
621 */
622
623 if (get_is_default(index)) {
624 offset->set_element(index, offset->get_element(parent_index));
625 ui::get()->set_offset(offset->get_element(index));
626 }
627 }
628
629 void init_default() {
630
631 if (default_initial_alignment_type == 0) {
632
633 /*
634 * Follow the transformation of the original frame,
635 * setting new image dimensions.
636 */
637
638 // astate->default_initial_alignment = orig_t;
639 default_initial_alignment.set_current_element(orig_t.get_element(0));
640 default_initial_alignment.set_dimensions(input_frame);
641
642 } else if (default_initial_alignment_type == 1)
643
644 /*
645 * Follow previous transformation, setting new image
646 * dimensions.
647 */
648
649 default_initial_alignment.set_dimensions(input_frame);
650
651 else
652 assert(0);
653
654 old_is_default = get_is_default(0);
655 }
656 };
657
658
659 /*
df55d1a2 dhilvert2006-08-30 07:40:00 +0000660 * Check for exclusion region coverage in the reference
661 * array.
662 */
663 static int ref_excluded(int i, int j, point offset, exclusion *params, int param_count) {
664 for (int idx = 0; idx < param_count; idx++)
665 if (params[idx].type == exclusion::RENDER
666 && i + offset[0] >= params[idx].x[0]
667 && i + offset[0] <= params[idx].x[1]
668 && j + offset[1] >= params[idx].x[2]
669 && j + offset[1] <= params[idx].x[3])
670 return 1;
671
672 return 0;
673 }
674
675 /*
676 * Check for exclusion region coverage in the input
677 * array.
678 */
679 static int input_excluded(ale_pos ti, ale_pos tj, exclusion *params, int param_count) {
680 for (int idx = 0; idx < param_count; idx++)
681 if (params[idx].type == exclusion::FRAME
682 && ti >= params[idx].x[0]
683 && ti <= params[idx].x[1]
684 && tj >= params[idx].x[2]
685 && tj <= params[idx].x[3])
686 return 1;
687
688 return 0;
689 }
690
691 /*
4949c031 dhilvert2005-01-07 06:44:00 +0000692 * Overlap function. Determines the number of pixels in areas where
693 * the arrays overlap. Uses the reference array's notion of pixel
694 * positions.
695 */
696 static unsigned int overlap(struct scale_cluster c, transformation t, int ax_count) {
697 assert (reference_image);
698
699 unsigned int result = 0;
700
701 point offset = c.accum->offset();
702
703 for (unsigned int i = 0; i < c.accum->height(); i++)
704 for (unsigned int j = 0; j < c.accum->width(); j++) {
705
df55d1a2 dhilvert2006-08-30 07:40:00 +0000706 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
4949c031 dhilvert2005-01-07 06:44:00 +0000707 continue;
708
709 /*
710 * Transform
711 */
712
713 struct point q;
714
07271611 dhilvert2005-01-07 06:48:00 +0000715 q = (c.input_scale < 1.0 && interpolant == NULL)
716 ? t.scaled_inverse_transform(
717 point(i + offset[0], j + offset[1]))
718 : t.unscaled_inverse_transform(
4949c031 dhilvert2005-01-07 06:44:00 +0000719 point(i + offset[0], j + offset[1]));
720
721 ale_pos ti = q[0];
722 ale_pos tj = q[1];
723
724 /*
725 * Check that the transformed coordinates are within
726 * the boundaries of array c.input, and check that the
727 * weight value in the accumulated array is nonzero,
728 * unless we know it is nonzero by virtue of the fact
729 * that it falls within the region of the original
730 * frame (e.g. when we're not increasing image
df55d1a2 dhilvert2006-08-30 07:40:00 +0000731 * extents). Also check for frame exclusion.
4949c031 dhilvert2005-01-07 06:44:00 +0000732 */
733
df55d1a2 dhilvert2006-08-30 07:40:00 +0000734 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
735 continue;
736
4949c031 dhilvert2005-01-07 06:44:00 +0000737 if (ti >= 0
738 && ti <= c.input->height() - 1
739 && tj >= 0
740 && tj <= c.input->width() - 1
580b5321 David Hilvert2007-09-10 17:35:00 +0000741 && c.certainty->get_pixel(i, j)[0] != 0)
4949c031 dhilvert2005-01-07 06:44:00 +0000742 result++;
743 }
744
745 return result;
746 }
747
748 /*
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000749 * Monte carlo iteration class.
750 *
751 * Monte Carlo alignment has been used for statistical comparisons in
752 * spatial registration, and is now used for tonal registration
753 * and final match calculation.
754 */
755
756 /*
757 * We use a random process for which the expected number of sampled
758 * pixels is +/- .000003 from the coverage in the range [.005,.995] for
759 * an image with 100,000 pixels. (The actual number may still deviate
760 * from the expected number by more than this amount, however.) The
761 * method is as follows:
762 *
763 * We have coverage == USE/ALL, or (expected # pixels to use)/(# total
764 * pixels). We derive from this SKIP/USE.
765 *
766 * SKIP/USE == (SKIP/ALL)/(USE/ALL) == (1 - (USE/ALL))/(USE/ALL)
767 *
768 * Once we have SKIP/USE, we know the expected number of pixels to skip
769 * in each iteration. We use a random selection process that provides
770 * SKIP/USE close to this calculated value.
771 *
772 * If we can draw uniformly to select the number of pixels to skip, we
773 * do. In this case, the maximum number of pixels to skip is twice the
774 * expected number.
775 *
776 * If we cannot draw uniformly, we still assign equal probability to
777 * each of the integer values in the interval [0, 2 * (SKIP/USE)], but
778 * assign an unequal amount to the integer value ceil(2 * SKIP/USE) +
779 * 1.
780 */
781
782 /*
783 * When reseeding the random number generator, we want the same set of
784 * pixels to be used in cases where two alignment options are compared.
785 * If we wanted to avoid bias from repeatedly utilizing the same seed,
786 * we could seed with the number of the frame most recently aligned:
787 *
788 * srand(latest);
789 *
790 * However, in cursory tests, it seems okay to just use the default
791 * seed of 1, and so we do this, since it is simpler; both of these
792 * approaches to reseeding achieve better results than not reseeding.
793 * (1 is the default seed according to the GNU Manual Page for
794 * rand(3).)
795 *
796 * For subdomain calculations, we vary the seed by adding the subdomain
797 * index.
798 */
799
800 class mc_iterate {
801 ale_pos mc_max;
802 unsigned int index;
803 unsigned int index_max;
804 int i_min;
805 int i_max;
806 int j_min;
807 int j_max;
808
809 rng_t rng;
810
63f46ff7 David Hilvert2007-09-21 00:03:00 +0000811 public:
f0af1fea
DH
David Hilvert2007-09-20 23:22:00 +0000812 mc_iterate(int _i_min, int _i_max, int _j_min, int _j_max, unsigned int subdomain)
813 : rng() {
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000814
815 ale_pos coverage;
816
817 i_min = _i_min;
818 i_max = _i_max;
819 j_min = _j_min;
820 j_max = _j_max;
821
a0c28c9a
DH
David Hilvert2008-03-23 15:55:54 -0500822 if (i_max < i_min || j_max < j_min)
823 index_max = 0;
824 else
825 index_max = (i_max - i_min) * (j_max - j_min);
699711e2 David Hilvert2007-09-20 21:03:00 +0000826
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000827 if (index_max < 500 || _mc > 100 || _mc <= 0)
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000828 coverage = 1;
829 else
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000830 coverage = _mc / 100;
699711e2 David Hilvert2007-09-20 21:03:00 +0000831
a85f57f9 David Hilvert2007-10-15 17:07:00 +0000832 double su = (1 - coverage) / coverage;
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000833
834 mc_max = (floor(2*su) * (1 + floor(2*su)) + 2*su)
835 / (2 + 2 * floor(2*su) - 2*su);
836
837 rng.seed(1 + subdomain);
838
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000839#define FIXED16 3
840#if ALE_COORDINATES == FIXED16
841 /*
842 * XXX: This calculation might not yield the correct
843 * expected value.
844 */
e4a3555e
DH
David Hilvert2007-10-24 22:37:00 +0000845 index = -1 + (int) ceil(((ale_pos) mc_max+1)
846 / (ale_pos) ( (1 + 0xffffff)
847 / (1 + (rng.get() & 0xffffff))));
793fc1a6 David Hilvert2007-10-25 16:36:00 +0000848#else
ff364936 David Hilvert2007-10-26 23:35:00 +0000849 index = -1 + (int) ceil((ale_accum) (mc_max+1)
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000850 * ( (1 + ((ale_accum) (rng.get())) )
851 / (1 + ((ale_accum) RAND_MAX)) ));
852#endif
853#undef FIXED16
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000854 }
855
856 int get_i() {
857 return index / (j_max - j_min) + i_min;
858 }
859
860 int get_j() {
861 return index % (j_max - j_min) + j_min;
862 }
863
63f46ff7 David Hilvert2007-09-21 00:03:00 +0000864 void operator++(int whats_this_for) {
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000865#define FIXED16 3
866#if ALE_COORDINATES == FIXED16
e4a3555e
DH
David Hilvert2007-10-24 22:37:00 +0000867 index += (int) ceil(((ale_pos) mc_max+1)
868 / (ale_pos) ( (1 + 0xffffff)
869 / (1 + (rng.get() & 0xffffff))));
793fc1a6 David Hilvert2007-10-25 16:36:00 +0000870#else
ff364936 David Hilvert2007-10-26 23:35:00 +0000871 index += (int) ceil((ale_accum) (mc_max+1)
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000872 * ( (1 + ((ale_accum) (rng.get())) )
873 / (1 + ((ale_accum) RAND_MAX)) ));
874#endif
875#undef FIXED16
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000876 }
877
878 int done() {
879 return (index >= index_max);
880 }
881 };
882
883 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000884 * Not-quite-symmetric difference function. Determines the difference in areas
4949c031 dhilvert2005-01-07 06:44:00 +0000885 * where the arrays overlap. Uses the reference array's notion of pixel positions.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000886 *
887 * For the purposes of determining the difference, this function divides each
888 * pixel value by the corresponding image's average pixel magnitude, unless we
889 * are:
890 *
891 * a) Extending the boundaries of the image, or
892 *
893 * b) following the previous frame's transform
894 *
895 * If we are doing monte-carlo pixel sampling for alignment, we
896 * typically sample a subset of available pixels; otherwise, we sample
897 * all pixels.
898 *
899 */
4707675e dhilvert2006-10-19 10:24:00 +0000900
f8864302
DH
David Hilvert2008-04-11 18:15:57 +0000901 template<class diff_trans>
902 class diff_stat_generic {
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000903
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000904 transformation::elem_bounds_t elem_bounds;
e492922d David Hilvert2007-05-09 05:53:00 +0000905
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000906 struct run {
907
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000908 diff_trans offset;
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000909
910 ale_accum result;
911 ale_accum divisor;
912
913 point max, min;
914 ale_accum centroid[2], centroid_divisor;
915 ale_accum de_centroid[2], de_centroid_v, de_sum;
916
5d53e401 David Hilvert2007-05-02 03:12:00 +0000917 void init() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000918
919 result = 0;
920 divisor = 0;
e492922d David Hilvert2007-05-09 05:53:00 +0000921
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000922 min = point::posinf();
923 max = point::neginf();
924
925 centroid[0] = 0;
926 centroid[1] = 0;
927 centroid_divisor = 0;
928
929 de_centroid[0] = 0;
930 de_centroid[1] = 0;
931
932 de_centroid_v = 0;
933
934 de_sum = 0;
935 }
936
1b980378 David Hilvert2008-07-18 18:30:40 +0000937 void init(diff_trans _offset) {
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +0000938 offset = _offset;
939 init();
940 }
941
942 /*
943 * Required for STL sanity.
944 */
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000945 run() : offset(diff_trans::eu_identity()) {
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +0000946 init();
947 }
948
1b980378
DH
David Hilvert2008-07-18 18:30:40 +0000949 run(diff_trans _offset) : offset(_offset) {
950 init(_offset);
e492922d
DH
David Hilvert2007-05-09 05:53:00 +0000951 }
952
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000953 void add(const run &_run) {
954 result += _run.result;
955 divisor += _run.divisor;
956
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000957 for (int d = 0; d < 2; d++) {
958 if (min[d] > _run.min[d])
959 min[d] = _run.min[d];
960 if (max[d] < _run.max[d])
961 max[d] = _run.max[d];
962 centroid[d] += _run.centroid[d];
963 de_centroid[d] += _run.de_centroid[d];
964 }
965
966 centroid_divisor += _run.centroid_divisor;
967 de_centroid_v += _run.de_centroid_v;
968 de_sum += _run.de_sum;
969 }
970
283c3ecc David Hilvert2008-01-26 01:36:00 +0000971 run(const run &_run) : offset(_run.offset) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000972
973 /*
974 * Initialize
975 */
1b980378 David Hilvert2008-07-18 18:30:40 +0000976 init(_run.offset);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000977
978 /*
979 * Add
980 */
981 add(_run);
982 }
983
984 run &operator=(const run &_run) {
985
986 /*
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000987 * Initialize
988 */
1b980378 David Hilvert2008-07-18 18:30:40 +0000989 init(_run.offset);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000990
991 /*
992 * Add
993 */
994 add(_run);
995
996 return *this;
997 }
998
999 ~run() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001000 }
1001
1002 ale_accum get_error() const {
c9968081 David Hilvert2007-10-24 02:54:00 +00001003 return pow(result / divisor, 1/(ale_accum) metric_exponent);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001004 }
1005
368d214e
DH
David Hilvert2007-05-09 07:57:00 +00001006 void sample(int f, scale_cluster c, int i, int j, point t, point u,
1007 const run &comparison) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001008
1009 pixel pa = c.accum->get_pixel(i, j);
1010
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001011 ale_real this_result[2] = { 0, 0 };
1012 ale_real this_divisor[2] = { 0, 0 };
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001013
f064b1a9
DH
David Hilvert2007-09-21 21:21:00 +00001014 pixel p[2];
1015 pixel weight[2];
1016 weight[0] = pixel(1, 1, 1);
1017 weight[1] = pixel(1, 1, 1);
1018
ca7acd56 David Hilvert2008-06-05 23:43:51 +00001019 pixel tm = offset.get_tonal_multiplier(point(i, j) + c.accum->offset());
28e6b6f7 David Hilvert2008-06-05 02:36:34 +00001020
1e559234 David Hilvert2007-09-11 19:34:00 +00001021 if (interpolant != NULL) {
4132897c
DH
David Hilvert2007-10-26 18:13:00 +00001022 interpolant->filtered(i, j, &p[0], &weight[0], 1, f);
1023
fa3844c7 David Hilvert2007-10-26 18:39:00 +00001024 if (weight[0].min_norm() > ale_real_weight_floor) {
4132897c
DH
David Hilvert2007-10-26 18:13:00 +00001025 p[0] /= weight[0];
1026 } else {
1027 return;
1028 }
1029
1e559234 David Hilvert2007-09-11 19:34:00 +00001030 } else {
e7f30dec David Hilvert2007-09-21 19:25:00 +00001031 p[0] = c.input->get_bl(t);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001032 }
1033
28e6b6f7 David Hilvert2008-06-05 02:36:34 +00001034 p[0] *= tm;
64e05da1 David Hilvert2008-05-05 16:21:18 -05001035
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001036 if (u.defined()) {
19b07c65 David Hilvert2007-09-11 18:07:00 +00001037 p[1] = c.input->get_bl(u);
28e6b6f7 David Hilvert2008-06-05 02:36:34 +00001038 p[1] *= tm;
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001039 }
1040
1041
1042 /*
1043 * Handle certainty.
1044 */
1045
f064b1a9 David Hilvert2007-09-21 21:21:00 +00001046 if (certainty_weights == 1) {
32ec9768
DH
David Hilvert2007-09-21 23:14:00 +00001047
1048 /*
1049 * For speed, use arithmetic interpolation (get_bl(.))
1050 * instead of geometric (get_bl(., 1))
1051 */
1052
1053 weight[0] *= c.input_certainty->get_bl(t);
c4fb894c David Hilvert2007-09-21 22:44:00 +00001054 if (u.defined())
32ec9768 David Hilvert2007-09-21 23:14:00 +00001055 weight[1] *= c.input_certainty->get_bl(u);
e7f30dec
DH
David Hilvert2007-09-21 19:25:00 +00001056 weight[0] *= c.certainty->get_pixel(i, j);
1057 weight[1] *= c.certainty->get_pixel(i, j);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001058 }
1059
1060 if (c.aweight != NULL) {
1061 weight[0] *= c.aweight->get_pixel(i, j);
1062 weight[1] *= c.aweight->get_pixel(i, j);
1063 }
1064
1065 /*
1066 * Update sampling area statistics
1067 */
1068
1069 if (min[0] > i)
1070 min[0] = i;
1071 if (min[1] > j)
1072 min[1] = j;
1073 if (max[0] < i)
1074 max[0] = i;
1075 if (max[1] < j)
1076 max[1] = j;
1077
1078 centroid[0] += (weight[0][0] + weight[0][1] + weight[0][2]) * i;
1079 centroid[1] += (weight[0][0] + weight[0][1] + weight[0][2]) * j;
1080 centroid_divisor += (weight[0][0] + weight[0][1] + weight[0][2]);
1081
1082 /*
1083 * Determine alignment type.
1084 */
1085
1086 for (int m = 0; m < (u.defined() ? 2 : 1); m++)
1087 if (channel_alignment_type == 0) {
1088 /*
1089 * Align based on all channels.
1090 */
1091
1092
1093 for (int k = 0; k < 3; k++) {
1094 ale_real achan = pa[k];
1095 ale_real bchan = p[m][k];
1096
1097 this_result[m] += weight[m][k] * pow(fabs(achan - bchan), metric_exponent);
1098 this_divisor[m] += weight[m][k] * pow(achan > bchan ? achan : bchan, metric_exponent);
1099 }
1100 } else if (channel_alignment_type == 1) {
1101 /*
1102 * Align based on the green channel.
1103 */
1104
1105 ale_real achan = pa[1];
1106 ale_real bchan = p[m][1];
1107
1108 this_result[m] = weight[m][1] * pow(fabs(achan - bchan), metric_exponent);
1109 this_divisor[m] = weight[m][1] * pow(achan > bchan ? achan : bchan, metric_exponent);
1110 } else if (channel_alignment_type == 2) {
1111 /*
1112 * Align based on the sum of all channels.
1113 */
1114
1115 ale_real asum = 0;
1116 ale_real bsum = 0;
1117 ale_real wsum = 0;
1118
1119 for (int k = 0; k < 3; k++) {
1120 asum += pa[k];
1121 bsum += p[m][k];
1122 wsum += weight[m][k] / 3;
1123 }
1124
1125 this_result[m] = wsum * pow(fabs(asum - bsum), metric_exponent);
1126 this_divisor[m] = wsum * pow(asum > bsum ? asum : bsum, metric_exponent);
1127 }
1128
1129 if (u.defined()) {
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001130// ale_real de = fabs(this_result[0] / this_divisor[0]
1131// - this_result[1] / this_divisor[1]);
1132 ale_real de = fabs(this_result[0] - this_result[1]);
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001133
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001134 de_centroid[0] += de * (ale_real) i;
1135 de_centroid[1] += de * (ale_real) j;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001136
42772195 David Hilvert2007-10-21 15:36:00 +00001137 de_centroid_v += de * (ale_real) t.lengthto(u);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001138
1139 de_sum += de;
1140 }
1141
1142 result += (this_result[0]);
1143 divisor += (this_divisor[0]);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001144 }
1145
1146 void rescale(ale_pos scale) {
1147 offset.rescale(scale);
1148
1149 de_centroid[0] *= scale;
1150 de_centroid[1] *= scale;
1151 de_centroid_v *= scale;
1152 }
1153
1154 point get_centroid() {
1155 point result = point(centroid[0] / centroid_divisor, centroid[1] / centroid_divisor);
1156
1157 assert (finite(centroid[0])
1158 && finite(centroid[1])
1159 && (result.defined() || centroid_divisor == 0));
1160
1161 return result;
1162 }
1163
1164 point get_error_centroid() {
1165 point result = point(de_centroid[0] / de_sum, de_centroid[1] / de_sum);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001166 return result;
1167 }
1168
1169
1170 ale_pos get_error_perturb() {
1171 ale_pos result = de_centroid_v / de_sum;
1172
1173 return result;
1174 }
1175
1176 };
1177
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001178 /*
1179 * When non-empty, runs.front() is best, runs.back() is
1180 * testing.
1181 */
1182
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001183 std::vector<run> runs;
1184
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001185 /*
1186 * old_runs stores the latest available perturbation set for
1187 * each multi-alignment element.
1188 */
1189
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001190 typedef int run_index;
30ea890d David Hilvert2007-05-14 20:54:00 +00001191 std::map<run_index, run> old_runs;
5d53e401 David Hilvert2007-05-02 03:12:00 +00001192
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001193 static void *diff_subdomain(void *args);
1194
1195 struct subdomain_args {
1196 struct scale_cluster c;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001197 std::vector<run> runs;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001198 int ax_count;
1199 int f;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001200 int i_min, i_max, j_min, j_max;
1201 int subdomain;
1202 };
1203
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001204 struct scale_cluster si;
1205 int ax_count;
1206 int frame;
1207
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001208 std::vector<ale_pos> perturb_multipliers;
1209
30ea890d David Hilvert2007-05-14 20:54:00 +00001210public:
1b980378 David Hilvert2008-07-18 18:30:40 +00001211 void diff(struct scale_cluster c, const diff_trans &t,
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001212 int _ax_count, int f) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001213
1214 if (runs.size() == 2)
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001215 runs.pop_back();
1216
1b980378 David Hilvert2008-07-18 18:30:40 +00001217 runs.push_back(run(t));
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001218
1219 si = c;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001220 ax_count = _ax_count;
1221 frame = f;
1222
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001223 ui::get()->d2_align_sample_start();
1224
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001225 if (interpolant != NULL) {
1226
1227 /*
1228 * XXX: This has not been tested, and may be completely
1229 * wrong.
1230 */
1231
1232 transformation tt = transformation::eu_identity();
1233 tt.set_current_element(t);
1234 interpolant->set_parameters(tt, c.input, c.accum->offset());
1235 }
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001236
1237 int N;
1238#ifdef USE_PTHREAD
1239 N = thread::count();
1240
1241 pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t) * N);
1242 pthread_attr_t *thread_attr = (pthread_attr_t *) malloc(sizeof(pthread_attr_t) * N);
1243
1244#else
1245 N = 1;
1246#endif
1247
1248 subdomain_args *args = new subdomain_args[N];
1249
d790f7da David Hilvert2008-05-02 18:59:43 -05001250 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 +00001251
a7ee2759
DH
David Hilvert2008-03-17 17:05:06 -05001252// fprintf(stdout, "[%d %d] [%d %d]\n",
1253// global_i_min, global_i_max, global_j_min, global_j_max);
e55e5de1 David Hilvert2008-02-14 01:08:00 +00001254
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001255 for (int ti = 0; ti < N; ti++) {
1256 args[ti].c = c;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001257 args[ti].runs = runs;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001258 args[ti].ax_count = ax_count;
1259 args[ti].f = f;
d790f7da
DH
David Hilvert2008-05-02 18:59:43 -05001260 args[ti].i_min = b.imin + ((b.imax - b.imin) * ti) / N;
1261 args[ti].i_max = b.imin + ((b.imax - b.imin) * (ti + 1)) / N;
1262 args[ti].j_min = b.jmin;
1263 args[ti].j_max = b.jmax;
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001264 args[ti].subdomain = ti;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001265#ifdef USE_PTHREAD
1266 pthread_attr_init(&thread_attr[ti]);
1267 pthread_attr_setdetachstate(&thread_attr[ti], PTHREAD_CREATE_JOINABLE);
1268 pthread_create(&threads[ti], &thread_attr[ti], diff_subdomain, &args[ti]);
1269#else
1270 diff_subdomain(&args[ti]);
1271#endif
1272 }
1273
1274 for (int ti = 0; ti < N; ti++) {
1275#ifdef USE_PTHREAD
1276 pthread_join(threads[ti], NULL);
1277#endif
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001278 runs.back().add(args[ti].runs.back());
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001279 }
1280
44a1d1de
DH
David Hilvert2009-03-30 19:02:57 +00001281#ifdef USE_PTHREAD
1282 free(threads);
1283 free(thread_attr);
1284#endif
1285
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001286 delete[] args;
1287
1288 ui::get()->d2_align_sample_stop();
1289
1290 }
1291
1292 private:
1293 void rediff() {
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001294 std::vector<diff_trans> t_array;
b971d971 David Hilvert2006-12-26 05:25:00 +00001295
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001296 for (unsigned int r = 0; r < runs.size(); r++) {
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001297 t_array.push_back(runs[r].offset);
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001298 }
b971d971 David Hilvert2006-12-26 05:25:00 +00001299
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001300 runs.clear();
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001301
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001302 for (unsigned int r = 0; r < t_array.size(); r++)
1b980378 David Hilvert2008-07-18 18:30:40 +00001303 diff(si, t_array[r], ax_count, frame);
86c0d2ba dhilvert2006-10-25 14:42:00 +00001304 }
1305
400c7826 David Hilvert2007-04-20 07:06:00 +00001306
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001307 public:
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001308 int better() {
1309 assert(runs.size() >= 2);
1310 assert(runs[0].offset.scale() == runs[1].offset.scale());
86c0d2ba dhilvert2006-10-25 14:42:00 +00001311
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001312 return (runs[1].get_error() < runs[0].get_error()
1313 || (!finite(runs[0].get_error()) && finite(runs[1].get_error())));
08151f52 dhilvert2006-10-25 17:36:00 +00001314 }
1315
e0577945
DH
David Hilvert2008-07-19 22:11:55 +00001316 int better_defined() {
1317 assert(runs.size() >= 2);
1318 assert(runs[0].offset.scale() == runs[1].offset.scale());
1319
1320 return (runs[1].get_error() < runs[0].get_error());
1321 }
1322
f8864302 David Hilvert2008-04-11 18:15:57 +00001323 diff_stat_generic(transformation::elem_bounds_t e)
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001324 : runs(), old_runs(), perturb_multipliers() {
1325 elem_bounds = e;
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001326 }
1327
1328 run_index get_run_index(unsigned int perturb_index) {
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001329 return perturb_index;
30ea890d David Hilvert2007-05-14 20:54:00 +00001330 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001331
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001332 run &get_run(unsigned int perturb_index) {
1333 run_index index = get_run_index(perturb_index);
dc426169 David Hilvert2007-04-25 06:50:00 +00001334
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001335 assert(old_runs.count(index));
1336 return old_runs[index];
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001337 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001338
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001339 void rescale(ale_pos scale, scale_cluster _si) {
1340 assert(runs.size() == 1);
86c0d2ba dhilvert2006-10-25 14:42:00 +00001341
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001342 si = _si;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001343
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001344 runs[0].rescale(scale);
1345
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001346 rediff();
1347 }
1348
f8864302 David Hilvert2008-04-11 18:15:57 +00001349 ~diff_stat_generic() {
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001350 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001351
f8864302 David Hilvert2008-04-11 18:15:57 +00001352 diff_stat_generic &operator=(const diff_stat_generic &dst) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001353 /*
1354 * Copy run information.
1355 */
1356 runs = dst.runs;
82db7fe6 David Hilvert2007-05-05 18:29:00 +00001357 old_runs = dst.old_runs;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001358
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001359 /*
1360 * Copy diff variables
1361 */
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001362 si = dst.si;
1363 ax_count = dst.ax_count;
1364 frame = dst.frame;
50a9f51d David Hilvert2007-05-03 05:16:00 +00001365 perturb_multipliers = dst.perturb_multipliers;
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001366 elem_bounds = dst.elem_bounds;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001367
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001368 return *this;
1369 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001370
f8864302 David Hilvert2008-04-11 18:15:57 +00001371 diff_stat_generic(const diff_stat_generic &dst) : runs(), old_runs(),
ca7b6c30 David Hilvert2007-05-06 02:42:00 +00001372 perturb_multipliers() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001373 operator=(dst);
1374 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001375
1ed23c0d
DH
David Hilvert2008-03-09 11:23:00 +00001376 void set_elem_bounds(transformation::elem_bounds_t e) {
1377 elem_bounds = e;
1378 }
1379
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001380 ale_accum get_result() {
1381 assert(runs.size() == 1);
1382 return runs[0].result;
1383 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001384
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001385 ale_accum get_divisor() {
1386 assert(runs.size() == 1);
1387 return runs[0].divisor;
1388 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001389
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001390 diff_trans get_offset() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001391 assert(runs.size() == 1);
1392 return runs[0].offset;
1393 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001394
f8864302 David Hilvert2008-04-11 18:15:57 +00001395 int operator!=(diff_stat_generic &param) {
65886ff7 David Hilvert2007-09-04 02:10:00 +00001396 return (get_error() != param.get_error());
86c0d2ba dhilvert2006-10-25 14:42:00 +00001397 }
08151f52 dhilvert2006-10-25 17:36:00 +00001398
f8864302 David Hilvert2008-04-11 18:15:57 +00001399 int operator==(diff_stat_generic &param) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001400 return !(operator!=(param));
1401 }
08151f52 dhilvert2006-10-25 17:36:00 +00001402
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001403 ale_pos get_error_perturb() {
1404 assert(runs.size() == 1);
1405 return runs[0].get_error_perturb();
08151f52 dhilvert2006-10-25 17:36:00 +00001406 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001407
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001408 ale_accum get_error() const {
1409 assert(runs.size() == 1);
1410 return runs[0].get_error();
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001411 }
dda1bf79 dhilvert2006-10-22 18:40:00 +00001412
30ea890d David Hilvert2007-05-14 20:54:00 +00001413 public:
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001414 /*
1415 * Get the set of transformations produced by a given perturbation
1416 */
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001417 void get_perturb_set(std::vector<diff_trans> *set,
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001418 ale_pos adj_p, ale_pos adj_o, ale_pos adj_b,
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001419 ale_pos *current_bd, ale_pos *modified_bd,
1420 std::vector<ale_pos> multipliers = std::vector<ale_pos>()) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001421
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001422 assert(runs.size() == 1);
dda1bf79 dhilvert2006-10-22 18:40:00 +00001423
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001424 diff_trans test_t(diff_trans::eu_identity());
dda1bf79 dhilvert2006-10-22 18:40:00 +00001425
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001426 /*
1427 * Translational or euclidean transformation
1428 */
2aa417e6 dhilvert2005-01-07 06:44:00 +00001429
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001430 for (unsigned int i = 0; i < 2; i++)
1431 for (unsigned int s = 0; s < 2; s++) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001432
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001433 if (!multipliers.size())
1434 multipliers.push_back(1);
dc426169 David Hilvert2007-04-25 06:50:00 +00001435
b2e7131e David Hilvert2007-05-02 08:35:00 +00001436 assert(finite(multipliers[0]));
5d53e401 David Hilvert2007-05-02 03:12:00 +00001437
b2e7131e David Hilvert2007-05-02 08:35:00 +00001438 test_t = get_offset();
dc426169 David Hilvert2007-04-25 06:50:00 +00001439
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001440 // test_t.eu_modify(i, (s ? -adj_p : adj_p) * multipliers[0]);
1441 test_t.translate((i ? point(1, 0) : point(0, 1))
1442 * (s ? -adj_p : adj_p)
1443 * multipliers[0]);
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001444
1445 test_t.snap(adj_p / 2);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001446
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001447 set->push_back(test_t);
1448 multipliers.erase(multipliers.begin());
46f9776a dhilvert2005-01-07 06:44:00 +00001449
b2e7131e David Hilvert2007-05-02 08:35:00 +00001450 }
4707675e dhilvert2006-10-19 10:24:00 +00001451
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001452 if (alignment_class > 0)
1453 for (unsigned int s = 0; s < 2; s++) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001454
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001455 if (!multipliers.size())
1456 multipliers.push_back(1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001457
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001458 assert(multipliers.size());
1459 assert(finite(multipliers[0]));
5d53e401 David Hilvert2007-05-02 03:12:00 +00001460
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001461 if (!(adj_o * multipliers[0] < rot_max))
1462 return;
4707675e dhilvert2006-10-19 10:24:00 +00001463
b2e7131e David Hilvert2007-05-02 08:35:00 +00001464 ale_pos adj_s = (s ? 1 : -1) * adj_o * multipliers[0];
5d53e401 David Hilvert2007-05-02 03:12:00 +00001465
b2e7131e David Hilvert2007-05-02 08:35:00 +00001466 test_t = get_offset();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001467
30ea890d David Hilvert2007-05-14 20:54:00 +00001468 run_index ori = get_run_index(set->size());
b2e7131e David Hilvert2007-05-02 08:35:00 +00001469 point centroid = point::undefined();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001470
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001471 if (!old_runs.count(ori))
1472 ori = get_run_index(0);
5d53e401 David Hilvert2007-05-02 03:12:00 +00001473
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001474 if (!centroid.finite() && old_runs.count(ori)) {
1475 centroid = old_runs[ori].get_error_centroid();
5d53e401 David Hilvert2007-05-02 03:12:00 +00001476
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001477 if (!centroid.finite())
1478 centroid = old_runs[ori].get_centroid();
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001479
1480 centroid *= test_t.scale()
1481 / old_runs[ori].offset.scale();
b2e7131e David Hilvert2007-05-02 08:35:00 +00001482 }
5d53e401 David Hilvert2007-05-02 03:12:00 +00001483
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001484 if (!centroid.finite() && !test_t.is_projective()) {
1485 test_t.eu_modify(2, adj_s);
1486 } else if (!centroid.finite()) {
1487 centroid = point(si.input->height() / 2,
1488 si.input->width() / 2);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001489
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001490 test_t.rotate(centroid + si.accum->offset(),
1491 adj_s);
1492 } else {
1493 test_t.rotate(centroid + si.accum->offset(),
1494 adj_s);
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001495 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001496
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001497 test_t.snap(adj_p / 2);
1498
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001499 set->push_back(test_t);
1500 multipliers.erase(multipliers.begin());
1501 }
1502
1503 if (alignment_class == 2) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001504
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001505 /*
1506 * Projective transformation
1507 */
30afe4b6 dhilvert2005-01-07 06:42:00 +00001508
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001509 for (unsigned int i = 0; i < 4; i++)
1510 for (unsigned int j = 0; j < 2; j++)
1511 for (unsigned int s = 0; s < 2; s++) {
1512
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001513 if (!multipliers.size())
1514 multipliers.push_back(1);
1515
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001516 assert(multipliers.size());
1517 assert(finite(multipliers[0]));
46f9776a dhilvert2005-01-07 06:44:00 +00001518
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001519 ale_pos adj_s = (s ? -1 : 1) * adj_p * multipliers [0];
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001520
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001521 test_t = get_offset();
46f9776a dhilvert2005-01-07 06:44:00 +00001522
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001523 if (perturb_type == 0)
73f0dc5c David Hilvert2008-08-18 17:37:54 -05001524 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 +00001525 else if (perturb_type == 1)
1526 test_t.gr_modify(j, i, adj_s);
1527 else
1528 assert(0);
dc426169 David Hilvert2007-04-25 06:50:00 +00001529
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001530 test_t.snap(adj_p / 2);
1531
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001532 set->push_back(test_t);
1533 multipliers.erase(multipliers.begin());
1534 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001535
b2e7131e David Hilvert2007-05-02 08:35:00 +00001536 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001537
49a3a0b4 David Hilvert2007-04-01 07:13:00 +00001538 /*
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001539 * Barrel distortion
49a3a0b4
DH
David Hilvert2007-04-01 07:13:00 +00001540 */
1541
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001542 if (bda_mult != 0 && adj_b != 0) {
7a696eb1 David Hilvert2007-04-01 06:41:00 +00001543
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001544 for (unsigned int d = 0; d < get_offset().bd_count(); d++)
1545 for (unsigned int s = 0; s < 2; s++) {
1546
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001547 if (!multipliers.size())
1548 multipliers.push_back(1);
1549
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001550 assert (multipliers.size());
1551 assert (finite(multipliers[0]));
1552
1553 ale_pos adj_s = (s ? -1 : 1) * adj_b * multipliers[0];
1554
1555 if (bda_rate > 0 && fabs(modified_bd[d] + adj_s - current_bd[d]) > bda_rate)
1556 continue;
1557
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001558 diff_trans test_t = get_offset();
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001559
1560 test_t.bd_modify(d, adj_s);
1561
1562 set->push_back(test_t);
1563 }
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001564 }
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001565 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001566
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001567 void confirm() {
1568 assert(runs.size() == 2);
1569 runs[0] = runs[1];
1570 runs.pop_back();
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001571 }
1572
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001573 void discard() {
1574 assert(runs.size() == 2);
1575 runs.pop_back();
1576 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001577
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001578 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 +00001579 ale_pos *current_bd, ale_pos *modified_bd, int stable) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001580
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001581 assert(runs.size() == 1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001582
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001583 std::vector<diff_trans> t_set;
4707675e dhilvert2006-10-19 10:24:00 +00001584
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001585 if (perturb_multipliers.size() == 0) {
1586 get_perturb_set(&t_set, adj_p, adj_o, adj_b,
1587 current_bd, modified_bd);
1588
1589 for (unsigned int i = 0; i < t_set.size(); i++) {
f8864302 David Hilvert2008-04-11 18:15:57 +00001590 diff_stat_generic test = *this;
50a9f51d David Hilvert2007-05-03 05:16:00 +00001591
1b980378 David Hilvert2008-07-18 18:30:40 +00001592 test.diff(si, t_set[i], ax_count, frame);
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001593
1594 test.confirm();
1595
42772195 David Hilvert2007-10-21 15:36:00 +00001596 if (finite(test.get_error_perturb()))
82db7fe6
DH
David Hilvert2007-05-05 18:29:00 +00001597 perturb_multipliers.push_back(adj_p / test.get_error_perturb());
1598 else
1599 perturb_multipliers.push_back(1);
1600
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001601 }
1602
1603 t_set.clear();
1604 }
1605
5d53e401 David Hilvert2007-05-02 03:12:00 +00001606 get_perturb_set(&t_set, adj_p, adj_o, adj_b, current_bd, modified_bd,
50a9f51d David Hilvert2007-05-03 05:16:00 +00001607 perturb_multipliers);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001608
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001609 int found_unreliable = 1;
1610 std::vector<int> tested(t_set.size(), 0);
dc426169 David Hilvert2007-04-25 06:50:00 +00001611
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001612 for (unsigned int i = 0; i < t_set.size(); i++) {
1613 run_index ori = get_run_index(i);
1614
1615 /*
1616 * Check for stability
1617 */
1618 if (stable
1619 && old_runs.count(ori)
1620 && old_runs[ori].offset == t_set[i])
1621 tested[i] = 1;
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001622 }
1623
1624 std::vector<ale_pos> perturb_multipliers_original = perturb_multipliers;
1625
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001626 while (found_unreliable) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001627
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001628 found_unreliable = 0;
08151f52 dhilvert2006-10-25 17:36:00 +00001629
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001630 for (unsigned int i = 0; i < t_set.size(); i++) {
4d806213 dhilvert2006-10-23 17:58:00 +00001631
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001632 if (tested[i])
1633 continue;
b410ef51 dhilvert2006-10-23 15:30:00 +00001634
1b980378 David Hilvert2008-07-18 18:30:40 +00001635 diff(si, t_set[i], ax_count, frame);
7e87bd8e dhilvert2006-10-23 06:39:00 +00001636
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001637 if (!(i < perturb_multipliers.size())
1638 || !finite(perturb_multipliers[i])) {
5d53e401 David Hilvert2007-05-02 03:12:00 +00001639
50a9f51d David Hilvert2007-05-03 05:16:00 +00001640 perturb_multipliers.resize(i + 1);
5d53e401 David Hilvert2007-05-02 03:12:00 +00001641
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001642 if (finite(perturb_multipliers[i])
1643 && finite(adj_p)
1644 && finite(adj_p / runs[1].get_error_perturb())) {
1645 perturb_multipliers[i] =
1646 adj_p / runs[1].get_error_perturb();
5d53e401 David Hilvert2007-05-02 03:12:00 +00001647
8c886617 David Hilvert2007-05-02 08:39:00 +00001648 found_unreliable = 1;
42772195 David Hilvert2007-10-21 15:36:00 +00001649 } else
858b0722 David Hilvert2007-10-03 20:44:00 +00001650 perturb_multipliers[i] = 1;
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001651
1652 continue;
1653 }
1654
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001655 run_index ori = get_run_index(i);
1656
1657 if (old_runs.count(ori) == 0)
1658 old_runs.insert(std::pair<run_index, run>(ori, runs[1]));
1659 else
1660 old_runs[ori] = runs[1];
5d53e401 David Hilvert2007-05-02 03:12:00 +00001661
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001662 if (finite(perturb_multipliers_original[i])
1663 && finite(runs[1].get_error_perturb())
1664 && finite(adj_p)
1665 && finite(perturb_multipliers_original[i] * adj_p / runs[1].get_error_perturb()))
1666 perturb_multipliers[i] = perturb_multipliers_original[i]
1667 * adj_p / runs[1].get_error_perturb();
1668 else
50a9f51d David Hilvert2007-05-03 05:16:00 +00001669 perturb_multipliers[i] = 1;
5d53e401 David Hilvert2007-05-02 03:12:00 +00001670
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001671 tested[i] = 1;
dda1bf79 dhilvert2006-10-22 18:40:00 +00001672
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001673 if (better()
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001674 && runs[1].get_error() < runs[0].get_error()
1675 && perturb_multipliers[i]
1676 / perturb_multipliers_original[i] < 2) {
9e8e62c9
DH
David Hilvert2007-05-13 10:57:00 +00001677 runs[0] = runs[1];
1678 runs.pop_back();
1679 return;
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001680 }
82db7fe6 David Hilvert2007-05-05 18:29:00 +00001681
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001682 }
dda1bf79 dhilvert2006-10-22 18:40:00 +00001683
2077ce22
DH
David Hilvert2007-05-13 09:23:00 +00001684 if (runs.size() > 1)
1685 runs.pop_back();
3aa65890 dhilvert2006-10-25 15:26:00 +00001686
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001687 if (!found_unreliable)
1688 return;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001689 }
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001690 }
08151f52 dhilvert2006-10-25 17:36:00 +00001691
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001692 };
4707675e dhilvert2006-10-19 10:24:00 +00001693
f8864302
DH
David Hilvert2008-04-11 18:15:57 +00001694 typedef diff_stat_generic<trans_single> diff_stat_t;
1695 typedef diff_stat_generic<trans_multi> diff_stat_multi;
1696
4707675e dhilvert2006-10-19 10:24:00 +00001697
30afe4b6 dhilvert2005-01-07 06:42:00 +00001698 /*
1699 * Adjust exposure for an aligned frame B against reference A.
07271611 dhilvert2005-01-07 06:48:00 +00001700 *
1701 * Expects full-LOD images.
1702 *
423af06c
DH
David Hilvert2007-09-10 17:43:00 +00001703 * Note: This method does not use any weighting, by certainty or
1704 * otherwise, in the first exposure registration pass, as any bias of
1705 * weighting according to color may also bias the exposure registration
1706 * result; it does use weighting, including weighting by certainty
1707 * (even if certainty weighting is not specified), in the second pass,
1708 * under the assumption that weighting by certainty improves handling
1709 * of out-of-range highlights, and that bias of exposure measurements
1710 * according to color may generally be less harmful after spatial
1711 * registration has been performed.
30afe4b6 dhilvert2005-01-07 06:42:00 +00001712 */
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001713 class exposure_ratio_iterate : public thread::decompose_domain {
1714 pixel_accum *asums;
1715 pixel_accum *bsums;
1716 pixel_accum *asum;
1717 pixel_accum *bsum;
1718 struct scale_cluster c;
214d014c David Hilvert2008-05-04 22:08:03 -05001719 const transformation &t;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001720 int ax_count;
1721 int pass_number;
1722 protected:
1723 void prepare_subdomains(unsigned int N) {
1724 asums = new pixel_accum[N];
1725 bsums = new pixel_accum[N];
1726 }
1727 void subdomain_algorithm(unsigned int thread,
1728 int i_min, int i_max, int j_min, int j_max) {
1729
1730 point offset = c.accum->offset();
1731
1732 for (mc_iterate m(i_min, i_max, j_min, j_max, thread); !m.done(); m++) {
1733
1734 unsigned int i = (unsigned int) m.get_i();
1735 unsigned int j = (unsigned int) m.get_j();
1736
1737 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
1738 continue;
1739
1740 /*
1741 * Transform
1742 */
1743
1744 struct point q;
1745
1746 q = (c.input_scale < 1.0 && interpolant == NULL)
1747 ? t.scaled_inverse_transform(
1748 point(i + offset[0], j + offset[1]))
1749 : t.unscaled_inverse_transform(
1750 point(i + offset[0], j + offset[1]));
1751
1752 /*
1753 * Check that the transformed coordinates are within
1754 * the boundaries of array c.input, that they are not
1755 * subject to exclusion, and that the weight value in
1756 * the accumulated array is nonzero.
1757 */
1758
1759 if (input_excluded(q[0], q[1], c.ax_parameters, ax_count))
1760 continue;
1761
1762 if (q[0] >= 0
1763 && q[0] <= c.input->height() - 1
1764 && q[1] >= 0
1765 && q[1] <= c.input->width() - 1
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00001766 && ((pixel) c.certainty->get_pixel(i, j)).minabs_norm() != 0) {
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001767 pixel a = c.accum->get_pixel(i, j);
1768 pixel b;
1769
1770 b = c.input->get_bl(q);
1771
1772 pixel weight = ((c.aweight && pass_number)
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00001773 ? (pixel) c.aweight->get_pixel(i, j)
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001774 : pixel(1, 1, 1))
1775 * (pass_number
5c603c78
DH
David Hilvert2007-10-29 04:51:00 +00001776 ? psqrt(c.certainty->get_pixel(i, j)
1777 * c.input_certainty->get_bl(q, 1))
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001778 : pixel(1, 1, 1));
1779
1780 asums[thread] += a * weight;
1781 bsums[thread] += b * weight;
1782 }
1783 }
1784 }
1785
1786 void finish_subdomains(unsigned int N) {
1787 for (unsigned int n = 0; n < N; n++) {
1788 *asum += asums[n];
1789 *bsum += bsums[n];
1790 }
34c6efce
DH
David Hilvert2007-10-23 01:35:00 +00001791 delete[] asums;
1792 delete[] bsums;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001793 }
1794 public:
1795 exposure_ratio_iterate(pixel_accum *_asum,
1796 pixel_accum *_bsum,
1797 struct scale_cluster _c,
214d014c David Hilvert2008-05-04 22:08:03 -05001798 const transformation &_t,
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001799 int _ax_count,
1800 int _pass_number) : decompose_domain(0, _c.accum->height(),
dd761b64
DH
David Hilvert2008-01-26 17:41:00 +00001801 0, _c.accum->width()),
1802 t(_t) {
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001803
1804 asum = _asum;
1805 bsum = _bsum;
1806 c = _c;
214d014c
DH
David Hilvert2008-05-04 22:08:03 -05001807 ax_count = _ax_count;
1808 pass_number = _pass_number;
1809 }
1810
1811 exposure_ratio_iterate(pixel_accum *_asum,
1812 pixel_accum *_bsum,
1813 struct scale_cluster _c,
1814 const transformation &_t,
1815 int _ax_count,
1816 int _pass_number,
1817 transformation::elem_bounds_int_t b) : decompose_domain(b.imin, b.imax,
1818 b.jmin, b.jmax),
1819 t(_t) {
1820
1821 asum = _asum;
1822 bsum = _bsum;
1823 c = _c;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001824 ax_count = _ax_count;
1825 pass_number = _pass_number;
1826 }
1827 };
1828
2aa417e6 dhilvert2005-01-07 06:44:00 +00001829 static void set_exposure_ratio(unsigned int m, struct scale_cluster c,
993fde09 David Hilvert2008-05-05 05:28:56 +00001830 const transformation &t, int ax_count, int pass_number) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001831
3dc20778 dhilvert2005-01-10 23:06:00 +00001832 if (_exp_register == 2) {
1833 /*
1834 * Use metadata only.
1835 */
1836 ale_real gain_multiplier = image_rw::exp(m).get_gain_multiplier();
1837 pixel multiplier = pixel(gain_multiplier, gain_multiplier, gain_multiplier);
1838
1839 image_rw::exp(m).set_multiplier(multiplier);
a9d66b26 dhilvert2005-01-10 23:15:00 +00001840 ui::get()->exp_multiplier(multiplier[0],
1841 multiplier[1],
1842 multiplier[2]);
3d7fd555 dhilvert2005-01-10 23:10:00 +00001843
1844 return;
3dc20778 dhilvert2005-01-10 23:06:00 +00001845 }
1846
70fb02f9 David Hilvert2007-09-21 03:18:00 +00001847 pixel_accum asum(0, 0, 0), bsum(0, 0, 0);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001848
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001849 exposure_ratio_iterate eri(&asum, &bsum, c, t, ax_count, pass_number);
1850 eri.run();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001851
1852 // std::cerr << (asum / bsum) << " ";
07271611 dhilvert2005-01-07 06:48:00 +00001853
1854 pixel_accum new_multiplier;
1855
1856 new_multiplier = asum / bsum * image_rw::exp(m).get_multiplier();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001857
07271611 dhilvert2005-01-07 06:48:00 +00001858 if (finite(new_multiplier[0])
1859 && finite(new_multiplier[1])
1860 && finite(new_multiplier[2])) {
1861 image_rw::exp(m).set_multiplier(new_multiplier);
1862 ui::get()->exp_multiplier(new_multiplier[0],
1863 new_multiplier[1],
1864 new_multiplier[2]);
1865 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001866 }
1867
df55d1a2 dhilvert2006-08-30 07:40:00 +00001868 /*
1869 * Copy all ax parameters.
1870 */
1871 static exclusion *copy_ax_parameters(int local_ax_count, exclusion *source) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001872
df55d1a2 dhilvert2006-08-30 07:40:00 +00001873 exclusion *dest = (exclusion *) malloc(local_ax_count * sizeof(exclusion));
2aa417e6 dhilvert2005-01-07 06:44:00 +00001874
df55d1a2 dhilvert2006-08-30 07:40:00 +00001875 assert (dest);
2aa417e6 dhilvert2005-01-07 06:44:00 +00001876
df55d1a2 dhilvert2006-08-30 07:40:00 +00001877 if (!dest)
07271611 dhilvert2005-01-07 06:48:00 +00001878 ui::get()->memory_error("exclusion regions");
2aa417e6 dhilvert2005-01-07 06:44:00 +00001879
df55d1a2 dhilvert2006-08-30 07:40:00 +00001880 for (int idx = 0; idx < local_ax_count; idx++)
1881 dest[idx] = source[idx];
2aa417e6 dhilvert2005-01-07 06:44:00 +00001882
df55d1a2 dhilvert2006-08-30 07:40:00 +00001883 return dest;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001884 }
1885
df55d1a2 dhilvert2006-08-30 07:40:00 +00001886 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00001887 * Prepare the next level of detail for ordinary images.
1888 */
1889 static const image *prepare_lod(const image *current) {
1890 if (current == NULL)
1891 return NULL;
46f9776a dhilvert2005-01-07 06:44:00 +00001892
2aa417e6 dhilvert2005-01-07 06:44:00 +00001893 return current->scale_by_half("prepare_lod");
1894 }
46f9776a dhilvert2005-01-07 06:44:00 +00001895
2aa417e6 dhilvert2005-01-07 06:44:00 +00001896 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00001897 * Prepare the next level of detail for definition maps.
1898 */
1899 static const image *prepare_lod_def(const image *current) {
7a19e165
DH
David Hilvert2007-09-10 21:16:00 +00001900 if (current == NULL)
1901 return NULL;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001902
1903 return current->defined_scale_by_half("prepare_lod_def");
1904 }
1905
1906 /*
8f2ed1fd David Hilvert2007-09-07 18:36:00 +00001907 * Initialize scale cluster data structures.
2aa417e6 dhilvert2005-01-07 06:44:00 +00001908 */
8f2ed1fd
DH
David Hilvert2007-09-07 18:36:00 +00001909
1910 static void init_nl_cluster(struct scale_cluster *sc) {
1911 }
1912
2aa417e6 dhilvert2005-01-07 06:44:00 +00001913 /*
1914 * Destroy the first element in the scale cluster data structure.
1915 */
a85f57f9 David Hilvert2007-10-15 17:07:00 +00001916 static void final_clusters(struct scale_cluster *scale_clusters, ale_pos scale_factor,
2aa417e6 dhilvert2005-01-07 06:44:00 +00001917 unsigned int steps) {
1918
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001919 if (scale_clusters[0].input_scale < 1.0) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001920 delete scale_clusters[0].input;
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001921 }
2aa417e6 dhilvert2005-01-07 06:44:00 +00001922
44a1d1de
DH
David Hilvert2009-03-30 19:02:57 +00001923 delete scale_clusters[0].input_certainty;
1924
2aa417e6 dhilvert2005-01-07 06:44:00 +00001925 free((void *)scale_clusters[0].ax_parameters);
1926
1927 for (unsigned int step = 1; step < steps; step++) {
1928 delete scale_clusters[step].accum;
580b5321 David Hilvert2007-09-10 17:35:00 +00001929 delete scale_clusters[step].certainty;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001930 delete scale_clusters[step].aweight;
1931
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001932 if (scale_clusters[step].input_scale < 1.0) {
07271611 dhilvert2005-01-07 06:48:00 +00001933 delete scale_clusters[step].input;
c6e3d33a
DH
David Hilvert2007-10-02 15:57:00 +00001934 delete scale_clusters[step].input_certainty;
1935 }
07271611 dhilvert2005-01-07 06:48:00 +00001936
2aa417e6 dhilvert2005-01-07 06:44:00 +00001937 free((void *)scale_clusters[step].ax_parameters);
1938 }
1939
1940 free(scale_clusters);
46f9776a dhilvert2005-01-07 06:44:00 +00001941 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001942
1943 /*
c052e200 dhilvert2005-05-08 16:16:00 +00001944 * Calculate the centroid of a control point for the set of frames
1945 * having index lower than m. Divide by any scaling of the output.
1946 */
1947 static point unscaled_centroid(unsigned int m, unsigned int p) {
1948 assert(_keep);
1949
1950 point point_sum(0, 0);
1951 ale_accum divisor = 0;
1952
1953 for(unsigned int j = 0; j < m; j++) {
1954 point pp = cp_array[p][j];
1955
1956 if (pp.defined()) {
1957 point_sum += kept_t[j].transform_unscaled(pp)
1958 / kept_t[j].scale();
1959 divisor += 1;
1960 }
1961 }
1962
1963 if (divisor == 0)
1964 return point::undefined();
1965
1966 return point_sum / divisor;
1967 }
1968
1969 /*
1970 * Calculate centroid of this frame, and of all previous frames,
1971 * from points common to both sets.
1972 */
1973 static void centroids(unsigned int m, point *current, point *previous) {
1974 /*
1975 * Calculate the translation
1976 */
1977 point other_centroid(0, 0);
1978 point this_centroid(0, 0);
1979 ale_pos divisor = 0;
1980
1981 for (unsigned int i = 0; i < cp_count; i++) {
1982 point other_c = unscaled_centroid(m, i);
1983 point this_c = cp_array[i][m];
1984
1985 if (!other_c.defined() || !this_c.defined())
1986 continue;
1987
1988 other_centroid += other_c;
1989 this_centroid += this_c;
1990 divisor += 1;
1991
1992 }
1993
1994 if (divisor == 0) {
1995 *current = point::undefined();
1996 *previous = point::undefined();
1997 return;
1998 }
1999
2000 *current = this_centroid / divisor;
2001 *previous = other_centroid / divisor;
2002 }
2003
2004 /*
b386e644 dhilvert2005-04-30 09:28:00 +00002005 * Calculate the RMS error of control points for frame m, with
2006 * transformation t, against control points for earlier frames.
2007 */
e812ee44 David Hilvert2007-10-18 18:24:00 +00002008 static ale_pos cp_rms_error(unsigned int m, transformation t) {
b386e644 dhilvert2005-04-30 09:28:00 +00002009 assert (_keep);
2010
2011 ale_accum err = 0;
2012 ale_accum divisor = 0;
2013
2014 for (unsigned int i = 0; i < cp_count; i++)
2015 for (unsigned int j = 0; j < m; j++) {
2016 const point *p = cp_array[i];
936ff6ec dhilvert2005-05-07 20:02:00 +00002017 point p_ref = kept_t[j].transform_unscaled(p[j]);
2018 point p_cur = t.transform_unscaled(p[m]);
b386e644 dhilvert2005-04-30 09:28:00 +00002019
2020 if (!p_ref.defined() || !p_cur.defined())
2021 continue;
2022
2023 err += p_ref.lengthtosq(p_cur);
2024 divisor += 1;
2025 }
2026
e812ee44 David Hilvert2007-10-18 18:24:00 +00002027 return (ale_pos) sqrt(err / divisor);
b386e644 dhilvert2005-04-30 09:28:00 +00002028 }
2029
6126fb3c David Hilvert2007-04-03 08:15:00 +00002030
59e5857b David Hilvert2007-05-08 12:15:00 +00002031 static void test_global(diff_stat_t *here, scale_cluster si, transformation t,
a7882498 David Hilvert2007-10-16 19:48:00 +00002032 int local_ax_count, int m, ale_accum local_gs_mo, ale_pos perturb) {
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00002033
2034 diff_stat_t test(*here);
2035
1b980378 David Hilvert2008-07-18 18:30:40 +00002036 test.diff(si, t.get_current_element(), local_ax_count, m);
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00002037
2038 unsigned int ovl = overlap(si, t, local_ax_count);
2039
2040 if (ovl >= local_gs_mo && test.better()) {
2041 test.confirm();
2042 *here = test;
2043 ui::get()->set_match(here->get_error());
2044 ui::get()->set_offset(here->get_offset());
2045 } else {
2046 test.discard();
2047 }
2048
2049 }
2050
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002051 /*
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002052 * Get the set of global transformations for a given density
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002053 */
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00002054 static void test_globals(diff_stat_t *here,
2055 scale_cluster si, transformation t, int local_gs, ale_pos adj_p,
a7882498 David Hilvert2007-10-16 19:48:00 +00002056 int local_ax_count, int m, ale_accum local_gs_mo, ale_pos perturb) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002057
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002058 transformation offset = t;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002059
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002060 point min, max;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002061
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002062 transformation offset_p = offset;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002063
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002064 if (!offset_p.is_projective())
2065 offset_p.eu_to_gpt();
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002066
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002067 min = max = offset_p.gpt_get(0);
2068 for (int p_index = 1; p_index < 4; p_index++) {
2069 point p = offset_p.gpt_get(p_index);
2070 if (p[0] < min[0])
2071 min[0] = p[0];
2072 if (p[1] < min[1])
2073 min[1] = p[1];
2074 if (p[0] > max[0])
2075 max[0] = p[0];
2076 if (p[1] > max[1])
2077 max[1] = p[1];
2078 }
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002079
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002080 point inner_min_t = -min;
2081 point inner_max_t = -max + point(si.accum->height(), si.accum->width());
2082 point outer_min_t = -max + point(adj_p - 1, adj_p - 1);
2083 point outer_max_t = point(si.accum->height(), si.accum->width()) - point(adj_p, adj_p);
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002084
02eb92ab David Hilvert2007-05-08 07:11:00 +00002085 if (local_gs == 1 || local_gs == 3 || local_gs == 4 || local_gs == 6) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002086
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002087 /*
2088 * Inner
2089 */
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002090
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002091 for (ale_pos i = inner_min_t[0]; i <= inner_max_t[0]; i += adj_p)
2092 for (ale_pos j = inner_min_t[1]; j <= inner_max_t[1]; j += adj_p) {
2093 transformation test_t = offset;
2094 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002095 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002096 }
2097 }
2098
02eb92ab David Hilvert2007-05-08 07:11:00 +00002099 if (local_gs == 2 || local_gs == 3 || local_gs == -1 || local_gs == 6) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002100
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002101 /*
2102 * Outer
2103 */
2104
2105 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
2106 for (ale_pos j = outer_min_t[1]; j < inner_min_t[1]; j += adj_p) {
2107 transformation test_t = offset;
2108 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002109 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002110 }
2111 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
2112 for (ale_pos j = outer_max_t[1]; j > inner_max_t[1]; j -= adj_p) {
2113 transformation test_t = offset;
2114 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002115 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002116 }
2117 for (ale_pos i = outer_min_t[0]; i < inner_min_t[0]; i += adj_p)
2118 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
2119 transformation test_t = offset;
2120 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002121 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002122 }
2123 for (ale_pos i = outer_max_t[0]; i > inner_max_t[0]; i -= adj_p)
2124 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
2125 transformation test_t = offset;
2126 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002127 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
f2d60fe2
DH
David Hilvert2007-04-13 23:28:00 +00002128 }
2129 }
cc71efb2
DH
David Hilvert2007-04-08 16:37:00 +00002130 }
2131
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00002132 static void get_translational_set(std::vector<transformation> *set,
2133 transformation t, ale_pos adj_p) {
2134
2135 ale_pos adj_s;
2136
2137 transformation offset = t;
dd761b64 David Hilvert2008-01-26 17:41:00 +00002138 transformation test_t(transformation::eu_identity());
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00002139
2140 for (int i = 0; i < 2; i++)
2141 for (adj_s = -adj_p; adj_s <= adj_p; adj_s += 2 * adj_p) {
2142
2143 test_t = offset;
2144
5b7749b0 David Hilvert2007-04-26 04:36:00 +00002145 test_t.translate(i ? point(adj_s, 0) : point(0, adj_s));
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00002146
2147 set->push_back(test_t);
2148 }
2149 }
2150
cd621c15 David Hilvert2007-07-23 20:38:00 +00002151 static int threshold_ok(ale_accum error) {
34add5e1 David Hilvert2007-10-17 21:47:00 +00002152 if ((1 - error) * (ale_accum) 100 >= match_threshold)
cd621c15
DH
David Hilvert2007-07-23 20:38:00 +00002153 return 1;
2154
2155 if (!(match_threshold >= 0))
2156 return 1;
2157
2158 return 0;
2159 }
228e156a
DH
David Hilvert2007-04-22 23:17:00 +00002160
2161 /*
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00002162 * Check for satisfaction of the certainty threshold.
2163 */
2164 static int ma_cert_satisfied(const scale_cluster &c, const transformation &t, unsigned int i) {
d790f7da David Hilvert2008-05-02 18:59:43 -05002165 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 +00002166 ale_accum sum[3] = {0, 0, 0};
2167
d790f7da
DH
David Hilvert2008-05-02 18:59:43 -05002168 for (unsigned int ii = b.imin; ii < b.imax; ii++)
2169 for (unsigned int jj = b.jmin; jj < b.jmax; jj++) {
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00002170 pixel p = c.accum->get_pixel(ii, jj);
2171 sum[0] += p[0];
2172 sum[1] += p[1];
2173 sum[2] += p[2];
2174 }
2175
d790f7da David Hilvert2008-05-02 18:59:43 -05002176 unsigned int count = (b.jmax - b.jmin) * (b.imax - b.imin);
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00002177
2178 for (int k = 0; k < 3; k++)
2179 if (sum[k] / count < _ma_cert)
2180 return 0;
2181
2182 return 1;
2183 }
2184
1b980378
DH
David Hilvert2008-07-18 18:30:40 +00002185 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) {
2186
2187 if (offset.get_current_index() > 0)
2188 for (int i = offset.parent_index(offset.get_current_index()); i >= 0; i = (i > 0) ? (int) offset.parent_index(i) : -1) {
2189 trans_single t = offset.get_element(i);
2190 t.rescale(offset.get_current_element().scale());
2191
2192 here.diff(si, t, local_ax_count, frame);
2193
e0577945 David Hilvert2008-07-19 22:11:55 +00002194 if (here.better_defined())
1b980378
DH
David Hilvert2008-07-18 18:30:40 +00002195 here.confirm();
2196 else
2197 here.discard();
2198 }
2199
2200 return here;
2201 }
2202
46f9776a dhilvert2005-01-07 06:44:00 +00002203#ifdef USE_FFTW
2204 /*
2205 * High-pass filter for frequency weights
2206 */
2207 static void hipass(int rows, int cols, fftw_complex *inout) {
2208 for (int i = 0; i < rows * vert_freq_cut; i++)
2209 for (int j = 0; j < cols; j++)
2210 for (int k = 0; k < 2; k++)
2211 inout[i * cols + j][k] = 0;
2212 for (int i = 0; i < rows; i++)
2213 for (int j = 0; j < cols * horiz_freq_cut; j++)
2214 for (int k = 0; k < 2; k++)
2215 inout[i * cols + j][k] = 0;
2216 for (int i = 0; i < rows; i++)
2217 for (int j = 0; j < cols; j++)
2218 for (int k = 0; k < 2; k++)
2219 if (i / (double) rows + j / (double) cols < 2 * avg_freq_cut)
2220 inout[i * cols + j][k] = 0;
2221 }
2222#endif
2223
2aa417e6 dhilvert2005-01-07 06:44:00 +00002224
2225 /*
2226 * Reset alignment weights
2227 */
2228 static void reset_weights() {
07271611 dhilvert2005-01-07 06:48:00 +00002229 if (alignment_weights != NULL)
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002230 ale_image_release(alignment_weights);
07271611 dhilvert2005-01-07 06:48:00 +00002231
2232 alignment_weights = NULL;
2aa417e6 dhilvert2005-01-07 06:44:00 +00002233 }
2234
2235 /*
2236 * Initialize alignment weights
2237 */
2238 static void init_weights() {
2239 if (alignment_weights != NULL)
2240 return;
2241
3617b771 David Hilvert2009-05-31 15:07:14 +00002242 alignment_weights = ale_new_image(accel::context(), ALE_IMAGE_RGB, ale_image_get_type(reference_image));
2aa417e6 dhilvert2005-01-07 06:44:00 +00002243
2244 assert (alignment_weights);
2245
e28f8ff7 David Hilvert2009-06-02 22:23:44 +00002246 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 +00002247
bccf19c9 David Hilvert2009-07-18 19:30:20 +00002248 ale_eval("MAP_PIXEL(%0I, p, PIXEL(1, 1, 1))", alignment_weights);
2aa417e6 dhilvert2005-01-07 06:44:00 +00002249 }
2250
46f9776a dhilvert2005-01-07 06:44:00 +00002251 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002252 * Update alignment weights with weight map
2253 */
2254 static void map_update() {
2255
2256 if (weight_map == NULL)
2257 return;
2258
2259 init_weights();
2260
bccf19c9 David Hilvert2009-07-18 19:30:20 +00002261 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 +00002262 }
2263
2264 /*
2265 * Update alignment weights with algorithmic weights
46f9776a dhilvert2005-01-07 06:44:00 +00002266 */
2267 static void wmx_update() {
2268#ifdef USE_UNIX
2269
2270 static exposure *exp_def = new exposure_default();
2271 static exposure *exp_bool = new exposure_boolean();
2272
46f9776a dhilvert2005-01-07 06:44:00 +00002273 if (wmx_file == NULL || wmx_exec == NULL || wmx_defs == NULL)
2274 return;
2275
33a3cc28
DH
David Hilvert2009-06-03 19:51:46 +00002276 unsigned int rows = ale_image_get_height(reference_image);
2277 unsigned int cols = ale_image_get_width(reference_image);
46f9776a dhilvert2005-01-07 06:44:00 +00002278
2279 image_rw::write_image(wmx_file, reference_image);
ac4577d5 David Hilvert2009-06-14 19:02:25 +00002280 image_rw::write_image(wmx_defs, reference_image, exp_bool->get_gamma(), 0, 0, 1);
46f9776a dhilvert2005-01-07 06:44:00 +00002281
2282 /* execute ... */
2283 int exit_status = 1;
2284 if (!fork()) {
2285 execlp(wmx_exec, wmx_exec, wmx_file, wmx_defs, NULL);
07271611 dhilvert2005-01-07 06:48:00 +00002286 ui::get()->exec_failure(wmx_exec, wmx_file, wmx_defs);
46f9776a dhilvert2005-01-07 06:44:00 +00002287 }
2288
2289 wait(&exit_status);
2290
07271611 dhilvert2005-01-07 06:48:00 +00002291 if (exit_status)
2292 ui::get()->fork_failure("d2::align");
46f9776a dhilvert2005-01-07 06:44:00 +00002293
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002294 ale_image wmx_weights = image_rw::read_image(wmx_file, exp_def);
46f9776a dhilvert2005-01-07 06:44:00 +00002295
35c1c6e3
DH
David Hilvert2009-06-14 21:17:14 +00002296 ale_image_set_x_offset(wmx_weights, ale_image_get_x_offset(reference_image));
2297 ale_image_set_y_offset(wmx_weights, ale_image_get_y_offset(reference_image));
5073b97e David Hilvert2009-06-14 20:59:56 +00002298
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002299 if (ale_image_get_height(wmx_weights) != rows || ale_image_get_width(wmx_weights) != cols)
07271611 dhilvert2005-01-07 06:48:00 +00002300 ui::get()->error("algorithmic weighting must not change image size");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002301
2302 if (alignment_weights == NULL)
2303 alignment_weights = wmx_weights;
2304 else
bccf19c9 David Hilvert2009-07-18 19:30:20 +00002305 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 +00002306#endif
2307 }
2308
2309 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002310 * Update alignment weights with frequency weights
46f9776a dhilvert2005-01-07 06:44:00 +00002311 */
2312 static void fw_update() {
2313#ifdef USE_FFTW
46f9776a dhilvert2005-01-07 06:44:00 +00002314 if (horiz_freq_cut == 0
2315 && vert_freq_cut == 0
2316 && avg_freq_cut == 0)
2317 return;
2318
2aa417e6 dhilvert2005-01-07 06:44:00 +00002319 /*
2320 * Required for correct operation of --fwshow
2321 */
2322
2323 assert (alignment_weights == NULL);
2324
46f9776a dhilvert2005-01-07 06:44:00 +00002325 int rows = reference_image->height();
2326 int cols = reference_image->width();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002327 int colors = reference_image->depth();
46f9776a dhilvert2005-01-07 06:44:00 +00002328
7cc12274 David Hilvert2007-12-11 04:50:00 +00002329 alignment_weights = new_image_ale_real(rows, cols,
2aa417e6 dhilvert2005-01-07 06:44:00 +00002330 colors, "alignment_weights");
46f9776a dhilvert2005-01-07 06:44:00 +00002331
2332 fftw_complex *inout = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * rows * cols);
2333
2334 assert (inout);
2335
2336 fftw_plan pf = fftw_plan_dft_2d(rows, cols,
2337 inout, inout,
2338 FFTW_FORWARD, FFTW_ESTIMATE);
2339
2340 fftw_plan pb = fftw_plan_dft_2d(rows, cols,
2341 inout, inout,
2342 FFTW_BACKWARD, FFTW_ESTIMATE);
2343
2aa417e6 dhilvert2005-01-07 06:44:00 +00002344 for (int k = 0; k < colors; k++) {
46f9776a dhilvert2005-01-07 06:44:00 +00002345 for (int i = 0; i < rows * cols; i++) {
2346 inout[i][0] = reference_image->get_pixel(i / cols, i % cols)[k];
2347 inout[i][1] = 0;
2348 }
2349
2350 fftw_execute(pf);
2351 hipass(rows, cols, inout);
2352 fftw_execute(pb);
2353
2354 for (int i = 0; i < rows * cols; i++) {
2355#if 0
2aa417e6 dhilvert2005-01-07 06:44:00 +00002356 alignment_weights->pix(i / cols, i % cols)[k] = fabs(inout[i][0] / (rows * cols));
46f9776a dhilvert2005-01-07 06:44:00 +00002357#else
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00002358 alignment_weights->set_chan(i / cols, i % cols, k,
46f9776a dhilvert2005-01-07 06:44:00 +00002359 sqrt(pow(inout[i][0] / (rows * cols), 2)
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00002360 + pow(inout[i][1] / (rows * cols), 2)));
46f9776a dhilvert2005-01-07 06:44:00 +00002361#endif
2362 }
2363 }
2364
2365 fftw_destroy_plan(pf);
2366 fftw_destroy_plan(pb);
2367 fftw_free(inout);
2368
2369 if (fw_output != NULL)
2aa417e6 dhilvert2005-01-07 06:44:00 +00002370 image_rw::write_image(fw_output, alignment_weights);
46f9776a dhilvert2005-01-07 06:44:00 +00002371#endif
2372 }
2373
30afe4b6 dhilvert2005-01-07 06:42:00 +00002374 /*
2375 * Update alignment to frame N.
2376 */
2377 static void update_to(int n) {
0e4ec247 David Hilvert2007-03-13 04:51:00 +00002378
30afe4b6 dhilvert2005-01-07 06:42:00 +00002379 assert (n <= latest + 1);
0a432b63 David Hilvert2007-03-13 08:03:00 +00002380 assert (n >= 0);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002381
f922c1c4 David Hilvert2009-06-22 00:04:12 +00002382 ale_align_properties astate = align_properties();
f65325e3 David Hilvert2007-03-15 06:24:00 +00002383
724b1c71
DH
David Hilvert2008-07-01 15:20:56 +00002384 ui::get()->set_frame_num(n);
2385
46f9776a dhilvert2005-01-07 06:44:00 +00002386 if (latest < 0) {
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002387
2388 /*
2389 * Handle the initial frame
2390 */
2391
8aaa492c
DH
David Hilvert2009-06-28 01:59:05 +00002392 astate.set_input_frame(image_rw::open(n));
2393
2394 const image *i = astate.get_input_frame();
46f9776a dhilvert2005-01-07 06:44:00 +00002395 int is_default;
2396 transformation result = alignment_class == 2
2397 ? transformation::gpt_identity(i, scale_factor)
2398 : transformation::eu_identity(i, scale_factor);
2399 result = tload_first(tload, alignment_class == 2, result, &is_default);
2400 tsave_first(tsave, result, alignment_class == 2);
46f9776a dhilvert2005-01-07 06:44:00 +00002401
2402 if (_keep > 0) {
dd761b64 David Hilvert2008-01-26 17:41:00 +00002403 kept_t = transformation::new_eu_identity_array(image_rw::count());
46f9776a dhilvert2005-01-07 06:44:00 +00002404 kept_ok = (int *) malloc(image_rw::count()
2405 * sizeof(int));
2406 assert (kept_t);
2407 assert (kept_ok);
2408
07271611 dhilvert2005-01-07 06:48:00 +00002409 if (!kept_t || !kept_ok)
2410 ui::get()->memory_error("alignment");
46f9776a dhilvert2005-01-07 06:44:00 +00002411
2412 kept_ok[0] = 1;
2413 kept_t[0] = result;
2414 }
2415
2416 latest = 0;
2417 latest_ok = 1;
2418 latest_t = result;
2419
0467efe3 David Hilvert2008-04-09 21:14:38 +00002420 astate.set_default(result);
46f9776a dhilvert2005-01-07 06:44:00 +00002421 orig_t = result;
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002422
2423 image_rw::close(n);
46f9776a dhilvert2005-01-07 06:44:00 +00002424 }
2425
bbc7699c David Hilvert2007-04-02 03:05:00 +00002426 for (int i = latest + 1; i <= n; i++) {
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002427
2428 /*
2429 * Handle supplemental frames.
2430 */
2431
46f9776a dhilvert2005-01-07 06:44:00 +00002432 assert (reference != NULL);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002433
07271611 dhilvert2005-01-07 06:48:00 +00002434 ui::get()->set_arender_current();
46f9776a dhilvert2005-01-07 06:44:00 +00002435 reference->sync(i - 1);
07271611 dhilvert2005-01-07 06:48:00 +00002436 ui::get()->clear_arender_current();
46f9776a dhilvert2005-01-07 06:44:00 +00002437 reference_image = reference->get_image();
2438 reference_defined = reference->get_defined();
30afe4b6 dhilvert2005-01-07 06:42:00 +00002439
f2fc9b99 David Hilvert2008-02-14 17:35:00 +00002440 if (i == 1)
0467efe3 David Hilvert2008-04-09 21:14:38 +00002441 astate.default_set_original_bounds(reference_image);
f2fc9b99 David Hilvert2008-02-14 17:35:00 +00002442
2aa417e6 dhilvert2005-01-07 06:44:00 +00002443 reset_weights();
46f9776a dhilvert2005-01-07 06:44:00 +00002444 fw_update();
2445 wmx_update();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002446 map_update();
30afe4b6 dhilvert2005-01-07 06:42:00 +00002447
46f9776a dhilvert2005-01-07 06:44:00 +00002448 assert (reference_image != NULL);
2449 assert (reference_defined != NULL);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002450
0467efe3 David Hilvert2008-04-09 21:14:38 +00002451 astate.set_input_frame(image_rw::open(i));
0a432b63 David Hilvert2007-03-13 08:03:00 +00002452
e580d9d3 David Hilvert2007-12-19 16:59:00 +00002453 _align(i, _gs, &astate);
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002454
2455 image_rw::close(n);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002456 }
2457 }
2458
2459public:
2460
2461 /*
04382119 dhilvert2005-04-29 09:23:00 +00002462 * Set the control point count
2463 */
2464 static void set_cp_count(unsigned int n) {
2465 assert (cp_array == NULL);
2466
2467 cp_count = n;
2468 cp_array = (const point **) malloc(n * sizeof(const point *));
2469 }
2470
2471 /*
2472 * Set control points.
2473 */
2474 static void set_cp(unsigned int i, const point *p) {
2475 cp_array[i] = p;
2476 }
2477
2478 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002479 * Register exposure
2480 */
2481 static void exp_register() {
2482 _exp_register = 1;
2483 }
2484
2485 /*
3dc20778 dhilvert2005-01-10 23:06:00 +00002486 * Register exposure only based on metadata
2487 */
2488 static void exp_meta_only() {
2489 _exp_register = 2;
2490 }
2491
2492 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002493 * Don't register exposure
2494 */
2495 static void exp_noregister() {
2496 _exp_register = 0;
2497 }
2498
2499 /*
2500 * Set alignment class to translation only. Only adjust the x and y
2501 * position of images. Do not rotate input images or perform
2502 * projective transformations.
2503 */
2504 static void class_translation() {
2505 alignment_class = 0;
2506 }
2507
2508 /*
2509 * Set alignment class to Euclidean transformations only. Adjust the x
2510 * and y position of images and the orientation of the image about the
2511 * image center.
2512 */
2513 static void class_euclidean() {
2514 alignment_class = 1;
2515 }
2516
2517 /*
2518 * Set alignment class to perform general projective transformations.
2519 * See the file gpt.h for more information about general projective
2520 * transformations.
2521 */
2522 static void class_projective() {
2523 alignment_class = 2;
2524 }
2525
2526 /*
2527 * Set the default initial alignment to the identity transformation.
2528 */
2529 static void initial_default_identity() {
2530 default_initial_alignment_type = 0;
2531 }
2532
2533 /*
2534 * Set the default initial alignment to the most recently matched
2535 * frame's final transformation.
2536 */
2537 static void initial_default_follow() {
2538 default_initial_alignment_type = 1;
2539 }
2540
2541 /*
f09b7254 dhilvert2005-01-07 06:44:00 +00002542 * Perturb output coordinates.
2543 */
2544 static void perturb_output() {
2545 perturb_type = 0;
2546 }
2547
2548 /*
2549 * Perturb source coordinates.
2550 */
2551 static void perturb_source() {
2552 perturb_type = 1;
2553 }
2554
2555 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002556 * Frames under threshold align optimally
2557 */
2558 static void fail_optimal() {
2559 is_fail_default = 0;
2560 }
2561
2562 /*
2563 * Frames under threshold keep their default alignments.
2564 */
2565 static void fail_default() {
2566 is_fail_default = 1;
2567 }
2568
2569 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002570 * Align images with an error contribution from each color channel.
2571 */
2572 static void all() {
2573 channel_alignment_type = 0;
2574 }
2575
2576 /*
2577 * Align images with an error contribution only from the green channel.
2578 * Other color channels do not affect alignment.
2579 */
2580 static void green() {
2581 channel_alignment_type = 1;
2582 }
2583
2584 /*
2585 * Align images using a summation of channels. May be useful when
2586 * dealing with images that have high frequency color ripples due to
2587 * color aliasing.
2588 */
2589 static void sum() {
2590 channel_alignment_type = 2;
2591 }
2592
2593 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002594 * Error metric exponent
2595 */
2596
2597 static void set_metric_exponent(float me) {
2598 metric_exponent = me;
2599 }
2600
2601 /*
2602 * Match threshold
2603 */
2604
2605 static void set_match_threshold(float mt) {
2606 match_threshold = mt;
2607 }
2608
2609 /*
2610 * Perturbation lower and upper bounds.
2611 */
2612
f09b7254 dhilvert2005-01-07 06:44:00 +00002613 static void set_perturb_lower(ale_pos pl, int plp) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002614 perturb_lower = pl;
f09b7254 dhilvert2005-01-07 06:44:00 +00002615 perturb_lower_percent = plp;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002616 }
2617
f09b7254 dhilvert2005-01-07 06:44:00 +00002618 static void set_perturb_upper(ale_pos pu, int pup) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002619 perturb_upper = pu;
f09b7254 dhilvert2005-01-07 06:44:00 +00002620 perturb_upper_percent = pup;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002621 }
2622
2623 /*
2624 * Maximum rotational perturbation.
2625 */
2626
2627 static void set_rot_max(int rm) {
2628
2629 /*
2630 * Obtain the largest power of two not larger than rm.
2631 */
2632
2633 rot_max = pow(2, floor(log(rm) / log(2)));
2634 }
2635
2636 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002637 * Barrel distortion adjustment multiplier
2638 */
2639
2640 static void set_bda_mult(ale_pos m) {
2641 bda_mult = m;
2642 }
2643
2644 /*
2645 * Barrel distortion maximum rate of change
2646 */
2647
2648 static void set_bda_rate(ale_pos m) {
2649 bda_rate = m;
2650 }
2651
2652 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002653 * Level-of-detail
2654 */
2655
5292ffa7
DH
David Hilvert2008-05-28 01:17:53 +00002656 static void set_lod_preferred(int lm) {
2657 lod_preferred = lm;
2658 }
2659
2660 /*
2661 * Minimum dimension for reduced level-of-detail.
2662 */
2663
2664 static void set_min_dimension(int md) {
2665 min_dimension = md;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002666 }
2667
2668 /*
2669 * Set the scale factor
2670 */
2671 static void set_scale(ale_pos s) {
2672 scale_factor = s;
2673 }
2674
2675 /*
2676 * Set reference rendering to align against
2677 */
2678 static void set_reference(render *r) {
2679 reference = r;
2680 }
2681
2682 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002683 * Set the interpolant
2684 */
2685 static void set_interpolant(filter::scaled_filter *f) {
2686 interpolant = f;
2687 }
2688
2689 /*
2690 * Set alignment weights image
2691 */
2aa417e6 dhilvert2005-01-07 06:44:00 +00002692 static void set_weight_map(const image *i) {
2693 weight_map = i;
46f9776a dhilvert2005-01-07 06:44:00 +00002694 }
2695
2696 /*
2697 * Set frequency cuts
2698 */
2699 static void set_frequency_cut(double h, double v, double a) {
2700 horiz_freq_cut = h;
2701 vert_freq_cut = v;
2702 avg_freq_cut = a;
2703 }
2704
2705 /*
2706 * Set algorithmic alignment weighting
2707 */
2708 static void set_wmx(const char *e, const char *f, const char *d) {
2709 wmx_exec = e;
2710 wmx_file = f;
2711 wmx_defs = d;
2712 }
2713
2714 /*
2715 * Show frequency weights
2716 */
2717 static void set_fl_show(const char *filename) {
2718 fw_output = filename;
2719 }
2720
2721 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002722 * Set transformation file loader.
2723 */
2724 static void set_tload(tload_t *tl) {
2725 tload = tl;
2726 }
2727
2728 /*
2729 * Set transformation file saver.
2730 */
2731 static void set_tsave(tsave_t *ts) {
2732 tsave = ts;
2733 }
2734
2735 /*
2736 * Get match statistics for frame N.
30afe4b6 dhilvert2005-01-07 06:42:00 +00002737 */
2738 static int match(int n) {
2739 update_to(n);
2740
46f9776a dhilvert2005-01-07 06:44:00 +00002741 if (n == latest)
30afe4b6 dhilvert2005-01-07 06:42:00 +00002742 return latest_ok;
2743 else if (_keep)
2744 return kept_ok[n];
46f9776a dhilvert2005-01-07 06:44:00 +00002745 else {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002746 assert(0);
46f9776a dhilvert2005-01-07 06:44:00 +00002747 exit(1);
2748 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00002749 }
2750
2751 /*
2752 * Message that old alignment data should be kept.
2753 */
2754 static void keep() {
46f9776a dhilvert2005-01-07 06:44:00 +00002755 assert (latest == -1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002756 _keep = 1;
2757 }
2758
2759 /*
2760 * Get alignment for frame N.
30afe4b6 dhilvert2005-01-07 06:42:00 +00002761 */
2762 static transformation of(int n) {
2763 update_to(n);
46f9776a dhilvert2005-01-07 06:44:00 +00002764 if (n == latest)
30afe4b6 dhilvert2005-01-07 06:42:00 +00002765 return latest_t;
2766 else if (_keep)
2767 return kept_t[n];
2768 else {
2769 assert(0);
2770 exit(1);
2771 }
2772 }
2773
2774 /*
bddc9e4d David Hilvert2007-10-01 19:50:00 +00002775 * Use Monte Carlo alignment sampling with argument N.
1c2f7405 David Hilvert2007-09-20 16:58:00 +00002776 */
bddc9e4d
DH
David Hilvert2007-10-01 19:50:00 +00002777 static void mc(ale_pos n) {
2778 _mc = n;
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +00002779 }
2780
2781 /*
07271611 dhilvert2005-01-07 06:48:00 +00002782 * Set the certainty-weighted flag.
2783 */
2784 static void certainty_weighted(int flag) {
2785 certainty_weights = flag;
2786 }
2787
2788 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002789 * Set the global search type.
2790 */
2791 static void gs(const char *type) {
7bcfe5db dhilvert2005-01-07 06:44:00 +00002792 if (!strcmp(type, "local")) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00002793 _gs = 0;
2794 } else if (!strcmp(type, "inner")) {
2795 _gs = 1;
2796 } else if (!strcmp(type, "outer")) {
2797 _gs = 2;
2798 } else if (!strcmp(type, "all")) {
2799 _gs = 3;
2800 } else if (!strcmp(type, "central")) {
2801 _gs = 4;
842afc18
DH
David Hilvert2007-05-08 06:55:00 +00002802 } else if (!strcmp(type, "defaults")) {
2803 _gs = 6;
04382119 dhilvert2005-04-29 09:23:00 +00002804 } else if (!strcmp(type, "points")) {
2805 _gs = 5;
b386e644 dhilvert2005-04-30 09:28:00 +00002806 keep();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002807 } else {
07271611 dhilvert2005-01-07 06:48:00 +00002808 ui::get()->error("bad global search type");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002809 }
2810 }
2811
2812 /*
4949c031 dhilvert2005-01-07 06:44:00 +00002813 * Set the minimum overlap for global searching
2814 */
326c35b1 David Hilvert2007-04-19 21:28:00 +00002815 static void gs_mo(ale_pos value, int _gs_mo_percent) {
4949c031 dhilvert2005-01-07 06:44:00 +00002816 _gs_mo = value;
326c35b1 David Hilvert2007-04-19 21:28:00 +00002817 gs_mo_percent = _gs_mo_percent;
4949c031 dhilvert2005-01-07 06:44:00 +00002818 }
2819
2820 /*
903df240
DH
David Hilvert2008-04-24 14:36:35 +00002821 * Set mutli-alignment certainty lower bound.
2822 */
2823 static void set_ma_cert(ale_real value) {
2824 _ma_cert = value;
2825 }
2826
2827 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002828 * Set alignment exclusion regions
2829 */
df55d1a2 dhilvert2006-08-30 07:40:00 +00002830 static void set_exclusion(exclusion *_ax_parameters, int _ax_count) {
46f9776a dhilvert2005-01-07 06:44:00 +00002831 ax_count = _ax_count;
2832 ax_parameters = _ax_parameters;
2833 }
2834
2835 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002836 * Get match summary statistics.
2837 */
2838 static ale_accum match_summary() {
34add5e1 David Hilvert2007-10-17 21:47:00 +00002839 return match_sum / (ale_accum) match_count;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002840 }
2841};
2842
f8864302
DH
David Hilvert2008-04-11 18:15:57 +00002843template<class diff_trans>
2844void *d2::align::diff_stat_generic<diff_trans>::diff_subdomain(void *args) {
2845
2846 subdomain_args *sargs = (subdomain_args *) args;
2847
2848 struct scale_cluster c = sargs->c;
2849 std::vector<run> runs = sargs->runs;
2850 int ax_count = sargs->ax_count;
2851 int f = sargs->f;
2852 int i_min = sargs->i_min;
2853 int i_max = sargs->i_max;
2854 int j_min = sargs->j_min;
2855 int j_max = sargs->j_max;
2856 int subdomain = sargs->subdomain;
2857
2858 assert (reference_image);
2859
2860 point offset = c.accum->offset();
2861
2862 for (mc_iterate m(i_min, i_max, j_min, j_max, subdomain); !m.done(); m++) {
2863
2864 int i = m.get_i();
2865 int j = m.get_j();
2866
2867 /*
2868 * Check reference frame definition.
2869 */
2870
2871 if (!((pixel) c.accum->get_pixel(i, j)).finite()
2872 || !(((pixel) c.certainty->get_pixel(i, j)).minabs_norm() > 0))
2873 continue;
2874
2875 /*
2876 * Check for exclusion in render coordinates.
2877 */
2878
2879 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
2880 continue;
2881
2882 /*
2883 * Transform
2884 */
2885
2886 struct point q, r = point::undefined();
2887
2888 q = (c.input_scale < 1.0 && interpolant == NULL)
2889 ? runs.back().offset.scaled_inverse_transform(
2890 point(i + offset[0], j + offset[1]))
2891 : runs.back().offset.unscaled_inverse_transform(
2892 point(i + offset[0], j + offset[1]));
2893
2894 if (runs.size() == 2) {
2895 r = (c.input_scale < 1.0)
2896 ? runs.front().offset.scaled_inverse_transform(
2897 point(i + offset[0], j + offset[1]))
2898 : runs.front().offset.unscaled_inverse_transform(
2899 point(i + offset[0], j + offset[1]));
2900 }
2901
2902 ale_pos ti = q[0];
2903 ale_pos tj = q[1];
2904
2905 /*
2906 * Check that the transformed coordinates are within
2907 * the boundaries of array c.input and that they
2908 * are not subject to exclusion.
2909 *
2910 * Also, check that the weight value in the accumulated array
2911 * is nonzero, unless we know it is nonzero by virtue of the
2912 * fact that it falls within the region of the original frame
2913 * (e.g. when we're not increasing image extents).
2914 */
2915
2916 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
2917 continue;
2918
2919 if (input_excluded(r[0], r[1], c.ax_parameters, ax_count))
2920 r = point::undefined();
2921
2922 /*
2923 * Check the boundaries of the input frame
2924 */
2925
2926 if (!(ti >= 0
2927 && ti <= c.input->height() - 1
2928 && tj >= 0
2929 && tj <= c.input->width() - 1))
2930 continue;
2931
2932 if (!(r[0] >= 0
2933 && r[0] <= c.input->height() - 1
2934 && r[1] >= 0
2935 && r[1] <= c.input->width() - 1))
2936 r = point::undefined();
2937
2938 sargs->runs.back().sample(f, c, i, j, q, r, runs.front());
2939 }
2940
2941 return NULL;
2942}
2943
30afe4b6 dhilvert2005-01-07 06:42:00 +00002944#endif