d2/align: Move d2::align::diff_stat*::diff_subdomain() to Libale.
[Ale.git] / d2 / align.h
Commit [+] Author Date Line Data
8a81d3be
DH
David Hilvert2007-04-03 18:57:00 +00001// Copyright 2002, 2004, 2007 David Hilvert <dhilvert@auricle.dyndns.org>,
2// <dhilvert@ugcs.caltech.edu>
30afe4b6 dhilvert2005-01-07 06:42:00 +00003
4/* This file is part of the Anti-Lamenessing Engine.
5
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
70932f40 David Hilvert2007-07-19 21:14:00 +00008 the Free Software Foundation; either version 3 of the License, or
30afe4b6 dhilvert2005-01-07 06:42:00 +00009 (at your option) any later version.
10
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/*
22 * align.h: Handle alignment of frames.
23 */
24
25#ifndef __d2align_h__
26#define __d2align_h__
27
46f9776a dhilvert2005-01-07 06:44:00 +000028#include "filter.h"
29#include "transformation.h"
30afe4b6 dhilvert2005-01-07 06:42:00 +000030#include "image.h"
31#include "point.h"
32#include "render.h"
33#include "tfile.h"
34#include "image_rw.h"
35
36class align {
37private:
38
39 /*
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 /*
df55d1a2 dhilvert2006-08-30 07:40:00 +0000884 * Copy all ax parameters.
885 */
886 static exclusion *copy_ax_parameters(int local_ax_count, exclusion *source) {
2aa417e6 dhilvert2005-01-07 06:44:00 +0000887
df55d1a2 dhilvert2006-08-30 07:40:00 +0000888 exclusion *dest = (exclusion *) malloc(local_ax_count * sizeof(exclusion));
2aa417e6 dhilvert2005-01-07 06:44:00 +0000889
df55d1a2 dhilvert2006-08-30 07:40:00 +0000890 assert (dest);
2aa417e6 dhilvert2005-01-07 06:44:00 +0000891
df55d1a2 dhilvert2006-08-30 07:40:00 +0000892 if (!dest)
07271611 dhilvert2005-01-07 06:48:00 +0000893 ui::get()->memory_error("exclusion regions");
2aa417e6 dhilvert2005-01-07 06:44:00 +0000894
df55d1a2 dhilvert2006-08-30 07:40:00 +0000895 for (int idx = 0; idx < local_ax_count; idx++)
896 dest[idx] = source[idx];
2aa417e6 dhilvert2005-01-07 06:44:00 +0000897
df55d1a2 dhilvert2006-08-30 07:40:00 +0000898 return dest;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000899 }
900
df55d1a2 dhilvert2006-08-30 07:40:00 +0000901 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +0000902 * Prepare the next level of detail for ordinary images.
903 */
904 static const image *prepare_lod(const image *current) {
905 if (current == NULL)
906 return NULL;
46f9776a dhilvert2005-01-07 06:44:00 +0000907
2aa417e6 dhilvert2005-01-07 06:44:00 +0000908 return current->scale_by_half("prepare_lod");
909 }
46f9776a dhilvert2005-01-07 06:44:00 +0000910
2aa417e6 dhilvert2005-01-07 06:44:00 +0000911 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +0000912 * Prepare the next level of detail for definition maps.
913 */
914 static const image *prepare_lod_def(const image *current) {
7a19e165
DH
David Hilvert2007-09-10 21:16:00 +0000915 if (current == NULL)
916 return NULL;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000917
918 return current->defined_scale_by_half("prepare_lod_def");
919 }
920
921 /*
8f2ed1fd David Hilvert2007-09-07 18:36:00 +0000922 * Initialize scale cluster data structures.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000923 */
8f2ed1fd
DH
David Hilvert2007-09-07 18:36:00 +0000924
925 static void init_nl_cluster(struct scale_cluster *sc) {
926 }
927
2aa417e6 dhilvert2005-01-07 06:44:00 +0000928 /*
929 * Destroy the first element in the scale cluster data structure.
930 */
a85f57f9 David Hilvert2007-10-15 17:07:00 +0000931 static void final_clusters(struct scale_cluster *scale_clusters, ale_pos scale_factor,
2aa417e6 dhilvert2005-01-07 06:44:00 +0000932 unsigned int steps) {
933
c6e3d33a David Hilvert2007-10-02 15:57:00 +0000934 if (scale_clusters[0].input_scale < 1.0) {
2aa417e6 dhilvert2005-01-07 06:44:00 +0000935 delete scale_clusters[0].input;
c6e3d33a David Hilvert2007-10-02 15:57:00 +0000936 }
2aa417e6 dhilvert2005-01-07 06:44:00 +0000937
44a1d1de
DH
David Hilvert2009-03-30 19:02:57 +0000938 delete scale_clusters[0].input_certainty;
939
2aa417e6 dhilvert2005-01-07 06:44:00 +0000940 free((void *)scale_clusters[0].ax_parameters);
941
942 for (unsigned int step = 1; step < steps; step++) {
943 delete scale_clusters[step].accum;
580b5321 David Hilvert2007-09-10 17:35:00 +0000944 delete scale_clusters[step].certainty;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000945 delete scale_clusters[step].aweight;
946
c6e3d33a David Hilvert2007-10-02 15:57:00 +0000947 if (scale_clusters[step].input_scale < 1.0) {
07271611 dhilvert2005-01-07 06:48:00 +0000948 delete scale_clusters[step].input;
c6e3d33a
DH
David Hilvert2007-10-02 15:57:00 +0000949 delete scale_clusters[step].input_certainty;
950 }
07271611 dhilvert2005-01-07 06:48:00 +0000951
2aa417e6 dhilvert2005-01-07 06:44:00 +0000952 free((void *)scale_clusters[step].ax_parameters);
953 }
954
955 free(scale_clusters);
46f9776a dhilvert2005-01-07 06:44:00 +0000956 }
30afe4b6 dhilvert2005-01-07 06:42:00 +0000957
958 /*
c052e200 dhilvert2005-05-08 16:16:00 +0000959 * Calculate the centroid of a control point for the set of frames
960 * having index lower than m. Divide by any scaling of the output.
961 */
962 static point unscaled_centroid(unsigned int m, unsigned int p) {
963 assert(_keep);
964
965 point point_sum(0, 0);
966 ale_accum divisor = 0;
967
968 for(unsigned int j = 0; j < m; j++) {
969 point pp = cp_array[p][j];
970
971 if (pp.defined()) {
972 point_sum += kept_t[j].transform_unscaled(pp)
973 / kept_t[j].scale();
974 divisor += 1;
975 }
976 }
977
978 if (divisor == 0)
979 return point::undefined();
980
981 return point_sum / divisor;
982 }
983
984 /*
985 * Calculate centroid of this frame, and of all previous frames,
986 * from points common to both sets.
987 */
988 static void centroids(unsigned int m, point *current, point *previous) {
989 /*
990 * Calculate the translation
991 */
992 point other_centroid(0, 0);
993 point this_centroid(0, 0);
994 ale_pos divisor = 0;
995
996 for (unsigned int i = 0; i < cp_count; i++) {
997 point other_c = unscaled_centroid(m, i);
998 point this_c = cp_array[i][m];
999
1000 if (!other_c.defined() || !this_c.defined())
1001 continue;
1002
1003 other_centroid += other_c;
1004 this_centroid += this_c;
1005 divisor += 1;
1006
1007 }
1008
1009 if (divisor == 0) {
1010 *current = point::undefined();
1011 *previous = point::undefined();
1012 return;
1013 }
1014
1015 *current = this_centroid / divisor;
1016 *previous = other_centroid / divisor;
1017 }
1018
1019 /*
b386e644 dhilvert2005-04-30 09:28:00 +00001020 * Calculate the RMS error of control points for frame m, with
1021 * transformation t, against control points for earlier frames.
1022 */
e812ee44 David Hilvert2007-10-18 18:24:00 +00001023 static ale_pos cp_rms_error(unsigned int m, transformation t) {
b386e644 dhilvert2005-04-30 09:28:00 +00001024 assert (_keep);
1025
1026 ale_accum err = 0;
1027 ale_accum divisor = 0;
1028
1029 for (unsigned int i = 0; i < cp_count; i++)
1030 for (unsigned int j = 0; j < m; j++) {
1031 const point *p = cp_array[i];
936ff6ec dhilvert2005-05-07 20:02:00 +00001032 point p_ref = kept_t[j].transform_unscaled(p[j]);
1033 point p_cur = t.transform_unscaled(p[m]);
b386e644 dhilvert2005-04-30 09:28:00 +00001034
1035 if (!p_ref.defined() || !p_cur.defined())
1036 continue;
1037
1038 err += p_ref.lengthtosq(p_cur);
1039 divisor += 1;
1040 }
1041
e812ee44 David Hilvert2007-10-18 18:24:00 +00001042 return (ale_pos) sqrt(err / divisor);
b386e644 dhilvert2005-04-30 09:28:00 +00001043 }
1044
6126fb3c David Hilvert2007-04-03 08:15:00 +00001045
59e5857b David Hilvert2007-05-08 12:15:00 +00001046 static void test_global(diff_stat_t *here, scale_cluster si, transformation t,
a7882498 David Hilvert2007-10-16 19:48:00 +00001047 int local_ax_count, int m, ale_accum local_gs_mo, ale_pos perturb) {
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00001048
1049 diff_stat_t test(*here);
1050
1b980378 David Hilvert2008-07-18 18:30:40 +00001051 test.diff(si, t.get_current_element(), local_ax_count, m);
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00001052
1053 unsigned int ovl = overlap(si, t, local_ax_count);
1054
1055 if (ovl >= local_gs_mo && test.better()) {
1056 test.confirm();
1057 *here = test;
1058 ui::get()->set_match(here->get_error());
1059 ui::get()->set_offset(here->get_offset());
1060 } else {
1061 test.discard();
1062 }
1063
1064 }
1065
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001066 /*
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001067 * Get the set of global transformations for a given density
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001068 */
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00001069 static void test_globals(diff_stat_t *here,
1070 scale_cluster si, transformation t, int local_gs, ale_pos adj_p,
a7882498 David Hilvert2007-10-16 19:48:00 +00001071 int local_ax_count, int m, ale_accum local_gs_mo, ale_pos perturb) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001072
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001073 transformation offset = t;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001074
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001075 point min, max;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001076
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001077 transformation offset_p = offset;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001078
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001079 if (!offset_p.is_projective())
1080 offset_p.eu_to_gpt();
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001081
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001082 min = max = offset_p.gpt_get(0);
1083 for (int p_index = 1; p_index < 4; p_index++) {
1084 point p = offset_p.gpt_get(p_index);
1085 if (p[0] < min[0])
1086 min[0] = p[0];
1087 if (p[1] < min[1])
1088 min[1] = p[1];
1089 if (p[0] > max[0])
1090 max[0] = p[0];
1091 if (p[1] > max[1])
1092 max[1] = p[1];
1093 }
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001094
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001095 point inner_min_t = -min;
1096 point inner_max_t = -max + point(si.accum->height(), si.accum->width());
1097 point outer_min_t = -max + point(adj_p - 1, adj_p - 1);
1098 point outer_max_t = point(si.accum->height(), si.accum->width()) - point(adj_p, adj_p);
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001099
02eb92ab David Hilvert2007-05-08 07:11:00 +00001100 if (local_gs == 1 || local_gs == 3 || local_gs == 4 || local_gs == 6) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001101
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001102 /*
1103 * Inner
1104 */
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001105
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001106 for (ale_pos i = inner_min_t[0]; i <= inner_max_t[0]; i += adj_p)
1107 for (ale_pos j = inner_min_t[1]; j <= inner_max_t[1]; j += adj_p) {
1108 transformation test_t = offset;
1109 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001110 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001111 }
1112 }
1113
02eb92ab David Hilvert2007-05-08 07:11:00 +00001114 if (local_gs == 2 || local_gs == 3 || local_gs == -1 || local_gs == 6) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00001115
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001116 /*
1117 * Outer
1118 */
1119
1120 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
1121 for (ale_pos j = outer_min_t[1]; j < inner_min_t[1]; j += adj_p) {
1122 transformation test_t = offset;
1123 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001124 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001125 }
1126 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
1127 for (ale_pos j = outer_max_t[1]; j > inner_max_t[1]; j -= adj_p) {
1128 transformation test_t = offset;
1129 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001130 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001131 }
1132 for (ale_pos i = outer_min_t[0]; i < inner_min_t[0]; i += adj_p)
1133 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
1134 transformation test_t = offset;
1135 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001136 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001137 }
1138 for (ale_pos i = outer_max_t[0]; i > inner_max_t[0]; i -= adj_p)
1139 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
1140 transformation test_t = offset;
1141 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001142 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
f2d60fe2
DH
David Hilvert2007-04-13 23:28:00 +00001143 }
1144 }
cc71efb2
DH
David Hilvert2007-04-08 16:37:00 +00001145 }
1146
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00001147 static void get_translational_set(std::vector<transformation> *set,
1148 transformation t, ale_pos adj_p) {
1149
1150 ale_pos adj_s;
1151
1152 transformation offset = t;
dd761b64 David Hilvert2008-01-26 17:41:00 +00001153 transformation test_t(transformation::eu_identity());
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00001154
1155 for (int i = 0; i < 2; i++)
1156 for (adj_s = -adj_p; adj_s <= adj_p; adj_s += 2 * adj_p) {
1157
1158 test_t = offset;
1159
5b7749b0 David Hilvert2007-04-26 04:36:00 +00001160 test_t.translate(i ? point(adj_s, 0) : point(0, adj_s));
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00001161
1162 set->push_back(test_t);
1163 }
1164 }
1165
cd621c15 David Hilvert2007-07-23 20:38:00 +00001166 static int threshold_ok(ale_accum error) {
34add5e1 David Hilvert2007-10-17 21:47:00 +00001167 if ((1 - error) * (ale_accum) 100 >= match_threshold)
cd621c15
DH
David Hilvert2007-07-23 20:38:00 +00001168 return 1;
1169
1170 if (!(match_threshold >= 0))
1171 return 1;
1172
1173 return 0;
1174 }
228e156a
DH
David Hilvert2007-04-22 23:17:00 +00001175
1176 /*
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00001177 * Check for satisfaction of the certainty threshold.
1178 */
1179 static int ma_cert_satisfied(const scale_cluster &c, const transformation &t, unsigned int i) {
d790f7da David Hilvert2008-05-02 18:59:43 -05001180 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 +00001181 ale_accum sum[3] = {0, 0, 0};
1182
d790f7da
DH
David Hilvert2008-05-02 18:59:43 -05001183 for (unsigned int ii = b.imin; ii < b.imax; ii++)
1184 for (unsigned int jj = b.jmin; jj < b.jmax; jj++) {
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00001185 pixel p = c.accum->get_pixel(ii, jj);
1186 sum[0] += p[0];
1187 sum[1] += p[1];
1188 sum[2] += p[2];
1189 }
1190
d790f7da David Hilvert2008-05-02 18:59:43 -05001191 unsigned int count = (b.jmax - b.jmin) * (b.imax - b.imin);
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00001192
1193 for (int k = 0; k < 3; k++)
1194 if (sum[k] / count < _ma_cert)
1195 return 0;
1196
1197 return 1;
1198 }
1199
1b980378
DH
David Hilvert2008-07-18 18:30:40 +00001200 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) {
1201
1202 if (offset.get_current_index() > 0)
1203 for (int i = offset.parent_index(offset.get_current_index()); i >= 0; i = (i > 0) ? (int) offset.parent_index(i) : -1) {
1204 trans_single t = offset.get_element(i);
1205 t.rescale(offset.get_current_element().scale());
1206
1207 here.diff(si, t, local_ax_count, frame);
1208
e0577945 David Hilvert2008-07-19 22:11:55 +00001209 if (here.better_defined())
1b980378
DH
David Hilvert2008-07-18 18:30:40 +00001210 here.confirm();
1211 else
1212 here.discard();
1213 }
1214
1215 return here;
1216 }
1217
46f9776a dhilvert2005-01-07 06:44:00 +00001218#ifdef USE_FFTW
1219 /*
1220 * High-pass filter for frequency weights
1221 */
1222 static void hipass(int rows, int cols, fftw_complex *inout) {
1223 for (int i = 0; i < rows * vert_freq_cut; i++)
1224 for (int j = 0; j < cols; j++)
1225 for (int k = 0; k < 2; k++)
1226 inout[i * cols + j][k] = 0;
1227 for (int i = 0; i < rows; i++)
1228 for (int j = 0; j < cols * horiz_freq_cut; j++)
1229 for (int k = 0; k < 2; k++)
1230 inout[i * cols + j][k] = 0;
1231 for (int i = 0; i < rows; i++)
1232 for (int j = 0; j < cols; j++)
1233 for (int k = 0; k < 2; k++)
1234 if (i / (double) rows + j / (double) cols < 2 * avg_freq_cut)
1235 inout[i * cols + j][k] = 0;
1236 }
1237#endif
1238
2aa417e6 dhilvert2005-01-07 06:44:00 +00001239
1240 /*
1241 * Reset alignment weights
1242 */
1243 static void reset_weights() {
07271611 dhilvert2005-01-07 06:48:00 +00001244 if (alignment_weights != NULL)
c2d1a70e David Hilvert2009-05-30 15:37:04 +00001245 ale_image_release(alignment_weights);
07271611 dhilvert2005-01-07 06:48:00 +00001246
1247 alignment_weights = NULL;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001248 }
1249
1250 /*
1251 * Initialize alignment weights
1252 */
1253 static void init_weights() {
1254 if (alignment_weights != NULL)
1255 return;
1256
3617b771 David Hilvert2009-05-31 15:07:14 +00001257 alignment_weights = ale_new_image(accel::context(), ALE_IMAGE_RGB, ale_image_get_type(reference_image));
2aa417e6 dhilvert2005-01-07 06:44:00 +00001258
1259 assert (alignment_weights);
1260
e28f8ff7 David Hilvert2009-06-02 22:23:44 +00001261 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 +00001262
bccf19c9 David Hilvert2009-07-18 19:30:20 +00001263 ale_eval("MAP_PIXEL(%0I, p, PIXEL(1, 1, 1))", alignment_weights);
2aa417e6 dhilvert2005-01-07 06:44:00 +00001264 }
1265
46f9776a dhilvert2005-01-07 06:44:00 +00001266 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00001267 * Update alignment weights with weight map
1268 */
1269 static void map_update() {
1270
1271 if (weight_map == NULL)
1272 return;
1273
1274 init_weights();
1275
bccf19c9 David Hilvert2009-07-18 19:30:20 +00001276 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 +00001277 }
1278
1279 /*
1280 * Update alignment weights with algorithmic weights
46f9776a dhilvert2005-01-07 06:44:00 +00001281 */
1282 static void wmx_update() {
1283#ifdef USE_UNIX
1284
1285 static exposure *exp_def = new exposure_default();
1286 static exposure *exp_bool = new exposure_boolean();
1287
46f9776a dhilvert2005-01-07 06:44:00 +00001288 if (wmx_file == NULL || wmx_exec == NULL || wmx_defs == NULL)
1289 return;
1290
33a3cc28
DH
David Hilvert2009-06-03 19:51:46 +00001291 unsigned int rows = ale_image_get_height(reference_image);
1292 unsigned int cols = ale_image_get_width(reference_image);
46f9776a dhilvert2005-01-07 06:44:00 +00001293
1294 image_rw::write_image(wmx_file, reference_image);
ac4577d5 David Hilvert2009-06-14 19:02:25 +00001295 image_rw::write_image(wmx_defs, reference_image, exp_bool->get_gamma(), 0, 0, 1);
46f9776a dhilvert2005-01-07 06:44:00 +00001296
1297 /* execute ... */
1298 int exit_status = 1;
1299 if (!fork()) {
1300 execlp(wmx_exec, wmx_exec, wmx_file, wmx_defs, NULL);
07271611 dhilvert2005-01-07 06:48:00 +00001301 ui::get()->exec_failure(wmx_exec, wmx_file, wmx_defs);
46f9776a dhilvert2005-01-07 06:44:00 +00001302 }
1303
1304 wait(&exit_status);
1305
07271611 dhilvert2005-01-07 06:48:00 +00001306 if (exit_status)
1307 ui::get()->fork_failure("d2::align");
46f9776a dhilvert2005-01-07 06:44:00 +00001308
c2d1a70e David Hilvert2009-05-30 15:37:04 +00001309 ale_image wmx_weights = image_rw::read_image(wmx_file, exp_def);
46f9776a dhilvert2005-01-07 06:44:00 +00001310
35c1c6e3
DH
David Hilvert2009-06-14 21:17:14 +00001311 ale_image_set_x_offset(wmx_weights, ale_image_get_x_offset(reference_image));
1312 ale_image_set_y_offset(wmx_weights, ale_image_get_y_offset(reference_image));
5073b97e David Hilvert2009-06-14 20:59:56 +00001313
c2d1a70e David Hilvert2009-05-30 15:37:04 +00001314 if (ale_image_get_height(wmx_weights) != rows || ale_image_get_width(wmx_weights) != cols)
07271611 dhilvert2005-01-07 06:48:00 +00001315 ui::get()->error("algorithmic weighting must not change image size");
2aa417e6 dhilvert2005-01-07 06:44:00 +00001316
1317 if (alignment_weights == NULL)
1318 alignment_weights = wmx_weights;
1319 else
bccf19c9 David Hilvert2009-07-18 19:30:20 +00001320 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 +00001321#endif
1322 }
1323
1324 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00001325 * Update alignment weights with frequency weights
46f9776a dhilvert2005-01-07 06:44:00 +00001326 */
1327 static void fw_update() {
1328#ifdef USE_FFTW
46f9776a dhilvert2005-01-07 06:44:00 +00001329 if (horiz_freq_cut == 0
1330 && vert_freq_cut == 0
1331 && avg_freq_cut == 0)
1332 return;
1333
2aa417e6 dhilvert2005-01-07 06:44:00 +00001334 /*
1335 * Required for correct operation of --fwshow
1336 */
1337
1338 assert (alignment_weights == NULL);
1339
46f9776a dhilvert2005-01-07 06:44:00 +00001340 int rows = reference_image->height();
1341 int cols = reference_image->width();
2aa417e6 dhilvert2005-01-07 06:44:00 +00001342 int colors = reference_image->depth();
46f9776a dhilvert2005-01-07 06:44:00 +00001343
7cc12274 David Hilvert2007-12-11 04:50:00 +00001344 alignment_weights = new_image_ale_real(rows, cols,
2aa417e6 dhilvert2005-01-07 06:44:00 +00001345 colors, "alignment_weights");
46f9776a dhilvert2005-01-07 06:44:00 +00001346
1347 fftw_complex *inout = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * rows * cols);
1348
1349 assert (inout);
1350
1351 fftw_plan pf = fftw_plan_dft_2d(rows, cols,
1352 inout, inout,
1353 FFTW_FORWARD, FFTW_ESTIMATE);
1354
1355 fftw_plan pb = fftw_plan_dft_2d(rows, cols,
1356 inout, inout,
1357 FFTW_BACKWARD, FFTW_ESTIMATE);
1358
2aa417e6 dhilvert2005-01-07 06:44:00 +00001359 for (int k = 0; k < colors; k++) {
46f9776a dhilvert2005-01-07 06:44:00 +00001360 for (int i = 0; i < rows * cols; i++) {
1361 inout[i][0] = reference_image->get_pixel(i / cols, i % cols)[k];
1362 inout[i][1] = 0;
1363 }
1364
1365 fftw_execute(pf);
1366 hipass(rows, cols, inout);
1367 fftw_execute(pb);
1368
1369 for (int i = 0; i < rows * cols; i++) {
1370#if 0
2aa417e6 dhilvert2005-01-07 06:44:00 +00001371 alignment_weights->pix(i / cols, i % cols)[k] = fabs(inout[i][0] / (rows * cols));
46f9776a dhilvert2005-01-07 06:44:00 +00001372#else
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00001373 alignment_weights->set_chan(i / cols, i % cols, k,
46f9776a dhilvert2005-01-07 06:44:00 +00001374 sqrt(pow(inout[i][0] / (rows * cols), 2)
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00001375 + pow(inout[i][1] / (rows * cols), 2)));
46f9776a dhilvert2005-01-07 06:44:00 +00001376#endif
1377 }
1378 }
1379
1380 fftw_destroy_plan(pf);
1381 fftw_destroy_plan(pb);
1382 fftw_free(inout);
1383
1384 if (fw_output != NULL)
2aa417e6 dhilvert2005-01-07 06:44:00 +00001385 image_rw::write_image(fw_output, alignment_weights);
46f9776a dhilvert2005-01-07 06:44:00 +00001386#endif
1387 }
1388
30afe4b6 dhilvert2005-01-07 06:42:00 +00001389 /*
1390 * Update alignment to frame N.
1391 */
1392 static void update_to(int n) {
0e4ec247 David Hilvert2007-03-13 04:51:00 +00001393
30afe4b6 dhilvert2005-01-07 06:42:00 +00001394 assert (n <= latest + 1);
0a432b63 David Hilvert2007-03-13 08:03:00 +00001395 assert (n >= 0);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001396
f922c1c4 David Hilvert2009-06-22 00:04:12 +00001397 ale_align_properties astate = align_properties();
f65325e3 David Hilvert2007-03-15 06:24:00 +00001398
724b1c71
DH
David Hilvert2008-07-01 15:20:56 +00001399 ui::get()->set_frame_num(n);
1400
46f9776a dhilvert2005-01-07 06:44:00 +00001401 if (latest < 0) {
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00001402
1403 /*
1404 * Handle the initial frame
1405 */
1406
8aaa492c
DH
David Hilvert2009-06-28 01:59:05 +00001407 astate.set_input_frame(image_rw::open(n));
1408
1409 const image *i = astate.get_input_frame();
46f9776a dhilvert2005-01-07 06:44:00 +00001410 int is_default;
1411 transformation result = alignment_class == 2
1412 ? transformation::gpt_identity(i, scale_factor)
1413 : transformation::eu_identity(i, scale_factor);
1414 result = tload_first(tload, alignment_class == 2, result, &is_default);
1415 tsave_first(tsave, result, alignment_class == 2);
46f9776a dhilvert2005-01-07 06:44:00 +00001416
1417 if (_keep > 0) {
dd761b64 David Hilvert2008-01-26 17:41:00 +00001418 kept_t = transformation::new_eu_identity_array(image_rw::count());
46f9776a dhilvert2005-01-07 06:44:00 +00001419 kept_ok = (int *) malloc(image_rw::count()
1420 * sizeof(int));
1421 assert (kept_t);
1422 assert (kept_ok);
1423
07271611 dhilvert2005-01-07 06:48:00 +00001424 if (!kept_t || !kept_ok)
1425 ui::get()->memory_error("alignment");
46f9776a dhilvert2005-01-07 06:44:00 +00001426
1427 kept_ok[0] = 1;
1428 kept_t[0] = result;
1429 }
1430
1431 latest = 0;
1432 latest_ok = 1;
1433 latest_t = result;
1434
0467efe3 David Hilvert2008-04-09 21:14:38 +00001435 astate.set_default(result);
46f9776a dhilvert2005-01-07 06:44:00 +00001436 orig_t = result;
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00001437
1438 image_rw::close(n);
46f9776a dhilvert2005-01-07 06:44:00 +00001439 }
1440
bbc7699c David Hilvert2007-04-02 03:05:00 +00001441 for (int i = latest + 1; i <= n; i++) {
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00001442
1443 /*
1444 * Handle supplemental frames.
1445 */
1446
46f9776a dhilvert2005-01-07 06:44:00 +00001447 assert (reference != NULL);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001448
07271611 dhilvert2005-01-07 06:48:00 +00001449 ui::get()->set_arender_current();
46f9776a dhilvert2005-01-07 06:44:00 +00001450 reference->sync(i - 1);
07271611 dhilvert2005-01-07 06:48:00 +00001451 ui::get()->clear_arender_current();
46f9776a dhilvert2005-01-07 06:44:00 +00001452 reference_image = reference->get_image();
1453 reference_defined = reference->get_defined();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001454
f2fc9b99 David Hilvert2008-02-14 17:35:00 +00001455 if (i == 1)
0467efe3 David Hilvert2008-04-09 21:14:38 +00001456 astate.default_set_original_bounds(reference_image);
f2fc9b99 David Hilvert2008-02-14 17:35:00 +00001457
2aa417e6 dhilvert2005-01-07 06:44:00 +00001458 reset_weights();
46f9776a dhilvert2005-01-07 06:44:00 +00001459 fw_update();
1460 wmx_update();
2aa417e6 dhilvert2005-01-07 06:44:00 +00001461 map_update();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001462
46f9776a dhilvert2005-01-07 06:44:00 +00001463 assert (reference_image != NULL);
1464 assert (reference_defined != NULL);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001465
0467efe3 David Hilvert2008-04-09 21:14:38 +00001466 astate.set_input_frame(image_rw::open(i));
0a432b63 David Hilvert2007-03-13 08:03:00 +00001467
e580d9d3 David Hilvert2007-12-19 16:59:00 +00001468 _align(i, _gs, &astate);
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00001469
1470 image_rw::close(n);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001471 }
1472 }
1473
1474public:
1475
1476 /*
04382119 dhilvert2005-04-29 09:23:00 +00001477 * Set the control point count
1478 */
1479 static void set_cp_count(unsigned int n) {
1480 assert (cp_array == NULL);
1481
1482 cp_count = n;
1483 cp_array = (const point **) malloc(n * sizeof(const point *));
1484 }
1485
1486 /*
1487 * Set control points.
1488 */
1489 static void set_cp(unsigned int i, const point *p) {
1490 cp_array[i] = p;
1491 }
1492
1493 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00001494 * Register exposure
1495 */
1496 static void exp_register() {
1497 _exp_register = 1;
1498 }
1499
1500 /*
3dc20778 dhilvert2005-01-10 23:06:00 +00001501 * Register exposure only based on metadata
1502 */
1503 static void exp_meta_only() {
1504 _exp_register = 2;
1505 }
1506
1507 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00001508 * Don't register exposure
1509 */
1510 static void exp_noregister() {
1511 _exp_register = 0;
1512 }
1513
1514 /*
1515 * Set alignment class to translation only. Only adjust the x and y
1516 * position of images. Do not rotate input images or perform
1517 * projective transformations.
1518 */
1519 static void class_translation() {
1520 alignment_class = 0;
1521 }
1522
1523 /*
1524 * Set alignment class to Euclidean transformations only. Adjust the x
1525 * and y position of images and the orientation of the image about the
1526 * image center.
1527 */
1528 static void class_euclidean() {
1529 alignment_class = 1;
1530 }
1531
1532 /*
1533 * Set alignment class to perform general projective transformations.
1534 * See the file gpt.h for more information about general projective
1535 * transformations.
1536 */
1537 static void class_projective() {
1538 alignment_class = 2;
1539 }
1540
1541 /*
1542 * Set the default initial alignment to the identity transformation.
1543 */
1544 static void initial_default_identity() {
1545 default_initial_alignment_type = 0;
1546 }
1547
1548 /*
1549 * Set the default initial alignment to the most recently matched
1550 * frame's final transformation.
1551 */
1552 static void initial_default_follow() {
1553 default_initial_alignment_type = 1;
1554 }
1555
1556 /*
f09b7254 dhilvert2005-01-07 06:44:00 +00001557 * Perturb output coordinates.
1558 */
1559 static void perturb_output() {
1560 perturb_type = 0;
1561 }
1562
1563 /*
1564 * Perturb source coordinates.
1565 */
1566 static void perturb_source() {
1567 perturb_type = 1;
1568 }
1569
1570 /*
46f9776a dhilvert2005-01-07 06:44:00 +00001571 * Frames under threshold align optimally
1572 */
1573 static void fail_optimal() {
1574 is_fail_default = 0;
1575 }
1576
1577 /*
1578 * Frames under threshold keep their default alignments.
1579 */
1580 static void fail_default() {
1581 is_fail_default = 1;
1582 }
1583
1584 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00001585 * Align images with an error contribution from each color channel.
1586 */
1587 static void all() {
1588 channel_alignment_type = 0;
1589 }
1590
1591 /*
1592 * Align images with an error contribution only from the green channel.
1593 * Other color channels do not affect alignment.
1594 */
1595 static void green() {
1596 channel_alignment_type = 1;
1597 }
1598
1599 /*
1600 * Align images using a summation of channels. May be useful when
1601 * dealing with images that have high frequency color ripples due to
1602 * color aliasing.
1603 */
1604 static void sum() {
1605 channel_alignment_type = 2;
1606 }
1607
1608 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00001609 * Error metric exponent
1610 */
1611
1612 static void set_metric_exponent(float me) {
1613 metric_exponent = me;
1614 }
1615
1616 /*
1617 * Match threshold
1618 */
1619
1620 static void set_match_threshold(float mt) {
1621 match_threshold = mt;
1622 }
1623
1624 /*
1625 * Perturbation lower and upper bounds.
1626 */
1627
f09b7254 dhilvert2005-01-07 06:44:00 +00001628 static void set_perturb_lower(ale_pos pl, int plp) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001629 perturb_lower = pl;
f09b7254 dhilvert2005-01-07 06:44:00 +00001630 perturb_lower_percent = plp;
30afe4b6 dhilvert2005-01-07 06:42:00 +00001631 }
1632
f09b7254 dhilvert2005-01-07 06:44:00 +00001633 static void set_perturb_upper(ale_pos pu, int pup) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001634 perturb_upper = pu;
f09b7254 dhilvert2005-01-07 06:44:00 +00001635 perturb_upper_percent = pup;
30afe4b6 dhilvert2005-01-07 06:42:00 +00001636 }
1637
1638 /*
1639 * Maximum rotational perturbation.
1640 */
1641
1642 static void set_rot_max(int rm) {
1643
1644 /*
1645 * Obtain the largest power of two not larger than rm.
1646 */
1647
1648 rot_max = pow(2, floor(log(rm) / log(2)));
1649 }
1650
1651 /*
46f9776a dhilvert2005-01-07 06:44:00 +00001652 * Barrel distortion adjustment multiplier
1653 */
1654
1655 static void set_bda_mult(ale_pos m) {
1656 bda_mult = m;
1657 }
1658
1659 /*
1660 * Barrel distortion maximum rate of change
1661 */
1662
1663 static void set_bda_rate(ale_pos m) {
1664 bda_rate = m;
1665 }
1666
1667 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00001668 * Level-of-detail
1669 */
1670
5292ffa7
DH
David Hilvert2008-05-28 01:17:53 +00001671 static void set_lod_preferred(int lm) {
1672 lod_preferred = lm;
1673 }
1674
1675 /*
1676 * Minimum dimension for reduced level-of-detail.
1677 */
1678
1679 static void set_min_dimension(int md) {
1680 min_dimension = md;
30afe4b6 dhilvert2005-01-07 06:42:00 +00001681 }
1682
1683 /*
1684 * Set the scale factor
1685 */
1686 static void set_scale(ale_pos s) {
1687 scale_factor = s;
1688 }
1689
1690 /*
1691 * Set reference rendering to align against
1692 */
1693 static void set_reference(render *r) {
1694 reference = r;
1695 }
1696
1697 /*
46f9776a dhilvert2005-01-07 06:44:00 +00001698 * Set the interpolant
1699 */
1700 static void set_interpolant(filter::scaled_filter *f) {
1701 interpolant = f;
1702 }
1703
1704 /*
1705 * Set alignment weights image
1706 */
2aa417e6 dhilvert2005-01-07 06:44:00 +00001707 static void set_weight_map(const image *i) {
1708 weight_map = i;
46f9776a dhilvert2005-01-07 06:44:00 +00001709 }
1710
1711 /*
1712 * Set frequency cuts
1713 */
1714 static void set_frequency_cut(double h, double v, double a) {
1715 horiz_freq_cut = h;
1716 vert_freq_cut = v;
1717 avg_freq_cut = a;
1718 }
1719
1720 /*
1721 * Set algorithmic alignment weighting
1722 */
1723 static void set_wmx(const char *e, const char *f, const char *d) {
1724 wmx_exec = e;
1725 wmx_file = f;
1726 wmx_defs = d;
1727 }
1728
1729 /*
1730 * Show frequency weights
1731 */
1732 static void set_fl_show(const char *filename) {
1733 fw_output = filename;
1734 }
1735
1736 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00001737 * Set transformation file loader.
1738 */
1739 static void set_tload(tload_t *tl) {
1740 tload = tl;
1741 }
1742
1743 /*
1744 * Set transformation file saver.
1745 */
1746 static void set_tsave(tsave_t *ts) {
1747 tsave = ts;
1748 }
1749
1750 /*
1751 * Get match statistics for frame N.
30afe4b6 dhilvert2005-01-07 06:42:00 +00001752 */
1753 static int match(int n) {
1754 update_to(n);
1755
46f9776a dhilvert2005-01-07 06:44:00 +00001756 if (n == latest)
30afe4b6 dhilvert2005-01-07 06:42:00 +00001757 return latest_ok;
1758 else if (_keep)
1759 return kept_ok[n];
46f9776a dhilvert2005-01-07 06:44:00 +00001760 else {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001761 assert(0);
46f9776a dhilvert2005-01-07 06:44:00 +00001762 exit(1);
1763 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001764 }
1765
1766 /*
1767 * Message that old alignment data should be kept.
1768 */
1769 static void keep() {
46f9776a dhilvert2005-01-07 06:44:00 +00001770 assert (latest == -1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001771 _keep = 1;
1772 }
1773
1774 /*
1775 * Get alignment for frame N.
30afe4b6 dhilvert2005-01-07 06:42:00 +00001776 */
1777 static transformation of(int n) {
1778 update_to(n);
46f9776a dhilvert2005-01-07 06:44:00 +00001779 if (n == latest)
30afe4b6 dhilvert2005-01-07 06:42:00 +00001780 return latest_t;
1781 else if (_keep)
1782 return kept_t[n];
1783 else {
1784 assert(0);
1785 exit(1);
1786 }
1787 }
1788
1789 /*
bddc9e4d David Hilvert2007-10-01 19:50:00 +00001790 * Use Monte Carlo alignment sampling with argument N.
1c2f7405 David Hilvert2007-09-20 16:58:00 +00001791 */
bddc9e4d
DH
David Hilvert2007-10-01 19:50:00 +00001792 static void mc(ale_pos n) {
1793 _mc = n;
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +00001794 }
1795
1796 /*
07271611 dhilvert2005-01-07 06:48:00 +00001797 * Set the certainty-weighted flag.
1798 */
1799 static void certainty_weighted(int flag) {
1800 certainty_weights = flag;
1801 }
1802
1803 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00001804 * Set the global search type.
1805 */
1806 static void gs(const char *type) {
7bcfe5db dhilvert2005-01-07 06:44:00 +00001807 if (!strcmp(type, "local")) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001808 _gs = 0;
1809 } else if (!strcmp(type, "inner")) {
1810 _gs = 1;
1811 } else if (!strcmp(type, "outer")) {
1812 _gs = 2;
1813 } else if (!strcmp(type, "all")) {
1814 _gs = 3;
1815 } else if (!strcmp(type, "central")) {
1816 _gs = 4;
842afc18
DH
David Hilvert2007-05-08 06:55:00 +00001817 } else if (!strcmp(type, "defaults")) {
1818 _gs = 6;
04382119 dhilvert2005-04-29 09:23:00 +00001819 } else if (!strcmp(type, "points")) {
1820 _gs = 5;
b386e644 dhilvert2005-04-30 09:28:00 +00001821 keep();
2aa417e6 dhilvert2005-01-07 06:44:00 +00001822 } else {
07271611 dhilvert2005-01-07 06:48:00 +00001823 ui::get()->error("bad global search type");
2aa417e6 dhilvert2005-01-07 06:44:00 +00001824 }
1825 }
1826
1827 /*
4949c031 dhilvert2005-01-07 06:44:00 +00001828 * Set the minimum overlap for global searching
1829 */
326c35b1 David Hilvert2007-04-19 21:28:00 +00001830 static void gs_mo(ale_pos value, int _gs_mo_percent) {
4949c031 dhilvert2005-01-07 06:44:00 +00001831 _gs_mo = value;
326c35b1 David Hilvert2007-04-19 21:28:00 +00001832 gs_mo_percent = _gs_mo_percent;
4949c031 dhilvert2005-01-07 06:44:00 +00001833 }
1834
1835 /*
903df240
DH
David Hilvert2008-04-24 14:36:35 +00001836 * Set mutli-alignment certainty lower bound.
1837 */
1838 static void set_ma_cert(ale_real value) {
1839 _ma_cert = value;
1840 }
1841
1842 /*
46f9776a dhilvert2005-01-07 06:44:00 +00001843 * Set alignment exclusion regions
1844 */
df55d1a2 dhilvert2006-08-30 07:40:00 +00001845 static void set_exclusion(exclusion *_ax_parameters, int _ax_count) {
46f9776a dhilvert2005-01-07 06:44:00 +00001846 ax_count = _ax_count;
1847 ax_parameters = _ax_parameters;
1848 }
1849
1850 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00001851 * Get match summary statistics.
1852 */
1853 static ale_accum match_summary() {
34add5e1 David Hilvert2007-10-17 21:47:00 +00001854 return match_sum / (ale_accum) match_count;
30afe4b6 dhilvert2005-01-07 06:42:00 +00001855 }
1856};
1857
1858#endif