d2/align: Specify instance for original bounds set operation.
[Ale.git] / d2 / align.h
Commit [+] Author Date Line Data
8a81d3be
DH
David Hilvert2007-04-03 18:57:00 +00001// Copyright 2002, 2004, 2007 David Hilvert <dhilvert@auricle.dyndns.org>,
2// <dhilvert@ugcs.caltech.edu>
30afe4b6 dhilvert2005-01-07 06:42:00 +00003
4/* This file is part of the Anti-Lamenessing Engine.
5
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
70932f40 David Hilvert2007-07-19 21:14:00 +00008 the Free Software Foundation; either version 3 of the License, or
30afe4b6 dhilvert2005-01-07 06:42:00 +00009 (at your option) any later version.
10
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/*
22 * align.h: Handle alignment of frames.
23 */
24
25#ifndef __d2align_h__
26#define __d2align_h__
27
46f9776a dhilvert2005-01-07 06:44:00 +000028#include "filter.h"
29#include "transformation.h"
30afe4b6 dhilvert2005-01-07 06:42:00 +000030#include "image.h"
31#include "point.h"
32#include "render.h"
33#include "tfile.h"
34#include "image_rw.h"
35
36class align {
37private:
38
39 /*
40 * Private data members
41 */
42
43 static ale_pos scale_factor;
44
45 /*
46f9776a dhilvert2005-01-07 06:44:00 +000046 * Original frame transformation
47 */
48 static transformation orig_t;
49
50 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +000051 * Keep data older than latest
52 */
53 static int _keep;
54 static transformation *kept_t;
55 static int *kept_ok;
56
57 /*
58 * Transformation file handlers
59 */
60
61 static tload_t *tload;
62 static tsave_t *tsave;
63
64 /*
04382119 dhilvert2005-04-29 09:23:00 +000065 * Control point variables
66 */
67
68 static const point **cp_array;
69 static unsigned int cp_count;
70
71 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +000072 * Reference rendering to align against
73 */
74
75 static render *reference;
46f9776a dhilvert2005-01-07 06:44:00 +000076 static filter::scaled_filter *interpolant;
3617b771 David Hilvert2009-05-31 15:07:14 +000077 static ale_image reference_image;
30afe4b6 dhilvert2005-01-07 06:42:00 +000078
46f9776a dhilvert2005-01-07 06:44:00 +000079 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +000080 * Per-pixel alignment weight map
46f9776a dhilvert2005-01-07 06:44:00 +000081 */
82
2f4c0699 David Hilvert2009-06-03 19:47:53 +000083 static ale_image weight_map;
46f9776a dhilvert2005-01-07 06:44:00 +000084
85 /*
86 * Frequency-dependent alignment weights
87 */
88
89 static double horiz_freq_cut;
90 static double vert_freq_cut;
91 static double avg_freq_cut;
46f9776a dhilvert2005-01-07 06:44:00 +000092 static const char *fw_output;
93
94 /*
95 * Algorithmic alignment weighting
96 */
97
98 static const char *wmx_exec;
99 static const char *wmx_file;
100 static const char *wmx_defs;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000101
102 /*
19b07c65 David Hilvert2007-09-11 18:07:00 +0000103 * Non-certainty alignment weights
2aa417e6 dhilvert2005-01-07 06:44:00 +0000104 */
105
c2d1a70e David Hilvert2009-05-30 15:37:04 +0000106 static ale_image alignment_weights;
46f9776a dhilvert2005-01-07 06:44:00 +0000107
30afe4b6 dhilvert2005-01-07 06:42:00 +0000108 /*
109 * Latest transformation.
110 */
111
112 static transformation latest_t;
113
114 /*
115 * Flag indicating whether the latest transformation
116 * resulted in a match.
117 */
118
119 static int latest_ok;
120
121 /*
122 * Frame number most recently aligned.
123 */
124
125 static int latest;
126
127 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000128 * Exposure registration
129 *
130 * 0. Preserve the original exposure of images.
131 *
132 * 1. Match exposure between images.
3dc20778 dhilvert2005-01-10 23:06:00 +0000133 *
134 * 2. Use only image metadata for registering exposure.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000135 */
136
137 static int _exp_register;
138
139 /*
140 * Alignment class.
141 *
142 * 0. Translation only. Only adjust the x and y position of images.
143 * Do not rotate input images or perform projective transformations.
144 *
145 * 1. Euclidean transformations only. Adjust the x and y position
146 * of images and the orientation of the image about the image center.
147 *
148 * 2. Perform general projective transformations. See the file gpt.h
149 * for more information about general projective transformations.
150 */
151
152 static int alignment_class;
153
154 /*
0a432b63 David Hilvert2007-03-13 08:03:00 +0000155 * Default initial alignment type.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000156 *
157 * 0. Identity transformation.
158 *
159 * 1. Most recently accepted frame's final transformation.
160 */
161
162 static int default_initial_alignment_type;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000163
164 /*
f09b7254 dhilvert2005-01-07 06:44:00 +0000165 * Projective group behavior
166 *
167 * 0. Perturb in output coordinates.
168 *
169 * 1. Perturb in source coordinates
170 */
171
172 static int perturb_type;
173
174 /*
e580d9d3 David Hilvert2007-12-19 16:59:00 +0000175 * Alignment state
30afe4b6 dhilvert2005-01-07 06:42:00 +0000176 *
e580d9d3
DH
David Hilvert2007-12-19 16:59:00 +0000177 * This structure contains alignment state information. The change
178 * between the non-default old initial alignment and old final
179 * alignment is used to adjust the non-default current initial
180 * alignment. If either the old or new initial alignment is a default
181 * alignment, the old --follow semantics are preserved.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000182 */
183
0467efe3 David Hilvert2008-04-09 21:14:38 +0000184 class astate_t {
071127c8
DH
David Hilvert2009-06-14 23:55:39 +0000185 ale_trans old_initial_alignment;
186 ale_trans old_final_alignment;
187 ale_trans default_initial_alignment;
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000188 int old_is_default;
189 std::vector<int> is_default;
071127c8 David Hilvert2009-06-14 23:55:39 +0000190 ale_image input_frame;
0e4ec247
DH
David Hilvert2007-03-13 04:51:00 +0000191
192 public:
283c3ecc David Hilvert2008-01-26 01:36:00 +0000193 astate_t() :
0467efe3 David Hilvert2008-04-09 21:14:38 +0000194 is_default(1) {
283c3ecc David Hilvert2008-01-26 01:36:00 +0000195
0b733568
DH
David Hilvert2009-06-15 20:43:18 +0000196 old_initial_alignment = ale_new_trans(accel::context(), NULL);
197 old_final_alignment = ale_new_trans(accel::context(), NULL);
198 default_initial_alignment = ale_new_trans(accel::context(), NULL);
199
0a432b63 David Hilvert2007-03-13 08:03:00 +0000200 input_frame = NULL;
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000201 is_default[0] = 1;
202 old_is_default = 1;
203 }
204
071127c8 David Hilvert2009-06-14 23:55:39 +0000205 ale_image get_input_frame() const {
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000206 return input_frame;
207 }
208
21733e56
DH
David Hilvert2008-04-10 03:39:03 +0000209 void set_is_default(unsigned int index, int value) {
210
211 /*
212 * Expand the array, if necessary.
213 */
214 if (index == is_default.size());
215 is_default.resize(index + 1);
216
217 assert (index < is_default.size());
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000218 is_default[index] = value;
219 }
220
21733e56
DH
David Hilvert2008-04-10 03:39:03 +0000221 int get_is_default(unsigned int index) {
222 assert (index < is_default.size());
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000223 return is_default[index];
224 }
225
0b733568 David Hilvert2009-06-15 20:43:18 +0000226 ale_trans get_default() {
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000227 return default_initial_alignment;
228 }
229
0b733568 David Hilvert2009-06-15 20:43:18 +0000230 void set_default(ale_trans t) {
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000231 default_initial_alignment = t;
232 }
233
9b4c5ba6 David Hilvert2009-06-16 21:34:26 +0000234 void default_set_original_bounds(ale_image i) {
7cc7cefe David Hilvert2009-06-17 22:45:14 +0000235 ale_trans_set_original_bounds(default_initial_alignment, i);
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000236 }
237
238 void set_final(transformation t) {
239 old_final_alignment = t;
240 }
241
071127c8 David Hilvert2009-06-14 23:55:39 +0000242 void set_input_frame(ale_image i) {
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000243 input_frame = i;
244 }
245
246 /*
247 * Implement new delta --follow semantics.
248 *
249 * If we have a transformation T such that
250 *
251 * prev_final == T(prev_init)
252 *
253 * Then we also have
254 *
255 * current_init_follow == T(current_init)
256 *
257 * We can calculate T as follows:
258 *
259 * T == prev_final(prev_init^-1)
260 *
261 * Where ^-1 is the inverse operator.
262 */
263 static trans_single follow(trans_single a, trans_single b, trans_single c) {
264 trans_single cc = c;
265
266 if (alignment_class == 0) {
267 /*
268 * Translational transformations
269 */
270
271 ale_pos t0 = -a.eu_get(0) + b.eu_get(0);
272 ale_pos t1 = -a.eu_get(1) + b.eu_get(1);
273
274 cc.eu_modify(0, t0);
275 cc.eu_modify(1, t1);
276
277 } else if (alignment_class == 1) {
278 /*
279 * Euclidean transformations
280 */
281
282 ale_pos t2 = -a.eu_get(2) + b.eu_get(2);
283
284 cc.eu_modify(2, t2);
285
286 point p( c.scaled_height()/2 + c.eu_get(0) - a.eu_get(0),
287 c.scaled_width()/2 + c.eu_get(1) - a.eu_get(1) );
288
289 p = b.transform_scaled(p);
290
291 cc.eu_modify(0, p[0] - c.scaled_height()/2 - c.eu_get(0));
292 cc.eu_modify(1, p[1] - c.scaled_width()/2 - c.eu_get(1));
293
294 } else if (alignment_class == 2) {
295 /*
296 * Projective transformations
297 */
298
299 point p[4];
300
301 p[0] = b.transform_scaled(a
302 . scaled_inverse_transform(c.transform_scaled(point( 0 , 0 ))));
303 p[1] = b.transform_scaled(a
304 . scaled_inverse_transform(c.transform_scaled(point(c.scaled_height(), 0 ))));
305 p[2] = b.transform_scaled(a
306 . scaled_inverse_transform(c.transform_scaled(point(c.scaled_height(), c.scaled_width()))));
307 p[3] = b.transform_scaled(a
308 . scaled_inverse_transform(c.transform_scaled(point( 0 , c.scaled_width()))));
309
310 cc.gpt_set(p);
311 }
312
313 return cc;
314 }
315
316 /*
317 * For multi-alignment following, we use the following approach, not
318 * guaranteed to work with large changes in scene or perspective, but
319 * which should be somewhat flexible:
320 *
321 * For
322 *
323 * t[][] calculated final alignments
324 * s[][] alignments as loaded from file
325 * previous frame n
326 * current frame n+1
327 * fundamental (primary) 0
328 * non-fundamental (non-primary) m!=0
329 * parent element m'
330 * follow(a, b, c) applying the (a, b) delta T=b(a^-1) to c
331 *
332 * following in the case of missing file data might be generated by
333 *
334 * t[n+1][0] = t[n][0]
335 * t[n+1][m!=0] = follow(t[n][m'], t[n+1][m'], t[n][m])
336 *
337 * cases with all noted file data present might be generated by
338 *
339 * t[n+1][0] = follow(s[n][0], t[n][0], s[n+1][0])
340 * t[n+1][m!=0] = follow(s[n+1][m'], t[n+1][m'], s[n+1][m])
341 *
342 * For non-following behavior, or where assigning the above is
343 * impossible, we assign the following default
344 *
345 * t[n+1][0] = Identity
346 * t[n+1][m!=0] = t[n+1][m']
347 */
348
349 void init_frame_alignment_primary(transformation *offset, int lod, ale_pos perturb) {
350
21733e56 David Hilvert2008-04-10 03:39:03 +0000351 if (perturb > 0 && !old_is_default && !get_is_default(0)
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000352 && default_initial_alignment_type == 1) {
353
354 /*
355 * Apply following logic for the primary element.
356 */
357
358 ui::get()->following();
359
360 trans_single new_offset = follow(old_initial_alignment.get_element(0),
361 old_final_alignment.get_element(0),
362 offset->get_element(0));
363
364 old_initial_alignment = *offset;
365
366 offset->set_element(0, new_offset);
367
368 ui::get()->set_offset(new_offset);
369 } else {
370 old_initial_alignment = *offset;
371 }
21733e56
DH
David Hilvert2008-04-10 03:39:03 +0000372
373 is_default.resize(old_initial_alignment.stack_depth());
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000374 }
375
376 void init_frame_alignment_nonprimary(transformation *offset,
377 int lod, ale_pos perturb, unsigned int index) {
378
379 assert (index > 0);
380
381 unsigned int parent_index = offset->parent_index(index);
382
383 if (perturb > 0
21733e56
DH
David Hilvert2008-04-10 03:39:03 +0000384 && !get_is_default(parent_index)
385 && !get_is_default(index)
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000386 && default_initial_alignment_type == 1) {
387
388 /*
389 * Apply file-based following logic for the
390 * given element.
391 */
392
393 ui::get()->following();
394
395 trans_single new_offset = follow(old_initial_alignment.get_element(parent_index),
396 offset->get_element(parent_index),
397 offset->get_element(index));
398
399 old_initial_alignment.set_element(index, offset->get_element(index));
400 offset->set_element(index, new_offset);
401
402 ui::get()->set_offset(new_offset);
403
404 return;
405 }
406
407 offset->get_coordinate(parent_index);
408
409
410 if (perturb > 0
411 && old_final_alignment.exists(offset->get_coordinate(parent_index))
412 && old_final_alignment.exists(offset->get_current_coordinate())
413 && default_initial_alignment_type == 1) {
414
415 /*
416 * Apply nonfile-based following logic for
417 * the given element.
418 */
419
420 ui::get()->following();
421
422 /*
423 * XXX: Although it is different, the below
424 * should be equivalent to the comment
425 * description.
426 */
427
428 trans_single a = old_final_alignment.get_element(offset->get_coordinate(parent_index));
429 trans_single b = old_final_alignment.get_element(offset->get_current_coordinate());
430 trans_single c = offset->get_element(parent_index);
431
432 trans_single new_offset = follow(a, b, c);
433
434 offset->set_element(index, new_offset);
435 ui::get()->set_offset(new_offset);
436
437 return;
438 }
439
440 /*
441 * Handle other cases.
442 */
443
21733e56 David Hilvert2008-04-10 03:39:03 +0000444 if (get_is_default(index)) {
0467efe3
DH
David Hilvert2008-04-09 21:14:38 +0000445 offset->set_element(index, offset->get_element(parent_index));
446 ui::get()->set_offset(offset->get_element(index));
447 }
448 }
449
450 void init_default() {
451
452 if (default_initial_alignment_type == 0) {
453
454 /*
455 * Follow the transformation of the original frame,
456 * setting new image dimensions.
457 */
458
459 // astate->default_initial_alignment = orig_t;
460 default_initial_alignment.set_current_element(orig_t.get_element(0));
461 default_initial_alignment.set_dimensions(input_frame);
462
463 } else if (default_initial_alignment_type == 1)
464
465 /*
466 * Follow previous transformation, setting new image
467 * dimensions.
468 */
469
470 default_initial_alignment.set_dimensions(input_frame);
471
472 else
473 assert(0);
474
21733e56 David Hilvert2008-04-10 03:39:03 +0000475 old_is_default = get_is_default(0);
0e4ec247
DH
David Hilvert2007-03-13 04:51:00 +0000476 }
477 };
30afe4b6 dhilvert2005-01-07 06:42:00 +0000478
479 /*
46f9776a dhilvert2005-01-07 06:44:00 +0000480 * Alignment for failed frames -- default or optimal?
481 *
482 * A frame that does not meet the match threshold can be assigned the
483 * best alignment found, or can be assigned its alignment default.
484 */
485
486 static int is_fail_default;
487
488 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000489 * Alignment code.
490 *
491 * 0. Align images with an error contribution from each color channel.
492 *
493 * 1. Align images with an error contribution only from the green channel.
494 * Other color channels do not affect alignment.
495 *
496 * 2. Align images using a summation of channels. May be useful when dealing
497 * with images that have high frequency color ripples due to color aliasing.
498 */
499
500 static int channel_alignment_type;
501
502 /*
503 * Error metric exponent
504 */
505
42772195 David Hilvert2007-10-21 15:36:00 +0000506 static ale_real metric_exponent;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000507
508 /*
509 * Match threshold
510 */
511
512 static float match_threshold;
513
514 /*
515 * Perturbation lower and upper bounds.
516 */
517
518 static ale_pos perturb_lower;
f09b7254 dhilvert2005-01-07 06:44:00 +0000519 static int perturb_lower_percent;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000520 static ale_pos perturb_upper;
f09b7254 dhilvert2005-01-07 06:44:00 +0000521 static int perturb_upper_percent;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000522
523 /*
5292ffa7 David Hilvert2008-05-28 01:17:53 +0000524 * Preferred level-of-detail scale factor is 2^lod_preferred/perturb.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000525 */
526
5292ffa7
DH
David Hilvert2008-05-28 01:17:53 +0000527 static int lod_preferred;
528
529 /*
530 * Minimum dimension for reduced LOD.
531 */
532
533 static int min_dimension;
30afe4b6 dhilvert2005-01-07 06:42:00 +0000534
535 /*
536 * Maximum rotational perturbation
537 */
538
539 static ale_pos rot_max;
540
541 /*
46f9776a dhilvert2005-01-07 06:44:00 +0000542 * Barrel distortion alignment multiplier
543 */
544
545 static ale_pos bda_mult;
546
547 /*
548 * Barrel distortion maximum adjustment rate
549 */
550
551 static ale_pos bda_rate;
552
553 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000554 * Alignment match sum
555 */
556
557 static ale_accum match_sum;
558
559 /*
560 * Alignment match count.
561 */
562
563 static int match_count;
564
565 /*
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000566 * Monte Carlo parameter
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +0000567 */
568
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000569 static ale_pos _mc;
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +0000570
571 /*
07271611 dhilvert2005-01-07 06:48:00 +0000572 * Certainty weight flag
573 *
574 * 0. Don't use certainty weights for alignment.
575 *
576 * 1. Use certainty weights for alignment.
577 */
578
579 static int certainty_weights;
580
581 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +0000582 * Global search parameter
583 *
7bcfe5db dhilvert2005-01-07 06:44:00 +0000584 * 0. Local: Local search only.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000585 * 1. Inner: Alignment reference image inner region
586 * 2. Outer: Alignment reference image outer region
7bcfe5db dhilvert2005-01-07 06:44:00 +0000587 * 3. All: Alignment reference image inner and outer regions.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000588 * 4. Central: Inner if possible; else, best of inner and outer.
04382119 dhilvert2005-04-29 09:23:00 +0000589 * 5. Points: Align by control points.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000590 */
591
592 static int _gs;
593
594 /*
4949c031 dhilvert2005-01-07 06:44:00 +0000595 * Minimum overlap for global searches
596 */
597
a7882498 David Hilvert2007-10-16 19:48:00 +0000598 static ale_accum _gs_mo;
326c35b1 David Hilvert2007-04-19 21:28:00 +0000599 static int gs_mo_percent;
4949c031 dhilvert2005-01-07 06:44:00 +0000600
601 /*
903df240
DH
David Hilvert2008-04-24 14:36:35 +0000602 * Minimum certainty for multi-alignment element registration.
603 */
604
605 static ale_real _ma_cert;
606
607 /*
46f9776a dhilvert2005-01-07 06:44:00 +0000608 * Exclusion regions
609 */
610
df55d1a2 dhilvert2006-08-30 07:40:00 +0000611 static exclusion *ax_parameters;
46f9776a dhilvert2005-01-07 06:44:00 +0000612 static int ax_count;
613
614 /*
773018a3 David Hilvert2007-09-07 15:14:00 +0000615 * Types for scale clusters.
2aa417e6 dhilvert2005-01-07 06:44:00 +0000616 */
617
773018a3
DH
David Hilvert2007-09-07 15:14:00 +0000618 struct nl_scale_cluster {
619 const image *accum_max;
620 const image *accum_min;
580b5321
DH
David Hilvert2007-09-10 17:35:00 +0000621 const image *certainty_max;
622 const image *certainty_min;
773018a3
DH
David Hilvert2007-09-07 15:14:00 +0000623 const image *aweight_max;
624 const image *aweight_min;
625 exclusion *ax_parameters;
626
627 ale_pos input_scale;
e7f30dec
DH
David Hilvert2007-09-21 19:25:00 +0000628 const image *input_certainty_max;
629 const image *input_certainty_min;
773018a3
DH
David Hilvert2007-09-07 15:14:00 +0000630 const image *input_max;
631 const image *input_min;
632 };
633
2aa417e6 dhilvert2005-01-07 06:44:00 +0000634 struct scale_cluster {
635 const image *accum;
580b5321 David Hilvert2007-09-10 17:35:00 +0000636 const image *certainty;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000637 const image *aweight;
df55d1a2 dhilvert2006-08-30 07:40:00 +0000638 exclusion *ax_parameters;
07271611 dhilvert2005-01-07 06:48:00 +0000639
640 ale_pos input_scale;
e7f30dec David Hilvert2007-09-21 19:25:00 +0000641 const image *input_certainty;
07271611 dhilvert2005-01-07 06:48:00 +0000642 const image *input;
46cc7d96
DH
David Hilvert2007-09-07 17:18:00 +0000643
644 nl_scale_cluster *nl_scale_clusters;
2aa417e6 dhilvert2005-01-07 06:44:00 +0000645 };
646
647 /*
df55d1a2 dhilvert2006-08-30 07:40:00 +0000648 * Check for exclusion region coverage in the reference
649 * array.
650 */
651 static int ref_excluded(int i, int j, point offset, exclusion *params, int param_count) {
652 for (int idx = 0; idx < param_count; idx++)
653 if (params[idx].type == exclusion::RENDER
654 && i + offset[0] >= params[idx].x[0]
655 && i + offset[0] <= params[idx].x[1]
656 && j + offset[1] >= params[idx].x[2]
657 && j + offset[1] <= params[idx].x[3])
658 return 1;
659
660 return 0;
661 }
662
663 /*
664 * Check for exclusion region coverage in the input
665 * array.
666 */
667 static int input_excluded(ale_pos ti, ale_pos tj, exclusion *params, int param_count) {
668 for (int idx = 0; idx < param_count; idx++)
669 if (params[idx].type == exclusion::FRAME
670 && ti >= params[idx].x[0]
671 && ti <= params[idx].x[1]
672 && tj >= params[idx].x[2]
673 && tj <= params[idx].x[3])
674 return 1;
675
676 return 0;
677 }
678
679 /*
4949c031 dhilvert2005-01-07 06:44:00 +0000680 * Overlap function. Determines the number of pixels in areas where
681 * the arrays overlap. Uses the reference array's notion of pixel
682 * positions.
683 */
684 static unsigned int overlap(struct scale_cluster c, transformation t, int ax_count) {
685 assert (reference_image);
686
687 unsigned int result = 0;
688
689 point offset = c.accum->offset();
690
691 for (unsigned int i = 0; i < c.accum->height(); i++)
692 for (unsigned int j = 0; j < c.accum->width(); j++) {
693
df55d1a2 dhilvert2006-08-30 07:40:00 +0000694 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
4949c031 dhilvert2005-01-07 06:44:00 +0000695 continue;
696
697 /*
698 * Transform
699 */
700
701 struct point q;
702
07271611 dhilvert2005-01-07 06:48:00 +0000703 q = (c.input_scale < 1.0 && interpolant == NULL)
704 ? t.scaled_inverse_transform(
705 point(i + offset[0], j + offset[1]))
706 : t.unscaled_inverse_transform(
4949c031 dhilvert2005-01-07 06:44:00 +0000707 point(i + offset[0], j + offset[1]));
708
709 ale_pos ti = q[0];
710 ale_pos tj = q[1];
711
712 /*
713 * Check that the transformed coordinates are within
714 * the boundaries of array c.input, and check that the
715 * weight value in the accumulated array is nonzero,
716 * unless we know it is nonzero by virtue of the fact
717 * that it falls within the region of the original
718 * frame (e.g. when we're not increasing image
df55d1a2 dhilvert2006-08-30 07:40:00 +0000719 * extents). Also check for frame exclusion.
4949c031 dhilvert2005-01-07 06:44:00 +0000720 */
721
df55d1a2 dhilvert2006-08-30 07:40:00 +0000722 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
723 continue;
724
4949c031 dhilvert2005-01-07 06:44:00 +0000725 if (ti >= 0
726 && ti <= c.input->height() - 1
727 && tj >= 0
728 && tj <= c.input->width() - 1
580b5321 David Hilvert2007-09-10 17:35:00 +0000729 && c.certainty->get_pixel(i, j)[0] != 0)
4949c031 dhilvert2005-01-07 06:44:00 +0000730 result++;
731 }
732
733 return result;
734 }
735
736 /*
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000737 * Monte carlo iteration class.
738 *
739 * Monte Carlo alignment has been used for statistical comparisons in
740 * spatial registration, and is now used for tonal registration
741 * and final match calculation.
742 */
743
744 /*
745 * We use a random process for which the expected number of sampled
746 * pixels is +/- .000003 from the coverage in the range [.005,.995] for
747 * an image with 100,000 pixels. (The actual number may still deviate
748 * from the expected number by more than this amount, however.) The
749 * method is as follows:
750 *
751 * We have coverage == USE/ALL, or (expected # pixels to use)/(# total
752 * pixels). We derive from this SKIP/USE.
753 *
754 * SKIP/USE == (SKIP/ALL)/(USE/ALL) == (1 - (USE/ALL))/(USE/ALL)
755 *
756 * Once we have SKIP/USE, we know the expected number of pixels to skip
757 * in each iteration. We use a random selection process that provides
758 * SKIP/USE close to this calculated value.
759 *
760 * If we can draw uniformly to select the number of pixels to skip, we
761 * do. In this case, the maximum number of pixels to skip is twice the
762 * expected number.
763 *
764 * If we cannot draw uniformly, we still assign equal probability to
765 * each of the integer values in the interval [0, 2 * (SKIP/USE)], but
766 * assign an unequal amount to the integer value ceil(2 * SKIP/USE) +
767 * 1.
768 */
769
770 /*
771 * When reseeding the random number generator, we want the same set of
772 * pixels to be used in cases where two alignment options are compared.
773 * If we wanted to avoid bias from repeatedly utilizing the same seed,
774 * we could seed with the number of the frame most recently aligned:
775 *
776 * srand(latest);
777 *
778 * However, in cursory tests, it seems okay to just use the default
779 * seed of 1, and so we do this, since it is simpler; both of these
780 * approaches to reseeding achieve better results than not reseeding.
781 * (1 is the default seed according to the GNU Manual Page for
782 * rand(3).)
783 *
784 * For subdomain calculations, we vary the seed by adding the subdomain
785 * index.
786 */
787
788 class mc_iterate {
789 ale_pos mc_max;
790 unsigned int index;
791 unsigned int index_max;
792 int i_min;
793 int i_max;
794 int j_min;
795 int j_max;
796
797 rng_t rng;
798
63f46ff7 David Hilvert2007-09-21 00:03:00 +0000799 public:
f0af1fea
DH
David Hilvert2007-09-20 23:22:00 +0000800 mc_iterate(int _i_min, int _i_max, int _j_min, int _j_max, unsigned int subdomain)
801 : rng() {
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000802
803 ale_pos coverage;
804
805 i_min = _i_min;
806 i_max = _i_max;
807 j_min = _j_min;
808 j_max = _j_max;
809
a0c28c9a
DH
David Hilvert2008-03-23 15:55:54 -0500810 if (i_max < i_min || j_max < j_min)
811 index_max = 0;
812 else
813 index_max = (i_max - i_min) * (j_max - j_min);
699711e2 David Hilvert2007-09-20 21:03:00 +0000814
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000815 if (index_max < 500 || _mc > 100 || _mc <= 0)
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000816 coverage = 1;
817 else
bddc9e4d David Hilvert2007-10-01 19:50:00 +0000818 coverage = _mc / 100;
699711e2 David Hilvert2007-09-20 21:03:00 +0000819
a85f57f9 David Hilvert2007-10-15 17:07:00 +0000820 double su = (1 - coverage) / coverage;
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000821
822 mc_max = (floor(2*su) * (1 + floor(2*su)) + 2*su)
823 / (2 + 2 * floor(2*su) - 2*su);
824
825 rng.seed(1 + subdomain);
826
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000827#define FIXED16 3
828#if ALE_COORDINATES == FIXED16
829 /*
830 * XXX: This calculation might not yield the correct
831 * expected value.
832 */
e4a3555e
DH
David Hilvert2007-10-24 22:37:00 +0000833 index = -1 + (int) ceil(((ale_pos) mc_max+1)
834 / (ale_pos) ( (1 + 0xffffff)
835 / (1 + (rng.get() & 0xffffff))));
793fc1a6 David Hilvert2007-10-25 16:36:00 +0000836#else
ff364936 David Hilvert2007-10-26 23:35:00 +0000837 index = -1 + (int) ceil((ale_accum) (mc_max+1)
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000838 * ( (1 + ((ale_accum) (rng.get())) )
839 / (1 + ((ale_accum) RAND_MAX)) ));
840#endif
841#undef FIXED16
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000842 }
843
844 int get_i() {
845 return index / (j_max - j_min) + i_min;
846 }
847
848 int get_j() {
849 return index % (j_max - j_min) + j_min;
850 }
851
63f46ff7 David Hilvert2007-09-21 00:03:00 +0000852 void operator++(int whats_this_for) {
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000853#define FIXED16 3
854#if ALE_COORDINATES == FIXED16
e4a3555e
DH
David Hilvert2007-10-24 22:37:00 +0000855 index += (int) ceil(((ale_pos) mc_max+1)
856 / (ale_pos) ( (1 + 0xffffff)
857 / (1 + (rng.get() & 0xffffff))));
793fc1a6 David Hilvert2007-10-25 16:36:00 +0000858#else
ff364936 David Hilvert2007-10-26 23:35:00 +0000859 index += (int) ceil((ale_accum) (mc_max+1)
793fc1a6
DH
David Hilvert2007-10-25 16:36:00 +0000860 * ( (1 + ((ale_accum) (rng.get())) )
861 / (1 + ((ale_accum) RAND_MAX)) ));
862#endif
863#undef FIXED16
699711e2
DH
David Hilvert2007-09-20 21:03:00 +0000864 }
865
866 int done() {
867 return (index >= index_max);
868 }
869 };
870
871 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +0000872 * Not-quite-symmetric difference function. Determines the difference in areas
4949c031 dhilvert2005-01-07 06:44:00 +0000873 * where the arrays overlap. Uses the reference array's notion of pixel positions.
30afe4b6 dhilvert2005-01-07 06:42:00 +0000874 *
875 * For the purposes of determining the difference, this function divides each
876 * pixel value by the corresponding image's average pixel magnitude, unless we
877 * are:
878 *
879 * a) Extending the boundaries of the image, or
880 *
881 * b) following the previous frame's transform
882 *
883 * If we are doing monte-carlo pixel sampling for alignment, we
884 * typically sample a subset of available pixels; otherwise, we sample
885 * all pixels.
886 *
887 */
4707675e dhilvert2006-10-19 10:24:00 +0000888
f8864302
DH
David Hilvert2008-04-11 18:15:57 +0000889 template<class diff_trans>
890 class diff_stat_generic {
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000891
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000892 transformation::elem_bounds_t elem_bounds;
e492922d David Hilvert2007-05-09 05:53:00 +0000893
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000894 struct run {
895
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000896 diff_trans offset;
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000897
898 ale_accum result;
899 ale_accum divisor;
900
901 point max, min;
902 ale_accum centroid[2], centroid_divisor;
903 ale_accum de_centroid[2], de_centroid_v, de_sum;
904
5d53e401 David Hilvert2007-05-02 03:12:00 +0000905 void init() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000906
907 result = 0;
908 divisor = 0;
e492922d David Hilvert2007-05-09 05:53:00 +0000909
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000910 min = point::posinf();
911 max = point::neginf();
912
913 centroid[0] = 0;
914 centroid[1] = 0;
915 centroid_divisor = 0;
916
917 de_centroid[0] = 0;
918 de_centroid[1] = 0;
919
920 de_centroid_v = 0;
921
922 de_sum = 0;
923 }
924
1b980378 David Hilvert2008-07-18 18:30:40 +0000925 void init(diff_trans _offset) {
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +0000926 offset = _offset;
927 init();
928 }
929
930 /*
931 * Required for STL sanity.
932 */
dd7602d7 David Hilvert2008-03-06 18:41:00 +0000933 run() : offset(diff_trans::eu_identity()) {
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +0000934 init();
935 }
936
1b980378
DH
David Hilvert2008-07-18 18:30:40 +0000937 run(diff_trans _offset) : offset(_offset) {
938 init(_offset);
e492922d
DH
David Hilvert2007-05-09 05:53:00 +0000939 }
940
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000941 void add(const run &_run) {
942 result += _run.result;
943 divisor += _run.divisor;
944
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000945 for (int d = 0; d < 2; d++) {
946 if (min[d] > _run.min[d])
947 min[d] = _run.min[d];
948 if (max[d] < _run.max[d])
949 max[d] = _run.max[d];
950 centroid[d] += _run.centroid[d];
951 de_centroid[d] += _run.de_centroid[d];
952 }
953
954 centroid_divisor += _run.centroid_divisor;
955 de_centroid_v += _run.de_centroid_v;
956 de_sum += _run.de_sum;
957 }
958
283c3ecc David Hilvert2008-01-26 01:36:00 +0000959 run(const run &_run) : offset(_run.offset) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000960
961 /*
962 * Initialize
963 */
1b980378 David Hilvert2008-07-18 18:30:40 +0000964 init(_run.offset);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000965
966 /*
967 * Add
968 */
969 add(_run);
970 }
971
972 run &operator=(const run &_run) {
973
974 /*
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000975 * Initialize
976 */
1b980378 David Hilvert2008-07-18 18:30:40 +0000977 init(_run.offset);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000978
979 /*
980 * Add
981 */
982 add(_run);
983
984 return *this;
985 }
986
987 ~run() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000988 }
989
990 ale_accum get_error() const {
c9968081 David Hilvert2007-10-24 02:54:00 +0000991 return pow(result / divisor, 1/(ale_accum) metric_exponent);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000992 }
993
368d214e
DH
David Hilvert2007-05-09 07:57:00 +0000994 void sample(int f, scale_cluster c, int i, int j, point t, point u,
995 const run &comparison) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +0000996
997 pixel pa = c.accum->get_pixel(i, j);
998
42772195
DH
David Hilvert2007-10-21 15:36:00 +0000999 ale_real this_result[2] = { 0, 0 };
1000 ale_real this_divisor[2] = { 0, 0 };
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001001
f064b1a9
DH
David Hilvert2007-09-21 21:21:00 +00001002 pixel p[2];
1003 pixel weight[2];
1004 weight[0] = pixel(1, 1, 1);
1005 weight[1] = pixel(1, 1, 1);
1006
ca7acd56 David Hilvert2008-06-05 23:43:51 +00001007 pixel tm = offset.get_tonal_multiplier(point(i, j) + c.accum->offset());
28e6b6f7 David Hilvert2008-06-05 02:36:34 +00001008
1e559234 David Hilvert2007-09-11 19:34:00 +00001009 if (interpolant != NULL) {
4132897c
DH
David Hilvert2007-10-26 18:13:00 +00001010 interpolant->filtered(i, j, &p[0], &weight[0], 1, f);
1011
fa3844c7 David Hilvert2007-10-26 18:39:00 +00001012 if (weight[0].min_norm() > ale_real_weight_floor) {
4132897c
DH
David Hilvert2007-10-26 18:13:00 +00001013 p[0] /= weight[0];
1014 } else {
1015 return;
1016 }
1017
1e559234 David Hilvert2007-09-11 19:34:00 +00001018 } else {
e7f30dec David Hilvert2007-09-21 19:25:00 +00001019 p[0] = c.input->get_bl(t);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001020 }
1021
28e6b6f7 David Hilvert2008-06-05 02:36:34 +00001022 p[0] *= tm;
64e05da1 David Hilvert2008-05-05 16:21:18 -05001023
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001024 if (u.defined()) {
19b07c65 David Hilvert2007-09-11 18:07:00 +00001025 p[1] = c.input->get_bl(u);
28e6b6f7 David Hilvert2008-06-05 02:36:34 +00001026 p[1] *= tm;
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001027 }
1028
1029
1030 /*
1031 * Handle certainty.
1032 */
1033
f064b1a9 David Hilvert2007-09-21 21:21:00 +00001034 if (certainty_weights == 1) {
32ec9768
DH
David Hilvert2007-09-21 23:14:00 +00001035
1036 /*
1037 * For speed, use arithmetic interpolation (get_bl(.))
1038 * instead of geometric (get_bl(., 1))
1039 */
1040
1041 weight[0] *= c.input_certainty->get_bl(t);
c4fb894c David Hilvert2007-09-21 22:44:00 +00001042 if (u.defined())
32ec9768 David Hilvert2007-09-21 23:14:00 +00001043 weight[1] *= c.input_certainty->get_bl(u);
e7f30dec
DH
David Hilvert2007-09-21 19:25:00 +00001044 weight[0] *= c.certainty->get_pixel(i, j);
1045 weight[1] *= c.certainty->get_pixel(i, j);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001046 }
1047
1048 if (c.aweight != NULL) {
1049 weight[0] *= c.aweight->get_pixel(i, j);
1050 weight[1] *= c.aweight->get_pixel(i, j);
1051 }
1052
1053 /*
1054 * Update sampling area statistics
1055 */
1056
1057 if (min[0] > i)
1058 min[0] = i;
1059 if (min[1] > j)
1060 min[1] = j;
1061 if (max[0] < i)
1062 max[0] = i;
1063 if (max[1] < j)
1064 max[1] = j;
1065
1066 centroid[0] += (weight[0][0] + weight[0][1] + weight[0][2]) * i;
1067 centroid[1] += (weight[0][0] + weight[0][1] + weight[0][2]) * j;
1068 centroid_divisor += (weight[0][0] + weight[0][1] + weight[0][2]);
1069
1070 /*
1071 * Determine alignment type.
1072 */
1073
1074 for (int m = 0; m < (u.defined() ? 2 : 1); m++)
1075 if (channel_alignment_type == 0) {
1076 /*
1077 * Align based on all channels.
1078 */
1079
1080
1081 for (int k = 0; k < 3; k++) {
1082 ale_real achan = pa[k];
1083 ale_real bchan = p[m][k];
1084
1085 this_result[m] += weight[m][k] * pow(fabs(achan - bchan), metric_exponent);
1086 this_divisor[m] += weight[m][k] * pow(achan > bchan ? achan : bchan, metric_exponent);
1087 }
1088 } else if (channel_alignment_type == 1) {
1089 /*
1090 * Align based on the green channel.
1091 */
1092
1093 ale_real achan = pa[1];
1094 ale_real bchan = p[m][1];
1095
1096 this_result[m] = weight[m][1] * pow(fabs(achan - bchan), metric_exponent);
1097 this_divisor[m] = weight[m][1] * pow(achan > bchan ? achan : bchan, metric_exponent);
1098 } else if (channel_alignment_type == 2) {
1099 /*
1100 * Align based on the sum of all channels.
1101 */
1102
1103 ale_real asum = 0;
1104 ale_real bsum = 0;
1105 ale_real wsum = 0;
1106
1107 for (int k = 0; k < 3; k++) {
1108 asum += pa[k];
1109 bsum += p[m][k];
1110 wsum += weight[m][k] / 3;
1111 }
1112
1113 this_result[m] = wsum * pow(fabs(asum - bsum), metric_exponent);
1114 this_divisor[m] = wsum * pow(asum > bsum ? asum : bsum, metric_exponent);
1115 }
1116
1117 if (u.defined()) {
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001118// ale_real de = fabs(this_result[0] / this_divisor[0]
1119// - this_result[1] / this_divisor[1]);
1120 ale_real de = fabs(this_result[0] - this_result[1]);
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001121
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001122 de_centroid[0] += de * (ale_real) i;
1123 de_centroid[1] += de * (ale_real) j;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001124
42772195 David Hilvert2007-10-21 15:36:00 +00001125 de_centroid_v += de * (ale_real) t.lengthto(u);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001126
1127 de_sum += de;
1128 }
1129
1130 result += (this_result[0]);
1131 divisor += (this_divisor[0]);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001132 }
1133
1134 void rescale(ale_pos scale) {
1135 offset.rescale(scale);
1136
1137 de_centroid[0] *= scale;
1138 de_centroid[1] *= scale;
1139 de_centroid_v *= scale;
1140 }
1141
1142 point get_centroid() {
1143 point result = point(centroid[0] / centroid_divisor, centroid[1] / centroid_divisor);
1144
1145 assert (finite(centroid[0])
1146 && finite(centroid[1])
1147 && (result.defined() || centroid_divisor == 0));
1148
1149 return result;
1150 }
1151
1152 point get_error_centroid() {
1153 point result = point(de_centroid[0] / de_sum, de_centroid[1] / de_sum);
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001154 return result;
1155 }
1156
1157
1158 ale_pos get_error_perturb() {
1159 ale_pos result = de_centroid_v / de_sum;
1160
1161 return result;
1162 }
1163
1164 };
1165
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001166 /*
1167 * When non-empty, runs.front() is best, runs.back() is
1168 * testing.
1169 */
1170
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001171 std::vector<run> runs;
1172
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001173 /*
1174 * old_runs stores the latest available perturbation set for
1175 * each multi-alignment element.
1176 */
1177
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001178 typedef int run_index;
30ea890d David Hilvert2007-05-14 20:54:00 +00001179 std::map<run_index, run> old_runs;
5d53e401 David Hilvert2007-05-02 03:12:00 +00001180
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001181 static void *diff_subdomain(void *args);
1182
1183 struct subdomain_args {
1184 struct scale_cluster c;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001185 std::vector<run> runs;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001186 int ax_count;
1187 int f;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001188 int i_min, i_max, j_min, j_max;
1189 int subdomain;
1190 };
1191
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001192 struct scale_cluster si;
1193 int ax_count;
1194 int frame;
1195
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001196 std::vector<ale_pos> perturb_multipliers;
1197
30ea890d David Hilvert2007-05-14 20:54:00 +00001198public:
1b980378 David Hilvert2008-07-18 18:30:40 +00001199 void diff(struct scale_cluster c, const diff_trans &t,
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001200 int _ax_count, int f) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001201
1202 if (runs.size() == 2)
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001203 runs.pop_back();
1204
1b980378 David Hilvert2008-07-18 18:30:40 +00001205 runs.push_back(run(t));
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001206
1207 si = c;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001208 ax_count = _ax_count;
1209 frame = f;
1210
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001211 ui::get()->d2_align_sample_start();
1212
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001213 if (interpolant != NULL) {
1214
1215 /*
1216 * XXX: This has not been tested, and may be completely
1217 * wrong.
1218 */
1219
1220 transformation tt = transformation::eu_identity();
1221 tt.set_current_element(t);
1222 interpolant->set_parameters(tt, c.input, c.accum->offset());
1223 }
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001224
1225 int N;
1226#ifdef USE_PTHREAD
1227 N = thread::count();
1228
1229 pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t) * N);
1230 pthread_attr_t *thread_attr = (pthread_attr_t *) malloc(sizeof(pthread_attr_t) * N);
1231
1232#else
1233 N = 1;
1234#endif
1235
1236 subdomain_args *args = new subdomain_args[N];
1237
d790f7da David Hilvert2008-05-02 18:59:43 -05001238 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 +00001239
a7ee2759
DH
David Hilvert2008-03-17 17:05:06 -05001240// fprintf(stdout, "[%d %d] [%d %d]\n",
1241// global_i_min, global_i_max, global_j_min, global_j_max);
e55e5de1 David Hilvert2008-02-14 01:08:00 +00001242
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001243 for (int ti = 0; ti < N; ti++) {
1244 args[ti].c = c;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001245 args[ti].runs = runs;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001246 args[ti].ax_count = ax_count;
1247 args[ti].f = f;
d790f7da
DH
David Hilvert2008-05-02 18:59:43 -05001248 args[ti].i_min = b.imin + ((b.imax - b.imin) * ti) / N;
1249 args[ti].i_max = b.imin + ((b.imax - b.imin) * (ti + 1)) / N;
1250 args[ti].j_min = b.jmin;
1251 args[ti].j_max = b.jmax;
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001252 args[ti].subdomain = ti;
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001253#ifdef USE_PTHREAD
1254 pthread_attr_init(&thread_attr[ti]);
1255 pthread_attr_setdetachstate(&thread_attr[ti], PTHREAD_CREATE_JOINABLE);
1256 pthread_create(&threads[ti], &thread_attr[ti], diff_subdomain, &args[ti]);
1257#else
1258 diff_subdomain(&args[ti]);
1259#endif
1260 }
1261
1262 for (int ti = 0; ti < N; ti++) {
1263#ifdef USE_PTHREAD
1264 pthread_join(threads[ti], NULL);
1265#endif
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001266 runs.back().add(args[ti].runs.back());
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001267 }
1268
44a1d1de
DH
David Hilvert2009-03-30 19:02:57 +00001269#ifdef USE_PTHREAD
1270 free(threads);
1271 free(thread_attr);
1272#endif
1273
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001274 delete[] args;
1275
1276 ui::get()->d2_align_sample_stop();
1277
1278 }
1279
1280 private:
1281 void rediff() {
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001282 std::vector<diff_trans> t_array;
b971d971 David Hilvert2006-12-26 05:25:00 +00001283
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001284 for (unsigned int r = 0; r < runs.size(); r++) {
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001285 t_array.push_back(runs[r].offset);
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001286 }
b971d971 David Hilvert2006-12-26 05:25:00 +00001287
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001288 runs.clear();
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001289
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001290 for (unsigned int r = 0; r < t_array.size(); r++)
1b980378 David Hilvert2008-07-18 18:30:40 +00001291 diff(si, t_array[r], ax_count, frame);
86c0d2ba dhilvert2006-10-25 14:42:00 +00001292 }
1293
400c7826 David Hilvert2007-04-20 07:06:00 +00001294
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001295 public:
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001296 int better() {
1297 assert(runs.size() >= 2);
1298 assert(runs[0].offset.scale() == runs[1].offset.scale());
86c0d2ba dhilvert2006-10-25 14:42:00 +00001299
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001300 return (runs[1].get_error() < runs[0].get_error()
1301 || (!finite(runs[0].get_error()) && finite(runs[1].get_error())));
08151f52 dhilvert2006-10-25 17:36:00 +00001302 }
1303
e0577945
DH
David Hilvert2008-07-19 22:11:55 +00001304 int better_defined() {
1305 assert(runs.size() >= 2);
1306 assert(runs[0].offset.scale() == runs[1].offset.scale());
1307
1308 return (runs[1].get_error() < runs[0].get_error());
1309 }
1310
f8864302 David Hilvert2008-04-11 18:15:57 +00001311 diff_stat_generic(transformation::elem_bounds_t e)
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00001312 : runs(), old_runs(), perturb_multipliers() {
1313 elem_bounds = e;
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001314 }
1315
1316 run_index get_run_index(unsigned int perturb_index) {
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001317 return perturb_index;
30ea890d David Hilvert2007-05-14 20:54:00 +00001318 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001319
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001320 run &get_run(unsigned int perturb_index) {
1321 run_index index = get_run_index(perturb_index);
dc426169 David Hilvert2007-04-25 06:50:00 +00001322
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001323 assert(old_runs.count(index));
1324 return old_runs[index];
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001325 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001326
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001327 void rescale(ale_pos scale, scale_cluster _si) {
1328 assert(runs.size() == 1);
86c0d2ba dhilvert2006-10-25 14:42:00 +00001329
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001330 si = _si;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001331
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001332 runs[0].rescale(scale);
1333
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001334 rediff();
1335 }
1336
f8864302 David Hilvert2008-04-11 18:15:57 +00001337 ~diff_stat_generic() {
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001338 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001339
f8864302 David Hilvert2008-04-11 18:15:57 +00001340 diff_stat_generic &operator=(const diff_stat_generic &dst) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001341 /*
1342 * Copy run information.
1343 */
1344 runs = dst.runs;
82db7fe6 David Hilvert2007-05-05 18:29:00 +00001345 old_runs = dst.old_runs;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001346
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001347 /*
1348 * Copy diff variables
1349 */
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001350 si = dst.si;
1351 ax_count = dst.ax_count;
1352 frame = dst.frame;
50a9f51d David Hilvert2007-05-03 05:16:00 +00001353 perturb_multipliers = dst.perturb_multipliers;
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001354 elem_bounds = dst.elem_bounds;
86c0d2ba dhilvert2006-10-25 14:42:00 +00001355
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001356 return *this;
1357 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001358
f8864302 David Hilvert2008-04-11 18:15:57 +00001359 diff_stat_generic(const diff_stat_generic &dst) : runs(), old_runs(),
ca7b6c30 David Hilvert2007-05-06 02:42:00 +00001360 perturb_multipliers() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001361 operator=(dst);
1362 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001363
1ed23c0d
DH
David Hilvert2008-03-09 11:23:00 +00001364 void set_elem_bounds(transformation::elem_bounds_t e) {
1365 elem_bounds = e;
1366 }
1367
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001368 ale_accum get_result() {
1369 assert(runs.size() == 1);
1370 return runs[0].result;
1371 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001372
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001373 ale_accum get_divisor() {
1374 assert(runs.size() == 1);
1375 return runs[0].divisor;
1376 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001377
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001378 diff_trans get_offset() {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001379 assert(runs.size() == 1);
1380 return runs[0].offset;
1381 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001382
f8864302 David Hilvert2008-04-11 18:15:57 +00001383 int operator!=(diff_stat_generic &param) {
65886ff7 David Hilvert2007-09-04 02:10:00 +00001384 return (get_error() != param.get_error());
86c0d2ba dhilvert2006-10-25 14:42:00 +00001385 }
08151f52 dhilvert2006-10-25 17:36:00 +00001386
f8864302 David Hilvert2008-04-11 18:15:57 +00001387 int operator==(diff_stat_generic &param) {
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001388 return !(operator!=(param));
1389 }
08151f52 dhilvert2006-10-25 17:36:00 +00001390
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001391 ale_pos get_error_perturb() {
1392 assert(runs.size() == 1);
1393 return runs[0].get_error_perturb();
08151f52 dhilvert2006-10-25 17:36:00 +00001394 }
86c0d2ba dhilvert2006-10-25 14:42:00 +00001395
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001396 ale_accum get_error() const {
1397 assert(runs.size() == 1);
1398 return runs[0].get_error();
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001399 }
dda1bf79 dhilvert2006-10-22 18:40:00 +00001400
30ea890d David Hilvert2007-05-14 20:54:00 +00001401 public:
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001402 /*
1403 * Get the set of transformations produced by a given perturbation
1404 */
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001405 void get_perturb_set(std::vector<diff_trans> *set,
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001406 ale_pos adj_p, ale_pos adj_o, ale_pos adj_b,
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001407 ale_pos *current_bd, ale_pos *modified_bd,
1408 std::vector<ale_pos> multipliers = std::vector<ale_pos>()) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001409
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001410 assert(runs.size() == 1);
dda1bf79 dhilvert2006-10-22 18:40:00 +00001411
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001412 diff_trans test_t(diff_trans::eu_identity());
dda1bf79 dhilvert2006-10-22 18:40:00 +00001413
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001414 /*
1415 * Translational or euclidean transformation
1416 */
2aa417e6 dhilvert2005-01-07 06:44:00 +00001417
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001418 for (unsigned int i = 0; i < 2; i++)
1419 for (unsigned int s = 0; s < 2; s++) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001420
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001421 if (!multipliers.size())
1422 multipliers.push_back(1);
dc426169 David Hilvert2007-04-25 06:50:00 +00001423
b2e7131e David Hilvert2007-05-02 08:35:00 +00001424 assert(finite(multipliers[0]));
5d53e401 David Hilvert2007-05-02 03:12:00 +00001425
b2e7131e David Hilvert2007-05-02 08:35:00 +00001426 test_t = get_offset();
dc426169 David Hilvert2007-04-25 06:50:00 +00001427
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001428 // test_t.eu_modify(i, (s ? -adj_p : adj_p) * multipliers[0]);
1429 test_t.translate((i ? point(1, 0) : point(0, 1))
1430 * (s ? -adj_p : adj_p)
1431 * multipliers[0]);
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001432
1433 test_t.snap(adj_p / 2);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001434
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001435 set->push_back(test_t);
1436 multipliers.erase(multipliers.begin());
46f9776a dhilvert2005-01-07 06:44:00 +00001437
b2e7131e David Hilvert2007-05-02 08:35:00 +00001438 }
4707675e dhilvert2006-10-19 10:24:00 +00001439
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001440 if (alignment_class > 0)
1441 for (unsigned int s = 0; s < 2; s++) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001442
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001443 if (!multipliers.size())
1444 multipliers.push_back(1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001445
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001446 assert(multipliers.size());
1447 assert(finite(multipliers[0]));
5d53e401 David Hilvert2007-05-02 03:12:00 +00001448
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001449 if (!(adj_o * multipliers[0] < rot_max))
1450 return;
4707675e dhilvert2006-10-19 10:24:00 +00001451
b2e7131e David Hilvert2007-05-02 08:35:00 +00001452 ale_pos adj_s = (s ? 1 : -1) * adj_o * multipliers[0];
5d53e401 David Hilvert2007-05-02 03:12:00 +00001453
b2e7131e David Hilvert2007-05-02 08:35:00 +00001454 test_t = get_offset();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001455
30ea890d David Hilvert2007-05-14 20:54:00 +00001456 run_index ori = get_run_index(set->size());
b2e7131e David Hilvert2007-05-02 08:35:00 +00001457 point centroid = point::undefined();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001458
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001459 if (!old_runs.count(ori))
1460 ori = get_run_index(0);
5d53e401 David Hilvert2007-05-02 03:12:00 +00001461
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001462 if (!centroid.finite() && old_runs.count(ori)) {
1463 centroid = old_runs[ori].get_error_centroid();
5d53e401 David Hilvert2007-05-02 03:12:00 +00001464
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001465 if (!centroid.finite())
1466 centroid = old_runs[ori].get_centroid();
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001467
1468 centroid *= test_t.scale()
1469 / old_runs[ori].offset.scale();
b2e7131e David Hilvert2007-05-02 08:35:00 +00001470 }
5d53e401 David Hilvert2007-05-02 03:12:00 +00001471
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001472 if (!centroid.finite() && !test_t.is_projective()) {
1473 test_t.eu_modify(2, adj_s);
1474 } else if (!centroid.finite()) {
1475 centroid = point(si.input->height() / 2,
1476 si.input->width() / 2);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001477
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001478 test_t.rotate(centroid + si.accum->offset(),
1479 adj_s);
1480 } else {
1481 test_t.rotate(centroid + si.accum->offset(),
1482 adj_s);
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001483 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001484
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001485 test_t.snap(adj_p / 2);
1486
b2e7131e
DH
David Hilvert2007-05-02 08:35:00 +00001487 set->push_back(test_t);
1488 multipliers.erase(multipliers.begin());
1489 }
1490
1491 if (alignment_class == 2) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001492
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001493 /*
1494 * Projective transformation
1495 */
30afe4b6 dhilvert2005-01-07 06:42:00 +00001496
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001497 for (unsigned int i = 0; i < 4; i++)
1498 for (unsigned int j = 0; j < 2; j++)
1499 for (unsigned int s = 0; s < 2; s++) {
1500
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001501 if (!multipliers.size())
1502 multipliers.push_back(1);
1503
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001504 assert(multipliers.size());
1505 assert(finite(multipliers[0]));
46f9776a dhilvert2005-01-07 06:44:00 +00001506
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001507 ale_pos adj_s = (s ? -1 : 1) * adj_p * multipliers [0];
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001508
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001509 test_t = get_offset();
46f9776a dhilvert2005-01-07 06:44:00 +00001510
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001511 if (perturb_type == 0)
73f0dc5c David Hilvert2008-08-18 17:37:54 -05001512 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 +00001513 else if (perturb_type == 1)
1514 test_t.gr_modify(j, i, adj_s);
1515 else
1516 assert(0);
dc426169 David Hilvert2007-04-25 06:50:00 +00001517
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001518 test_t.snap(adj_p / 2);
1519
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001520 set->push_back(test_t);
1521 multipliers.erase(multipliers.begin());
1522 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001523
b2e7131e David Hilvert2007-05-02 08:35:00 +00001524 }
dc426169 David Hilvert2007-04-25 06:50:00 +00001525
49a3a0b4 David Hilvert2007-04-01 07:13:00 +00001526 /*
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001527 * Barrel distortion
49a3a0b4
DH
David Hilvert2007-04-01 07:13:00 +00001528 */
1529
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001530 if (bda_mult != 0 && adj_b != 0) {
7a696eb1 David Hilvert2007-04-01 06:41:00 +00001531
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001532 for (unsigned int d = 0; d < get_offset().bd_count(); d++)
1533 for (unsigned int s = 0; s < 2; s++) {
1534
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001535 if (!multipliers.size())
1536 multipliers.push_back(1);
1537
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001538 assert (multipliers.size());
1539 assert (finite(multipliers[0]));
1540
1541 ale_pos adj_s = (s ? -1 : 1) * adj_b * multipliers[0];
1542
1543 if (bda_rate > 0 && fabs(modified_bd[d] + adj_s - current_bd[d]) > bda_rate)
1544 continue;
1545
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001546 diff_trans test_t = get_offset();
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001547
1548 test_t.bd_modify(d, adj_s);
1549
1550 set->push_back(test_t);
1551 }
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001552 }
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001553 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001554
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001555 void confirm() {
1556 assert(runs.size() == 2);
1557 runs[0] = runs[1];
1558 runs.pop_back();
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00001559 }
1560
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001561 void discard() {
1562 assert(runs.size() == 2);
1563 runs.pop_back();
1564 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001565
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001566 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 +00001567 ale_pos *current_bd, ale_pos *modified_bd, int stable) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001568
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001569 assert(runs.size() == 1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001570
dd7602d7 David Hilvert2008-03-06 18:41:00 +00001571 std::vector<diff_trans> t_set;
4707675e dhilvert2006-10-19 10:24:00 +00001572
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001573 if (perturb_multipliers.size() == 0) {
1574 get_perturb_set(&t_set, adj_p, adj_o, adj_b,
1575 current_bd, modified_bd);
1576
1577 for (unsigned int i = 0; i < t_set.size(); i++) {
f8864302 David Hilvert2008-04-11 18:15:57 +00001578 diff_stat_generic test = *this;
50a9f51d David Hilvert2007-05-03 05:16:00 +00001579
1b980378 David Hilvert2008-07-18 18:30:40 +00001580 test.diff(si, t_set[i], ax_count, frame);
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001581
1582 test.confirm();
1583
42772195 David Hilvert2007-10-21 15:36:00 +00001584 if (finite(test.get_error_perturb()))
82db7fe6
DH
David Hilvert2007-05-05 18:29:00 +00001585 perturb_multipliers.push_back(adj_p / test.get_error_perturb());
1586 else
1587 perturb_multipliers.push_back(1);
1588
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001589 }
1590
1591 t_set.clear();
1592 }
1593
5d53e401 David Hilvert2007-05-02 03:12:00 +00001594 get_perturb_set(&t_set, adj_p, adj_o, adj_b, current_bd, modified_bd,
50a9f51d David Hilvert2007-05-03 05:16:00 +00001595 perturb_multipliers);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001596
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001597 int found_unreliable = 1;
1598 std::vector<int> tested(t_set.size(), 0);
dc426169 David Hilvert2007-04-25 06:50:00 +00001599
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001600 for (unsigned int i = 0; i < t_set.size(); i++) {
1601 run_index ori = get_run_index(i);
1602
1603 /*
1604 * Check for stability
1605 */
1606 if (stable
1607 && old_runs.count(ori)
1608 && old_runs[ori].offset == t_set[i])
1609 tested[i] = 1;
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001610 }
1611
1612 std::vector<ale_pos> perturb_multipliers_original = perturb_multipliers;
1613
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001614 while (found_unreliable) {
dc426169 David Hilvert2007-04-25 06:50:00 +00001615
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001616 found_unreliable = 0;
08151f52 dhilvert2006-10-25 17:36:00 +00001617
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001618 for (unsigned int i = 0; i < t_set.size(); i++) {
4d806213 dhilvert2006-10-23 17:58:00 +00001619
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001620 if (tested[i])
1621 continue;
b410ef51 dhilvert2006-10-23 15:30:00 +00001622
1b980378 David Hilvert2008-07-18 18:30:40 +00001623 diff(si, t_set[i], ax_count, frame);
7e87bd8e dhilvert2006-10-23 06:39:00 +00001624
50a9f51d
DH
David Hilvert2007-05-03 05:16:00 +00001625 if (!(i < perturb_multipliers.size())
1626 || !finite(perturb_multipliers[i])) {
5d53e401 David Hilvert2007-05-02 03:12:00 +00001627
50a9f51d David Hilvert2007-05-03 05:16:00 +00001628 perturb_multipliers.resize(i + 1);
5d53e401 David Hilvert2007-05-02 03:12:00 +00001629
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001630 if (finite(perturb_multipliers[i])
1631 && finite(adj_p)
1632 && finite(adj_p / runs[1].get_error_perturb())) {
1633 perturb_multipliers[i] =
1634 adj_p / runs[1].get_error_perturb();
5d53e401 David Hilvert2007-05-02 03:12:00 +00001635
8c886617 David Hilvert2007-05-02 08:39:00 +00001636 found_unreliable = 1;
42772195 David Hilvert2007-10-21 15:36:00 +00001637 } else
858b0722 David Hilvert2007-10-03 20:44:00 +00001638 perturb_multipliers[i] = 1;
5d53e401
DH
David Hilvert2007-05-02 03:12:00 +00001639
1640 continue;
1641 }
1642
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001643 run_index ori = get_run_index(i);
1644
1645 if (old_runs.count(ori) == 0)
1646 old_runs.insert(std::pair<run_index, run>(ori, runs[1]));
1647 else
1648 old_runs[ori] = runs[1];
5d53e401 David Hilvert2007-05-02 03:12:00 +00001649
42772195
DH
David Hilvert2007-10-21 15:36:00 +00001650 if (finite(perturb_multipliers_original[i])
1651 && finite(runs[1].get_error_perturb())
1652 && finite(adj_p)
1653 && finite(perturb_multipliers_original[i] * adj_p / runs[1].get_error_perturb()))
1654 perturb_multipliers[i] = perturb_multipliers_original[i]
1655 * adj_p / runs[1].get_error_perturb();
1656 else
50a9f51d David Hilvert2007-05-03 05:16:00 +00001657 perturb_multipliers[i] = 1;
5d53e401 David Hilvert2007-05-02 03:12:00 +00001658
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001659 tested[i] = 1;
dda1bf79 dhilvert2006-10-22 18:40:00 +00001660
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001661 if (better()
30ea890d
DH
David Hilvert2007-05-14 20:54:00 +00001662 && runs[1].get_error() < runs[0].get_error()
1663 && perturb_multipliers[i]
1664 / perturb_multipliers_original[i] < 2) {
9e8e62c9
DH
David Hilvert2007-05-13 10:57:00 +00001665 runs[0] = runs[1];
1666 runs.pop_back();
1667 return;
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00001668 }
82db7fe6 David Hilvert2007-05-05 18:29:00 +00001669
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001670 }
dda1bf79 dhilvert2006-10-22 18:40:00 +00001671
2077ce22
DH
David Hilvert2007-05-13 09:23:00 +00001672 if (runs.size() > 1)
1673 runs.pop_back();
3aa65890 dhilvert2006-10-25 15:26:00 +00001674
1732c1c4
DH
David Hilvert2007-04-30 02:42:00 +00001675 if (!found_unreliable)
1676 return;
1732c1c4 David Hilvert2007-04-30 02:42:00 +00001677 }
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001678 }
08151f52 dhilvert2006-10-25 17:36:00 +00001679
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00001680 };
4707675e dhilvert2006-10-19 10:24:00 +00001681
f8864302
DH
David Hilvert2008-04-11 18:15:57 +00001682 typedef diff_stat_generic<trans_single> diff_stat_t;
1683 typedef diff_stat_generic<trans_multi> diff_stat_multi;
1684
4707675e dhilvert2006-10-19 10:24:00 +00001685
30afe4b6 dhilvert2005-01-07 06:42:00 +00001686 /*
1687 * Adjust exposure for an aligned frame B against reference A.
07271611 dhilvert2005-01-07 06:48:00 +00001688 *
1689 * Expects full-LOD images.
1690 *
423af06c
DH
David Hilvert2007-09-10 17:43:00 +00001691 * Note: This method does not use any weighting, by certainty or
1692 * otherwise, in the first exposure registration pass, as any bias of
1693 * weighting according to color may also bias the exposure registration
1694 * result; it does use weighting, including weighting by certainty
1695 * (even if certainty weighting is not specified), in the second pass,
1696 * under the assumption that weighting by certainty improves handling
1697 * of out-of-range highlights, and that bias of exposure measurements
1698 * according to color may generally be less harmful after spatial
1699 * registration has been performed.
30afe4b6 dhilvert2005-01-07 06:42:00 +00001700 */
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001701 class exposure_ratio_iterate : public thread::decompose_domain {
1702 pixel_accum *asums;
1703 pixel_accum *bsums;
1704 pixel_accum *asum;
1705 pixel_accum *bsum;
1706 struct scale_cluster c;
214d014c David Hilvert2008-05-04 22:08:03 -05001707 const transformation &t;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001708 int ax_count;
1709 int pass_number;
1710 protected:
1711 void prepare_subdomains(unsigned int N) {
1712 asums = new pixel_accum[N];
1713 bsums = new pixel_accum[N];
1714 }
1715 void subdomain_algorithm(unsigned int thread,
1716 int i_min, int i_max, int j_min, int j_max) {
1717
1718 point offset = c.accum->offset();
1719
1720 for (mc_iterate m(i_min, i_max, j_min, j_max, thread); !m.done(); m++) {
1721
1722 unsigned int i = (unsigned int) m.get_i();
1723 unsigned int j = (unsigned int) m.get_j();
1724
1725 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
1726 continue;
1727
1728 /*
1729 * Transform
1730 */
1731
1732 struct point q;
1733
1734 q = (c.input_scale < 1.0 && interpolant == NULL)
1735 ? t.scaled_inverse_transform(
1736 point(i + offset[0], j + offset[1]))
1737 : t.unscaled_inverse_transform(
1738 point(i + offset[0], j + offset[1]));
1739
1740 /*
1741 * Check that the transformed coordinates are within
1742 * the boundaries of array c.input, that they are not
1743 * subject to exclusion, and that the weight value in
1744 * the accumulated array is nonzero.
1745 */
1746
1747 if (input_excluded(q[0], q[1], c.ax_parameters, ax_count))
1748 continue;
1749
1750 if (q[0] >= 0
1751 && q[0] <= c.input->height() - 1
1752 && q[1] >= 0
1753 && q[1] <= c.input->width() - 1
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00001754 && ((pixel) c.certainty->get_pixel(i, j)).minabs_norm() != 0) {
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001755 pixel a = c.accum->get_pixel(i, j);
1756 pixel b;
1757
1758 b = c.input->get_bl(q);
1759
1760 pixel weight = ((c.aweight && pass_number)
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00001761 ? (pixel) c.aweight->get_pixel(i, j)
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001762 : pixel(1, 1, 1))
1763 * (pass_number
5c603c78
DH
David Hilvert2007-10-29 04:51:00 +00001764 ? psqrt(c.certainty->get_pixel(i, j)
1765 * c.input_certainty->get_bl(q, 1))
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001766 : pixel(1, 1, 1));
1767
1768 asums[thread] += a * weight;
1769 bsums[thread] += b * weight;
1770 }
1771 }
1772 }
1773
1774 void finish_subdomains(unsigned int N) {
1775 for (unsigned int n = 0; n < N; n++) {
1776 *asum += asums[n];
1777 *bsum += bsums[n];
1778 }
34c6efce
DH
David Hilvert2007-10-23 01:35:00 +00001779 delete[] asums;
1780 delete[] bsums;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001781 }
1782 public:
1783 exposure_ratio_iterate(pixel_accum *_asum,
1784 pixel_accum *_bsum,
1785 struct scale_cluster _c,
214d014c David Hilvert2008-05-04 22:08:03 -05001786 const transformation &_t,
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001787 int _ax_count,
1788 int _pass_number) : decompose_domain(0, _c.accum->height(),
dd761b64
DH
David Hilvert2008-01-26 17:41:00 +00001789 0, _c.accum->width()),
1790 t(_t) {
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001791
1792 asum = _asum;
1793 bsum = _bsum;
1794 c = _c;
214d014c
DH
David Hilvert2008-05-04 22:08:03 -05001795 ax_count = _ax_count;
1796 pass_number = _pass_number;
1797 }
1798
1799 exposure_ratio_iterate(pixel_accum *_asum,
1800 pixel_accum *_bsum,
1801 struct scale_cluster _c,
1802 const transformation &_t,
1803 int _ax_count,
1804 int _pass_number,
1805 transformation::elem_bounds_int_t b) : decompose_domain(b.imin, b.imax,
1806 b.jmin, b.jmax),
1807 t(_t) {
1808
1809 asum = _asum;
1810 bsum = _bsum;
1811 c = _c;
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001812 ax_count = _ax_count;
1813 pass_number = _pass_number;
1814 }
1815 };
1816
2aa417e6 dhilvert2005-01-07 06:44:00 +00001817 static void set_exposure_ratio(unsigned int m, struct scale_cluster c,
993fde09 David Hilvert2008-05-05 05:28:56 +00001818 const transformation &t, int ax_count, int pass_number) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00001819
3dc20778 dhilvert2005-01-10 23:06:00 +00001820 if (_exp_register == 2) {
1821 /*
1822 * Use metadata only.
1823 */
1824 ale_real gain_multiplier = image_rw::exp(m).get_gain_multiplier();
1825 pixel multiplier = pixel(gain_multiplier, gain_multiplier, gain_multiplier);
1826
1827 image_rw::exp(m).set_multiplier(multiplier);
a9d66b26 dhilvert2005-01-10 23:15:00 +00001828 ui::get()->exp_multiplier(multiplier[0],
1829 multiplier[1],
1830 multiplier[2]);
3d7fd555 dhilvert2005-01-10 23:10:00 +00001831
1832 return;
3dc20778 dhilvert2005-01-10 23:06:00 +00001833 }
1834
70fb02f9 David Hilvert2007-09-21 03:18:00 +00001835 pixel_accum asum(0, 0, 0), bsum(0, 0, 0);
30afe4b6 dhilvert2005-01-07 06:42:00 +00001836
70fb02f9
DH
David Hilvert2007-09-21 03:18:00 +00001837 exposure_ratio_iterate eri(&asum, &bsum, c, t, ax_count, pass_number);
1838 eri.run();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001839
1840 // std::cerr << (asum / bsum) << " ";
07271611 dhilvert2005-01-07 06:48:00 +00001841
1842 pixel_accum new_multiplier;
1843
1844 new_multiplier = asum / bsum * image_rw::exp(m).get_multiplier();
30afe4b6 dhilvert2005-01-07 06:42:00 +00001845
07271611 dhilvert2005-01-07 06:48:00 +00001846 if (finite(new_multiplier[0])
1847 && finite(new_multiplier[1])
1848 && finite(new_multiplier[2])) {
1849 image_rw::exp(m).set_multiplier(new_multiplier);
1850 ui::get()->exp_multiplier(new_multiplier[0],
1851 new_multiplier[1],
1852 new_multiplier[2]);
1853 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001854 }
1855
df55d1a2 dhilvert2006-08-30 07:40:00 +00001856 /*
1857 * Copy all ax parameters.
1858 */
1859 static exclusion *copy_ax_parameters(int local_ax_count, exclusion *source) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001860
df55d1a2 dhilvert2006-08-30 07:40:00 +00001861 exclusion *dest = (exclusion *) malloc(local_ax_count * sizeof(exclusion));
2aa417e6 dhilvert2005-01-07 06:44:00 +00001862
df55d1a2 dhilvert2006-08-30 07:40:00 +00001863 assert (dest);
2aa417e6 dhilvert2005-01-07 06:44:00 +00001864
df55d1a2 dhilvert2006-08-30 07:40:00 +00001865 if (!dest)
07271611 dhilvert2005-01-07 06:48:00 +00001866 ui::get()->memory_error("exclusion regions");
2aa417e6 dhilvert2005-01-07 06:44:00 +00001867
df55d1a2 dhilvert2006-08-30 07:40:00 +00001868 for (int idx = 0; idx < local_ax_count; idx++)
1869 dest[idx] = source[idx];
2aa417e6 dhilvert2005-01-07 06:44:00 +00001870
df55d1a2 dhilvert2006-08-30 07:40:00 +00001871 return dest;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001872 }
1873
df55d1a2 dhilvert2006-08-30 07:40:00 +00001874 /*
1875 * Copy ax parameters according to frame.
1876 */
1877 static exclusion *filter_ax_parameters(int frame, int *local_ax_count) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001878
df55d1a2 dhilvert2006-08-30 07:40:00 +00001879 exclusion *dest = (exclusion *) malloc(ax_count * sizeof(exclusion));
46f9776a dhilvert2005-01-07 06:44:00 +00001880
df55d1a2 dhilvert2006-08-30 07:40:00 +00001881 assert (dest);
46f9776a dhilvert2005-01-07 06:44:00 +00001882
df55d1a2 dhilvert2006-08-30 07:40:00 +00001883 if (!dest)
07271611 dhilvert2005-01-07 06:48:00 +00001884 ui::get()->memory_error("exclusion regions");
46f9776a dhilvert2005-01-07 06:44:00 +00001885
1886 *local_ax_count = 0;
1887
1888 for (int idx = 0; idx < ax_count; idx++) {
df55d1a2 dhilvert2006-08-30 07:40:00 +00001889 if (ax_parameters[idx].x[4] > frame
1890 || ax_parameters[idx].x[5] < frame)
46f9776a dhilvert2005-01-07 06:44:00 +00001891 continue;
1892
df55d1a2 dhilvert2006-08-30 07:40:00 +00001893 dest[*local_ax_count] = ax_parameters[idx];
46f9776a dhilvert2005-01-07 06:44:00 +00001894
1895 (*local_ax_count)++;
1896 }
1897
df55d1a2 dhilvert2006-08-30 07:40:00 +00001898 return dest;
1899 }
46f9776a dhilvert2005-01-07 06:44:00 +00001900
df55d1a2 dhilvert2006-08-30 07:40:00 +00001901 static void scale_ax_parameters(int local_ax_count, exclusion *ax_parameters,
1902 ale_pos ref_scale, ale_pos input_scale) {
1903 for (int i = 0; i < local_ax_count; i++) {
1904 ale_pos scale = (ax_parameters[i].type == exclusion::RENDER)
1905 ? ref_scale
1906 : input_scale;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001907
df55d1a2 dhilvert2006-08-30 07:40:00 +00001908 for (int n = 0; n < 6; n++) {
e1eaf84c David Hilvert2007-07-24 02:50:00 +00001909 ax_parameters[i].x[n] = ax_parameters[i].x[n] * scale;
df55d1a2 dhilvert2006-08-30 07:40:00 +00001910 }
1911 }
46f9776a dhilvert2005-01-07 06:44:00 +00001912 }
1913
2aa417e6 dhilvert2005-01-07 06:44:00 +00001914 /*
1915 * Prepare the next level of detail for ordinary images.
1916 */
1917 static const image *prepare_lod(const image *current) {
1918 if (current == NULL)
1919 return NULL;
46f9776a dhilvert2005-01-07 06:44:00 +00001920
2aa417e6 dhilvert2005-01-07 06:44:00 +00001921 return current->scale_by_half("prepare_lod");
1922 }
46f9776a dhilvert2005-01-07 06:44:00 +00001923
2aa417e6 dhilvert2005-01-07 06:44:00 +00001924 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00001925 * Prepare the next level of detail for definition maps.
1926 */
1927 static const image *prepare_lod_def(const image *current) {
7a19e165
DH
David Hilvert2007-09-10 21:16:00 +00001928 if (current == NULL)
1929 return NULL;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001930
1931 return current->defined_scale_by_half("prepare_lod_def");
1932 }
1933
1934 /*
8f2ed1fd David Hilvert2007-09-07 18:36:00 +00001935 * Initialize scale cluster data structures.
2aa417e6 dhilvert2005-01-07 06:44:00 +00001936 */
8f2ed1fd
DH
David Hilvert2007-09-07 18:36:00 +00001937
1938 static void init_nl_cluster(struct scale_cluster *sc) {
1939 }
1940
2aa417e6 dhilvert2005-01-07 06:44:00 +00001941 /*
1942 * Destroy the first element in the scale cluster data structure.
1943 */
a85f57f9 David Hilvert2007-10-15 17:07:00 +00001944 static void final_clusters(struct scale_cluster *scale_clusters, ale_pos scale_factor,
2aa417e6 dhilvert2005-01-07 06:44:00 +00001945 unsigned int steps) {
1946
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001947 if (scale_clusters[0].input_scale < 1.0) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00001948 delete scale_clusters[0].input;
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001949 }
2aa417e6 dhilvert2005-01-07 06:44:00 +00001950
44a1d1de
DH
David Hilvert2009-03-30 19:02:57 +00001951 delete scale_clusters[0].input_certainty;
1952
2aa417e6 dhilvert2005-01-07 06:44:00 +00001953 free((void *)scale_clusters[0].ax_parameters);
1954
1955 for (unsigned int step = 1; step < steps; step++) {
1956 delete scale_clusters[step].accum;
580b5321 David Hilvert2007-09-10 17:35:00 +00001957 delete scale_clusters[step].certainty;
2aa417e6 dhilvert2005-01-07 06:44:00 +00001958 delete scale_clusters[step].aweight;
1959
c6e3d33a David Hilvert2007-10-02 15:57:00 +00001960 if (scale_clusters[step].input_scale < 1.0) {
07271611 dhilvert2005-01-07 06:48:00 +00001961 delete scale_clusters[step].input;
c6e3d33a
DH
David Hilvert2007-10-02 15:57:00 +00001962 delete scale_clusters[step].input_certainty;
1963 }
07271611 dhilvert2005-01-07 06:48:00 +00001964
2aa417e6 dhilvert2005-01-07 06:44:00 +00001965 free((void *)scale_clusters[step].ax_parameters);
1966 }
1967
1968 free(scale_clusters);
46f9776a dhilvert2005-01-07 06:44:00 +00001969 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00001970
1971 /*
c052e200 dhilvert2005-05-08 16:16:00 +00001972 * Calculate the centroid of a control point for the set of frames
1973 * having index lower than m. Divide by any scaling of the output.
1974 */
1975 static point unscaled_centroid(unsigned int m, unsigned int p) {
1976 assert(_keep);
1977
1978 point point_sum(0, 0);
1979 ale_accum divisor = 0;
1980
1981 for(unsigned int j = 0; j < m; j++) {
1982 point pp = cp_array[p][j];
1983
1984 if (pp.defined()) {
1985 point_sum += kept_t[j].transform_unscaled(pp)
1986 / kept_t[j].scale();
1987 divisor += 1;
1988 }
1989 }
1990
1991 if (divisor == 0)
1992 return point::undefined();
1993
1994 return point_sum / divisor;
1995 }
1996
1997 /*
1998 * Calculate centroid of this frame, and of all previous frames,
1999 * from points common to both sets.
2000 */
2001 static void centroids(unsigned int m, point *current, point *previous) {
2002 /*
2003 * Calculate the translation
2004 */
2005 point other_centroid(0, 0);
2006 point this_centroid(0, 0);
2007 ale_pos divisor = 0;
2008
2009 for (unsigned int i = 0; i < cp_count; i++) {
2010 point other_c = unscaled_centroid(m, i);
2011 point this_c = cp_array[i][m];
2012
2013 if (!other_c.defined() || !this_c.defined())
2014 continue;
2015
2016 other_centroid += other_c;
2017 this_centroid += this_c;
2018 divisor += 1;
2019
2020 }
2021
2022 if (divisor == 0) {
2023 *current = point::undefined();
2024 *previous = point::undefined();
2025 return;
2026 }
2027
2028 *current = this_centroid / divisor;
2029 *previous = other_centroid / divisor;
2030 }
2031
2032 /*
b386e644 dhilvert2005-04-30 09:28:00 +00002033 * Calculate the RMS error of control points for frame m, with
2034 * transformation t, against control points for earlier frames.
2035 */
e812ee44 David Hilvert2007-10-18 18:24:00 +00002036 static ale_pos cp_rms_error(unsigned int m, transformation t) {
b386e644 dhilvert2005-04-30 09:28:00 +00002037 assert (_keep);
2038
2039 ale_accum err = 0;
2040 ale_accum divisor = 0;
2041
2042 for (unsigned int i = 0; i < cp_count; i++)
2043 for (unsigned int j = 0; j < m; j++) {
2044 const point *p = cp_array[i];
936ff6ec dhilvert2005-05-07 20:02:00 +00002045 point p_ref = kept_t[j].transform_unscaled(p[j]);
2046 point p_cur = t.transform_unscaled(p[m]);
b386e644 dhilvert2005-04-30 09:28:00 +00002047
2048 if (!p_ref.defined() || !p_cur.defined())
2049 continue;
2050
2051 err += p_ref.lengthtosq(p_cur);
2052 divisor += 1;
2053 }
2054
e812ee44 David Hilvert2007-10-18 18:24:00 +00002055 return (ale_pos) sqrt(err / divisor);
b386e644 dhilvert2005-04-30 09:28:00 +00002056 }
2057
6126fb3c David Hilvert2007-04-03 08:15:00 +00002058
59e5857b David Hilvert2007-05-08 12:15:00 +00002059 static void test_global(diff_stat_t *here, scale_cluster si, transformation t,
a7882498 David Hilvert2007-10-16 19:48:00 +00002060 int local_ax_count, int m, ale_accum local_gs_mo, ale_pos perturb) {
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00002061
2062 diff_stat_t test(*here);
2063
1b980378 David Hilvert2008-07-18 18:30:40 +00002064 test.diff(si, t.get_current_element(), local_ax_count, m);
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00002065
2066 unsigned int ovl = overlap(si, t, local_ax_count);
2067
2068 if (ovl >= local_gs_mo && test.better()) {
2069 test.confirm();
2070 *here = test;
2071 ui::get()->set_match(here->get_error());
2072 ui::get()->set_offset(here->get_offset());
2073 } else {
2074 test.discard();
2075 }
2076
2077 }
2078
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002079 /*
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002080 * Get the set of global transformations for a given density
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002081 */
59e5857b
DH
David Hilvert2007-05-08 12:15:00 +00002082 static void test_globals(diff_stat_t *here,
2083 scale_cluster si, transformation t, int local_gs, ale_pos adj_p,
a7882498 David Hilvert2007-10-16 19:48:00 +00002084 int local_ax_count, int m, ale_accum local_gs_mo, ale_pos perturb) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002085
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002086 transformation offset = t;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002087
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002088 point min, max;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002089
eb01b1b8 David Hilvert2007-04-24 05:36:00 +00002090 transformation offset_p = offset;
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002091
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002092 if (!offset_p.is_projective())
2093 offset_p.eu_to_gpt();
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002094
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002095 min = max = offset_p.gpt_get(0);
2096 for (int p_index = 1; p_index < 4; p_index++) {
2097 point p = offset_p.gpt_get(p_index);
2098 if (p[0] < min[0])
2099 min[0] = p[0];
2100 if (p[1] < min[1])
2101 min[1] = p[1];
2102 if (p[0] > max[0])
2103 max[0] = p[0];
2104 if (p[1] > max[1])
2105 max[1] = p[1];
2106 }
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002107
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002108 point inner_min_t = -min;
2109 point inner_max_t = -max + point(si.accum->height(), si.accum->width());
2110 point outer_min_t = -max + point(adj_p - 1, adj_p - 1);
2111 point outer_max_t = point(si.accum->height(), si.accum->width()) - point(adj_p, adj_p);
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002112
02eb92ab David Hilvert2007-05-08 07:11:00 +00002113 if (local_gs == 1 || local_gs == 3 || local_gs == 4 || local_gs == 6) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002114
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002115 /*
2116 * Inner
2117 */
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002118
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002119 for (ale_pos i = inner_min_t[0]; i <= inner_max_t[0]; i += adj_p)
2120 for (ale_pos j = inner_min_t[1]; j <= inner_max_t[1]; j += adj_p) {
2121 transformation test_t = offset;
2122 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002123 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002124 }
2125 }
2126
02eb92ab David Hilvert2007-05-08 07:11:00 +00002127 if (local_gs == 2 || local_gs == 3 || local_gs == -1 || local_gs == 6) {
f2d60fe2 David Hilvert2007-04-13 23:28:00 +00002128
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002129 /*
2130 * Outer
2131 */
2132
2133 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
2134 for (ale_pos j = outer_min_t[1]; j < inner_min_t[1]; j += adj_p) {
2135 transformation test_t = offset;
2136 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002137 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002138 }
2139 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
2140 for (ale_pos j = outer_max_t[1]; j > inner_max_t[1]; j -= adj_p) {
2141 transformation test_t = offset;
2142 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002143 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002144 }
2145 for (ale_pos i = outer_min_t[0]; i < inner_min_t[0]; i += adj_p)
2146 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
2147 transformation test_t = offset;
2148 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002149 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
eb01b1b8
DH
David Hilvert2007-04-24 05:36:00 +00002150 }
2151 for (ale_pos i = outer_max_t[0]; i > inner_max_t[0]; i -= adj_p)
2152 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
2153 transformation test_t = offset;
2154 test_t.translate(point(i, j));
afa6d8f6 David Hilvert2007-05-13 03:19:00 +00002155 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
f2d60fe2
DH
David Hilvert2007-04-13 23:28:00 +00002156 }
2157 }
cc71efb2
DH
David Hilvert2007-04-08 16:37:00 +00002158 }
2159
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00002160 static void get_translational_set(std::vector<transformation> *set,
2161 transformation t, ale_pos adj_p) {
2162
2163 ale_pos adj_s;
2164
2165 transformation offset = t;
dd761b64 David Hilvert2008-01-26 17:41:00 +00002166 transformation test_t(transformation::eu_identity());
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00002167
2168 for (int i = 0; i < 2; i++)
2169 for (adj_s = -adj_p; adj_s <= adj_p; adj_s += 2 * adj_p) {
2170
2171 test_t = offset;
2172
5b7749b0 David Hilvert2007-04-26 04:36:00 +00002173 test_t.translate(i ? point(adj_s, 0) : point(0, adj_s));
a9e10df7
DH
David Hilvert2007-04-25 12:39:00 +00002174
2175 set->push_back(test_t);
2176 }
2177 }
2178
cd621c15 David Hilvert2007-07-23 20:38:00 +00002179 static int threshold_ok(ale_accum error) {
34add5e1 David Hilvert2007-10-17 21:47:00 +00002180 if ((1 - error) * (ale_accum) 100 >= match_threshold)
cd621c15
DH
David Hilvert2007-07-23 20:38:00 +00002181 return 1;
2182
2183 if (!(match_threshold >= 0))
2184 return 1;
2185
2186 return 0;
2187 }
228e156a David Hilvert2007-04-22 23:17:00 +00002188
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00002189 static diff_stat_t _align_element(ale_pos perturb, ale_pos local_lower,
2190 scale_cluster *scale_clusters, diff_stat_t here,
2191 ale_pos adj_p, ale_pos adj_o, ale_pos adj_b,
2192 ale_pos *current_bd, ale_pos *modified_bd,
2193 astate_t *astate, int lod, scale_cluster si) {
2194
2195 /*
2196 * Run initial tests to get perturbation multipliers and error
2197 * centroids.
2198 */
2199
dd7602d7 David Hilvert2008-03-06 18:41:00 +00002200 std::vector<d2::trans_single> t_set;
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00002201
2202 here.get_perturb_set(&t_set, adj_p, adj_o, adj_b, current_bd, modified_bd);
2203
2204 int stable_count = 0;
2205
2206 while (perturb >= local_lower) {
fc8ecb0a
DH
David Hilvert2008-05-24 21:32:43 +00002207
2208 ui::get()->alignment_dims(scale_clusters[lod].accum->height(), scale_clusters[lod].accum->width(),
2209 scale_clusters[lod].input->height(), scale_clusters[lod].input->width());
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00002210
2211 /*
2212 * Orientational adjustment value in degrees.
2213 *
2214 * Since rotational perturbation is now specified as an
2215 * arclength, we have to convert.
2216 */
2217
2218 ale_pos adj_o = 2 * (double) perturb
2219 / sqrt(pow(scale_clusters[0].input->height(), 2)
2220 + pow(scale_clusters[0].input->width(), 2))
2221 * 180
2222 / M_PI;
2223
2224 /*
2225 * Barrel distortion adjustment value
2226 */
2227
2228 ale_pos adj_b = perturb * bda_mult;
2229
648ade15 David Hilvert2008-07-03 03:49:22 +00002230 trans_single old_offset = here.get_offset();
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00002231
2232 here.perturb_test(perturb, adj_p, adj_o, adj_b, current_bd, modified_bd,
2233 stable_count);
2234
648ade15 David Hilvert2008-07-03 03:49:22 +00002235 if (here.get_offset() == old_offset)
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00002236 stable_count++;
2237 else
2238 stable_count = 0;
2239
2240 if (stable_count == 3) {
2241
2242 stable_count = 0;
2243
dd7602d7 David Hilvert2008-03-06 18:41:00 +00002244 perturb *= 0.5;
3e3f229f David Hilvert2008-02-13 16:42:00 +00002245
5bb67119 David Hilvert2008-05-31 02:43:37 +00002246 if (lod > 0
a9f7d778 David Hilvert2008-05-31 06:39:31 +00002247 && lod > lrint(log(perturb) / log(2)) - lod_preferred) {
3e3f229f David Hilvert2008-02-13 16:42:00 +00002248
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00002249 /*
2250 * Work with images twice as large
2251 */
3e3f229f David Hilvert2008-02-13 16:42:00 +00002252
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00002253 lod--;
2254 si = scale_clusters[lod];
3e3f229f David Hilvert2008-02-13 16:42:00 +00002255
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00002256 /*
2257 * Rescale the transforms.
2258 */
3e3f229f David Hilvert2008-02-13 16:42:00 +00002259
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00002260 ale_pos rescale_factor = (double) scale_factor
2261 / (double) pow(2, lod)
2262 / (double) here.get_offset().scale();
3e3f229f David Hilvert2008-02-13 16:42:00 +00002263
dd7602d7 David Hilvert2008-03-06 18:41:00 +00002264 here.rescale(rescale_factor, si);
3e3f229f David Hilvert2008-02-13 16:42:00 +00002265
dd7602d7 David Hilvert2008-03-06 18:41:00 +00002266 } else {
6a39b1c3 David Hilvert2008-05-31 06:21:26 +00002267 adj_p = perturb / pow(2, lod);
dd7602d7 David Hilvert2008-03-06 18:41:00 +00002268 }
3e3f229f David Hilvert2008-02-13 16:42:00 +00002269
dd7602d7
DH
David Hilvert2008-03-06 18:41:00 +00002270 /*
2271 * Announce changes
2272 */
3e3f229f David Hilvert2008-02-13 16:42:00 +00002273
dd7602d7 David Hilvert2008-03-06 18:41:00 +00002274 ui::get()->alignment_perturbation_level(perturb, lod);
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00002275 }
2276
2277 ui::get()->set_match(here.get_error());
2278 ui::get()->set_offset(here.get_offset());
2279 }
2280
2281 if (lod > 0) {
2282 ale_pos rescale_factor = (double) scale_factor
3e3f229f
DH
David Hilvert2008-02-13 16:42:00 +00002283 / (double) here.get_offset().scale();
2284
2285 here.rescale(rescale_factor, scale_clusters[0]);
2286 }
2287
2288 return here;
2289 }
2290
228e156a David Hilvert2007-04-22 23:17:00 +00002291 /*
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00002292 * Check for satisfaction of the certainty threshold.
2293 */
2294 static int ma_cert_satisfied(const scale_cluster &c, const transformation &t, unsigned int i) {
d790f7da David Hilvert2008-05-02 18:59:43 -05002295 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 +00002296 ale_accum sum[3] = {0, 0, 0};
2297
d790f7da
DH
David Hilvert2008-05-02 18:59:43 -05002298 for (unsigned int ii = b.imin; ii < b.imax; ii++)
2299 for (unsigned int jj = b.jmin; jj < b.jmax; jj++) {
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00002300 pixel p = c.accum->get_pixel(ii, jj);
2301 sum[0] += p[0];
2302 sum[1] += p[1];
2303 sum[2] += p[2];
2304 }
2305
d790f7da David Hilvert2008-05-02 18:59:43 -05002306 unsigned int count = (b.jmax - b.jmin) * (b.imax - b.imin);
3fa727c5
DH
David Hilvert2008-04-26 00:41:37 +00002307
2308 for (int k = 0; k < 3; k++)
2309 if (sum[k] / count < _ma_cert)
2310 return 0;
2311
2312 return 1;
2313 }
2314
1b980378
DH
David Hilvert2008-07-18 18:30:40 +00002315 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) {
2316
2317 if (offset.get_current_index() > 0)
2318 for (int i = offset.parent_index(offset.get_current_index()); i >= 0; i = (i > 0) ? (int) offset.parent_index(i) : -1) {
2319 trans_single t = offset.get_element(i);
2320 t.rescale(offset.get_current_element().scale());
2321
2322 here.diff(si, t, local_ax_count, frame);
2323
e0577945 David Hilvert2008-07-19 22:11:55 +00002324 if (here.better_defined())
1b980378
DH
David Hilvert2008-07-18 18:30:40 +00002325 here.confirm();
2326 else
2327 here.discard();
2328 }
2329
2330 return here;
2331 }
2332
46f9776a dhilvert2005-01-07 06:44:00 +00002333#ifdef USE_FFTW
2334 /*
2335 * High-pass filter for frequency weights
2336 */
2337 static void hipass(int rows, int cols, fftw_complex *inout) {
2338 for (int i = 0; i < rows * vert_freq_cut; i++)
2339 for (int j = 0; j < cols; j++)
2340 for (int k = 0; k < 2; k++)
2341 inout[i * cols + j][k] = 0;
2342 for (int i = 0; i < rows; i++)
2343 for (int j = 0; j < cols * horiz_freq_cut; j++)
2344 for (int k = 0; k < 2; k++)
2345 inout[i * cols + j][k] = 0;
2346 for (int i = 0; i < rows; i++)
2347 for (int j = 0; j < cols; j++)
2348 for (int k = 0; k < 2; k++)
2349 if (i / (double) rows + j / (double) cols < 2 * avg_freq_cut)
2350 inout[i * cols + j][k] = 0;
2351 }
2352#endif
2353
2aa417e6 dhilvert2005-01-07 06:44:00 +00002354
2355 /*
2356 * Reset alignment weights
2357 */
2358 static void reset_weights() {
07271611 dhilvert2005-01-07 06:48:00 +00002359 if (alignment_weights != NULL)
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002360 ale_image_release(alignment_weights);
07271611 dhilvert2005-01-07 06:48:00 +00002361
2362 alignment_weights = NULL;
2aa417e6 dhilvert2005-01-07 06:44:00 +00002363 }
2364
2365 /*
2366 * Initialize alignment weights
2367 */
2368 static void init_weights() {
2369 if (alignment_weights != NULL)
2370 return;
2371
3617b771 David Hilvert2009-05-31 15:07:14 +00002372 alignment_weights = ale_new_image(accel::context(), ALE_IMAGE_RGB, ale_image_get_type(reference_image));
2aa417e6 dhilvert2005-01-07 06:44:00 +00002373
2374 assert (alignment_weights);
2375
e28f8ff7 David Hilvert2009-06-02 22:23:44 +00002376 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 +00002377
e28f8ff7 David Hilvert2009-06-02 22:23:44 +00002378 ale_image_map_0(alignment_weights, "SET_PIXEL(p, PIXEL(1, 1, 1))");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002379 }
2380
46f9776a dhilvert2005-01-07 06:44:00 +00002381 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002382 * Update alignment weights with weight map
2383 */
2384 static void map_update() {
2385
2386 if (weight_map == NULL)
2387 return;
2388
2389 init_weights();
2390
c17dab23 David Hilvert2009-06-04 15:49:20 +00002391 ale_image_map_2(alignment_weights, alignment_weights, weight_map, " \
af765c9b David Hilvert2009-06-12 19:51:02 +00002392 SET_PIXEL(p, GET_PIXEL(0, p) * GET_PIXEL_BG(1, p))");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002393 }
2394
2395 /*
2396 * Update alignment weights with algorithmic weights
46f9776a dhilvert2005-01-07 06:44:00 +00002397 */
2398 static void wmx_update() {
2399#ifdef USE_UNIX
2400
2401 static exposure *exp_def = new exposure_default();
2402 static exposure *exp_bool = new exposure_boolean();
2403
46f9776a dhilvert2005-01-07 06:44:00 +00002404 if (wmx_file == NULL || wmx_exec == NULL || wmx_defs == NULL)
2405 return;
2406
33a3cc28
DH
David Hilvert2009-06-03 19:51:46 +00002407 unsigned int rows = ale_image_get_height(reference_image);
2408 unsigned int cols = ale_image_get_width(reference_image);
46f9776a dhilvert2005-01-07 06:44:00 +00002409
2410 image_rw::write_image(wmx_file, reference_image);
ac4577d5 David Hilvert2009-06-14 19:02:25 +00002411 image_rw::write_image(wmx_defs, reference_image, exp_bool->get_gamma(), 0, 0, 1);
46f9776a dhilvert2005-01-07 06:44:00 +00002412
2413 /* execute ... */
2414 int exit_status = 1;
2415 if (!fork()) {
2416 execlp(wmx_exec, wmx_exec, wmx_file, wmx_defs, NULL);
07271611 dhilvert2005-01-07 06:48:00 +00002417 ui::get()->exec_failure(wmx_exec, wmx_file, wmx_defs);
46f9776a dhilvert2005-01-07 06:44:00 +00002418 }
2419
2420 wait(&exit_status);
2421
07271611 dhilvert2005-01-07 06:48:00 +00002422 if (exit_status)
2423 ui::get()->fork_failure("d2::align");
46f9776a dhilvert2005-01-07 06:44:00 +00002424
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002425 ale_image wmx_weights = image_rw::read_image(wmx_file, exp_def);
46f9776a dhilvert2005-01-07 06:44:00 +00002426
35c1c6e3
DH
David Hilvert2009-06-14 21:17:14 +00002427 ale_image_set_x_offset(wmx_weights, ale_image_get_x_offset(reference_image));
2428 ale_image_set_y_offset(wmx_weights, ale_image_get_y_offset(reference_image));
5073b97e David Hilvert2009-06-14 20:59:56 +00002429
c2d1a70e David Hilvert2009-05-30 15:37:04 +00002430 if (ale_image_get_height(wmx_weights) != rows || ale_image_get_width(wmx_weights) != cols)
07271611 dhilvert2005-01-07 06:48:00 +00002431 ui::get()->error("algorithmic weighting must not change image size");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002432
2433 if (alignment_weights == NULL)
2434 alignment_weights = wmx_weights;
2435 else
5073b97e
DH
David Hilvert2009-06-14 20:59:56 +00002436 ale_image_map_2(alignment_weights, alignment_weights, wmx_weights, "\
2437 SET_PIXEL(p, GET_PIXEL(0, p) * GET_PIXEL(1, p))");
46f9776a dhilvert2005-01-07 06:44:00 +00002438#endif
2439 }
2440
2441 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002442 * Update alignment weights with frequency weights
46f9776a dhilvert2005-01-07 06:44:00 +00002443 */
2444 static void fw_update() {
2445#ifdef USE_FFTW
46f9776a dhilvert2005-01-07 06:44:00 +00002446 if (horiz_freq_cut == 0
2447 && vert_freq_cut == 0
2448 && avg_freq_cut == 0)
2449 return;
2450
2aa417e6 dhilvert2005-01-07 06:44:00 +00002451 /*
2452 * Required for correct operation of --fwshow
2453 */
2454
2455 assert (alignment_weights == NULL);
2456
46f9776a dhilvert2005-01-07 06:44:00 +00002457 int rows = reference_image->height();
2458 int cols = reference_image->width();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002459 int colors = reference_image->depth();
46f9776a dhilvert2005-01-07 06:44:00 +00002460
7cc12274 David Hilvert2007-12-11 04:50:00 +00002461 alignment_weights = new_image_ale_real(rows, cols,
2aa417e6 dhilvert2005-01-07 06:44:00 +00002462 colors, "alignment_weights");
46f9776a dhilvert2005-01-07 06:44:00 +00002463
2464 fftw_complex *inout = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * rows * cols);
2465
2466 assert (inout);
2467
2468 fftw_plan pf = fftw_plan_dft_2d(rows, cols,
2469 inout, inout,
2470 FFTW_FORWARD, FFTW_ESTIMATE);
2471
2472 fftw_plan pb = fftw_plan_dft_2d(rows, cols,
2473 inout, inout,
2474 FFTW_BACKWARD, FFTW_ESTIMATE);
2475
2aa417e6 dhilvert2005-01-07 06:44:00 +00002476 for (int k = 0; k < colors; k++) {
46f9776a dhilvert2005-01-07 06:44:00 +00002477 for (int i = 0; i < rows * cols; i++) {
2478 inout[i][0] = reference_image->get_pixel(i / cols, i % cols)[k];
2479 inout[i][1] = 0;
2480 }
2481
2482 fftw_execute(pf);
2483 hipass(rows, cols, inout);
2484 fftw_execute(pb);
2485
2486 for (int i = 0; i < rows * cols; i++) {
2487#if 0
2aa417e6 dhilvert2005-01-07 06:44:00 +00002488 alignment_weights->pix(i / cols, i % cols)[k] = fabs(inout[i][0] / (rows * cols));
46f9776a dhilvert2005-01-07 06:44:00 +00002489#else
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00002490 alignment_weights->set_chan(i / cols, i % cols, k,
46f9776a dhilvert2005-01-07 06:44:00 +00002491 sqrt(pow(inout[i][0] / (rows * cols), 2)
e4e7ac02 David Hilvert2007-12-12 23:20:00 +00002492 + pow(inout[i][1] / (rows * cols), 2)));
46f9776a dhilvert2005-01-07 06:44:00 +00002493#endif
2494 }
2495 }
2496
2497 fftw_destroy_plan(pf);
2498 fftw_destroy_plan(pb);
2499 fftw_free(inout);
2500
2501 if (fw_output != NULL)
2aa417e6 dhilvert2005-01-07 06:44:00 +00002502 image_rw::write_image(fw_output, alignment_weights);
46f9776a dhilvert2005-01-07 06:44:00 +00002503#endif
2504 }
2505
30afe4b6 dhilvert2005-01-07 06:42:00 +00002506 /*
2507 * Update alignment to frame N.
2508 */
2509 static void update_to(int n) {
0e4ec247 David Hilvert2007-03-13 04:51:00 +00002510
30afe4b6 dhilvert2005-01-07 06:42:00 +00002511 assert (n <= latest + 1);
0a432b63 David Hilvert2007-03-13 08:03:00 +00002512 assert (n >= 0);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002513
e580d9d3 David Hilvert2007-12-19 16:59:00 +00002514 static astate_t astate;
f65325e3 David Hilvert2007-03-15 06:24:00 +00002515
724b1c71
DH
David Hilvert2008-07-01 15:20:56 +00002516 ui::get()->set_frame_num(n);
2517
46f9776a dhilvert2005-01-07 06:44:00 +00002518 if (latest < 0) {
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002519
2520 /*
2521 * Handle the initial frame
2522 */
2523
0467efe3 David Hilvert2008-04-09 21:14:38 +00002524 astate.set_input_frame(image_rw::open(n));
0a432b63 David Hilvert2007-03-13 08:03:00 +00002525
0467efe3 David Hilvert2008-04-09 21:14:38 +00002526 const image *i = astate.get_input_frame();
46f9776a dhilvert2005-01-07 06:44:00 +00002527 int is_default;
2528 transformation result = alignment_class == 2
2529 ? transformation::gpt_identity(i, scale_factor)
2530 : transformation::eu_identity(i, scale_factor);
2531 result = tload_first(tload, alignment_class == 2, result, &is_default);
2532 tsave_first(tsave, result, alignment_class == 2);
46f9776a dhilvert2005-01-07 06:44:00 +00002533
2534 if (_keep > 0) {
dd761b64 David Hilvert2008-01-26 17:41:00 +00002535 kept_t = transformation::new_eu_identity_array(image_rw::count());
46f9776a dhilvert2005-01-07 06:44:00 +00002536 kept_ok = (int *) malloc(image_rw::count()
2537 * sizeof(int));
2538 assert (kept_t);
2539 assert (kept_ok);
2540
07271611 dhilvert2005-01-07 06:48:00 +00002541 if (!kept_t || !kept_ok)
2542 ui::get()->memory_error("alignment");
46f9776a dhilvert2005-01-07 06:44:00 +00002543
2544 kept_ok[0] = 1;
2545 kept_t[0] = result;
2546 }
2547
2548 latest = 0;
2549 latest_ok = 1;
2550 latest_t = result;
2551
0467efe3 David Hilvert2008-04-09 21:14:38 +00002552 astate.set_default(result);
46f9776a dhilvert2005-01-07 06:44:00 +00002553 orig_t = result;
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002554
2555 image_rw::close(n);
46f9776a dhilvert2005-01-07 06:44:00 +00002556 }
2557
bbc7699c David Hilvert2007-04-02 03:05:00 +00002558 for (int i = latest + 1; i <= n; i++) {
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002559
2560 /*
2561 * Handle supplemental frames.
2562 */
2563
46f9776a dhilvert2005-01-07 06:44:00 +00002564 assert (reference != NULL);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002565
07271611 dhilvert2005-01-07 06:48:00 +00002566 ui::get()->set_arender_current();
46f9776a dhilvert2005-01-07 06:44:00 +00002567 reference->sync(i - 1);
07271611 dhilvert2005-01-07 06:48:00 +00002568 ui::get()->clear_arender_current();
46f9776a dhilvert2005-01-07 06:44:00 +00002569 reference_image = reference->get_image();
2570 reference_defined = reference->get_defined();
30afe4b6 dhilvert2005-01-07 06:42:00 +00002571
f2fc9b99 David Hilvert2008-02-14 17:35:00 +00002572 if (i == 1)
0467efe3 David Hilvert2008-04-09 21:14:38 +00002573 astate.default_set_original_bounds(reference_image);
f2fc9b99 David Hilvert2008-02-14 17:35:00 +00002574
2aa417e6 dhilvert2005-01-07 06:44:00 +00002575 reset_weights();
46f9776a dhilvert2005-01-07 06:44:00 +00002576 fw_update();
2577 wmx_update();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002578 map_update();
30afe4b6 dhilvert2005-01-07 06:42:00 +00002579
46f9776a dhilvert2005-01-07 06:44:00 +00002580 assert (reference_image != NULL);
2581 assert (reference_defined != NULL);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002582
0467efe3 David Hilvert2008-04-09 21:14:38 +00002583 astate.set_input_frame(image_rw::open(i));
0a432b63 David Hilvert2007-03-13 08:03:00 +00002584
e580d9d3 David Hilvert2007-12-19 16:59:00 +00002585 _align(i, _gs, &astate);
0a432b63
DH
David Hilvert2007-03-13 08:03:00 +00002586
2587 image_rw::close(n);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002588 }
2589 }
2590
2591public:
2592
2593 /*
04382119 dhilvert2005-04-29 09:23:00 +00002594 * Set the control point count
2595 */
2596 static void set_cp_count(unsigned int n) {
2597 assert (cp_array == NULL);
2598
2599 cp_count = n;
2600 cp_array = (const point **) malloc(n * sizeof(const point *));
2601 }
2602
2603 /*
2604 * Set control points.
2605 */
2606 static void set_cp(unsigned int i, const point *p) {
2607 cp_array[i] = p;
2608 }
2609
2610 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002611 * Register exposure
2612 */
2613 static void exp_register() {
2614 _exp_register = 1;
2615 }
2616
2617 /*
3dc20778 dhilvert2005-01-10 23:06:00 +00002618 * Register exposure only based on metadata
2619 */
2620 static void exp_meta_only() {
2621 _exp_register = 2;
2622 }
2623
2624 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002625 * Don't register exposure
2626 */
2627 static void exp_noregister() {
2628 _exp_register = 0;
2629 }
2630
2631 /*
2632 * Set alignment class to translation only. Only adjust the x and y
2633 * position of images. Do not rotate input images or perform
2634 * projective transformations.
2635 */
2636 static void class_translation() {
2637 alignment_class = 0;
2638 }
2639
2640 /*
2641 * Set alignment class to Euclidean transformations only. Adjust the x
2642 * and y position of images and the orientation of the image about the
2643 * image center.
2644 */
2645 static void class_euclidean() {
2646 alignment_class = 1;
2647 }
2648
2649 /*
2650 * Set alignment class to perform general projective transformations.
2651 * See the file gpt.h for more information about general projective
2652 * transformations.
2653 */
2654 static void class_projective() {
2655 alignment_class = 2;
2656 }
2657
2658 /*
2659 * Set the default initial alignment to the identity transformation.
2660 */
2661 static void initial_default_identity() {
2662 default_initial_alignment_type = 0;
2663 }
2664
2665 /*
2666 * Set the default initial alignment to the most recently matched
2667 * frame's final transformation.
2668 */
2669 static void initial_default_follow() {
2670 default_initial_alignment_type = 1;
2671 }
2672
2673 /*
f09b7254 dhilvert2005-01-07 06:44:00 +00002674 * Perturb output coordinates.
2675 */
2676 static void perturb_output() {
2677 perturb_type = 0;
2678 }
2679
2680 /*
2681 * Perturb source coordinates.
2682 */
2683 static void perturb_source() {
2684 perturb_type = 1;
2685 }
2686
2687 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002688 * Frames under threshold align optimally
2689 */
2690 static void fail_optimal() {
2691 is_fail_default = 0;
2692 }
2693
2694 /*
2695 * Frames under threshold keep their default alignments.
2696 */
2697 static void fail_default() {
2698 is_fail_default = 1;
2699 }
2700
2701 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002702 * Align images with an error contribution from each color channel.
2703 */
2704 static void all() {
2705 channel_alignment_type = 0;
2706 }
2707
2708 /*
2709 * Align images with an error contribution only from the green channel.
2710 * Other color channels do not affect alignment.
2711 */
2712 static void green() {
2713 channel_alignment_type = 1;
2714 }
2715
2716 /*
2717 * Align images using a summation of channels. May be useful when
2718 * dealing with images that have high frequency color ripples due to
2719 * color aliasing.
2720 */
2721 static void sum() {
2722 channel_alignment_type = 2;
2723 }
2724
2725 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002726 * Error metric exponent
2727 */
2728
2729 static void set_metric_exponent(float me) {
2730 metric_exponent = me;
2731 }
2732
2733 /*
2734 * Match threshold
2735 */
2736
2737 static void set_match_threshold(float mt) {
2738 match_threshold = mt;
2739 }
2740
2741 /*
2742 * Perturbation lower and upper bounds.
2743 */
2744
f09b7254 dhilvert2005-01-07 06:44:00 +00002745 static void set_perturb_lower(ale_pos pl, int plp) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002746 perturb_lower = pl;
f09b7254 dhilvert2005-01-07 06:44:00 +00002747 perturb_lower_percent = plp;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002748 }
2749
f09b7254 dhilvert2005-01-07 06:44:00 +00002750 static void set_perturb_upper(ale_pos pu, int pup) {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002751 perturb_upper = pu;
f09b7254 dhilvert2005-01-07 06:44:00 +00002752 perturb_upper_percent = pup;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002753 }
2754
2755 /*
2756 * Maximum rotational perturbation.
2757 */
2758
2759 static void set_rot_max(int rm) {
2760
2761 /*
2762 * Obtain the largest power of two not larger than rm.
2763 */
2764
2765 rot_max = pow(2, floor(log(rm) / log(2)));
2766 }
2767
2768 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002769 * Barrel distortion adjustment multiplier
2770 */
2771
2772 static void set_bda_mult(ale_pos m) {
2773 bda_mult = m;
2774 }
2775
2776 /*
2777 * Barrel distortion maximum rate of change
2778 */
2779
2780 static void set_bda_rate(ale_pos m) {
2781 bda_rate = m;
2782 }
2783
2784 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002785 * Level-of-detail
2786 */
2787
5292ffa7
DH
David Hilvert2008-05-28 01:17:53 +00002788 static void set_lod_preferred(int lm) {
2789 lod_preferred = lm;
2790 }
2791
2792 /*
2793 * Minimum dimension for reduced level-of-detail.
2794 */
2795
2796 static void set_min_dimension(int md) {
2797 min_dimension = md;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002798 }
2799
2800 /*
2801 * Set the scale factor
2802 */
2803 static void set_scale(ale_pos s) {
2804 scale_factor = s;
2805 }
2806
2807 /*
2808 * Set reference rendering to align against
2809 */
2810 static void set_reference(render *r) {
2811 reference = r;
2812 }
2813
2814 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002815 * Set the interpolant
2816 */
2817 static void set_interpolant(filter::scaled_filter *f) {
2818 interpolant = f;
2819 }
2820
2821 /*
2822 * Set alignment weights image
2823 */
2aa417e6 dhilvert2005-01-07 06:44:00 +00002824 static void set_weight_map(const image *i) {
2825 weight_map = i;
46f9776a dhilvert2005-01-07 06:44:00 +00002826 }
2827
2828 /*
2829 * Set frequency cuts
2830 */
2831 static void set_frequency_cut(double h, double v, double a) {
2832 horiz_freq_cut = h;
2833 vert_freq_cut = v;
2834 avg_freq_cut = a;
2835 }
2836
2837 /*
2838 * Set algorithmic alignment weighting
2839 */
2840 static void set_wmx(const char *e, const char *f, const char *d) {
2841 wmx_exec = e;
2842 wmx_file = f;
2843 wmx_defs = d;
2844 }
2845
2846 /*
2847 * Show frequency weights
2848 */
2849 static void set_fl_show(const char *filename) {
2850 fw_output = filename;
2851 }
2852
2853 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002854 * Set transformation file loader.
2855 */
2856 static void set_tload(tload_t *tl) {
2857 tload = tl;
2858 }
2859
2860 /*
2861 * Set transformation file saver.
2862 */
2863 static void set_tsave(tsave_t *ts) {
2864 tsave = ts;
2865 }
2866
2867 /*
2868 * Get match statistics for frame N.
30afe4b6 dhilvert2005-01-07 06:42:00 +00002869 */
2870 static int match(int n) {
2871 update_to(n);
2872
46f9776a dhilvert2005-01-07 06:44:00 +00002873 if (n == latest)
30afe4b6 dhilvert2005-01-07 06:42:00 +00002874 return latest_ok;
2875 else if (_keep)
2876 return kept_ok[n];
46f9776a dhilvert2005-01-07 06:44:00 +00002877 else {
30afe4b6 dhilvert2005-01-07 06:42:00 +00002878 assert(0);
46f9776a dhilvert2005-01-07 06:44:00 +00002879 exit(1);
2880 }
30afe4b6 dhilvert2005-01-07 06:42:00 +00002881 }
2882
2883 /*
2884 * Message that old alignment data should be kept.
2885 */
2886 static void keep() {
46f9776a dhilvert2005-01-07 06:44:00 +00002887 assert (latest == -1);
30afe4b6 dhilvert2005-01-07 06:42:00 +00002888 _keep = 1;
2889 }
2890
2891 /*
2892 * Get alignment for frame N.
30afe4b6 dhilvert2005-01-07 06:42:00 +00002893 */
2894 static transformation of(int n) {
2895 update_to(n);
46f9776a dhilvert2005-01-07 06:44:00 +00002896 if (n == latest)
30afe4b6 dhilvert2005-01-07 06:42:00 +00002897 return latest_t;
2898 else if (_keep)
2899 return kept_t[n];
2900 else {
2901 assert(0);
2902 exit(1);
2903 }
2904 }
2905
2906 /*
bddc9e4d David Hilvert2007-10-01 19:50:00 +00002907 * Use Monte Carlo alignment sampling with argument N.
1c2f7405 David Hilvert2007-09-20 16:58:00 +00002908 */
bddc9e4d
DH
David Hilvert2007-10-01 19:50:00 +00002909 static void mc(ale_pos n) {
2910 _mc = n;
1c2f7405
DH
David Hilvert2007-09-20 16:58:00 +00002911 }
2912
2913 /*
07271611 dhilvert2005-01-07 06:48:00 +00002914 * Set the certainty-weighted flag.
2915 */
2916 static void certainty_weighted(int flag) {
2917 certainty_weights = flag;
2918 }
2919
2920 /*
2aa417e6 dhilvert2005-01-07 06:44:00 +00002921 * Set the global search type.
2922 */
2923 static void gs(const char *type) {
7bcfe5db dhilvert2005-01-07 06:44:00 +00002924 if (!strcmp(type, "local")) {
2aa417e6 dhilvert2005-01-07 06:44:00 +00002925 _gs = 0;
2926 } else if (!strcmp(type, "inner")) {
2927 _gs = 1;
2928 } else if (!strcmp(type, "outer")) {
2929 _gs = 2;
2930 } else if (!strcmp(type, "all")) {
2931 _gs = 3;
2932 } else if (!strcmp(type, "central")) {
2933 _gs = 4;
842afc18
DH
David Hilvert2007-05-08 06:55:00 +00002934 } else if (!strcmp(type, "defaults")) {
2935 _gs = 6;
04382119 dhilvert2005-04-29 09:23:00 +00002936 } else if (!strcmp(type, "points")) {
2937 _gs = 5;
b386e644 dhilvert2005-04-30 09:28:00 +00002938 keep();
2aa417e6 dhilvert2005-01-07 06:44:00 +00002939 } else {
07271611 dhilvert2005-01-07 06:48:00 +00002940 ui::get()->error("bad global search type");
2aa417e6 dhilvert2005-01-07 06:44:00 +00002941 }
2942 }
2943
2944 /*
4949c031 dhilvert2005-01-07 06:44:00 +00002945 * Set the minimum overlap for global searching
2946 */
326c35b1 David Hilvert2007-04-19 21:28:00 +00002947 static void gs_mo(ale_pos value, int _gs_mo_percent) {
4949c031 dhilvert2005-01-07 06:44:00 +00002948 _gs_mo = value;
326c35b1 David Hilvert2007-04-19 21:28:00 +00002949 gs_mo_percent = _gs_mo_percent;
4949c031 dhilvert2005-01-07 06:44:00 +00002950 }
2951
2952 /*
903df240
DH
David Hilvert2008-04-24 14:36:35 +00002953 * Set mutli-alignment certainty lower bound.
2954 */
2955 static void set_ma_cert(ale_real value) {
2956 _ma_cert = value;
2957 }
2958
2959 /*
46f9776a dhilvert2005-01-07 06:44:00 +00002960 * Set alignment exclusion regions
2961 */
df55d1a2 dhilvert2006-08-30 07:40:00 +00002962 static void set_exclusion(exclusion *_ax_parameters, int _ax_count) {
46f9776a dhilvert2005-01-07 06:44:00 +00002963 ax_count = _ax_count;
2964 ax_parameters = _ax_parameters;
2965 }
2966
2967 /*
30afe4b6 dhilvert2005-01-07 06:42:00 +00002968 * Get match summary statistics.
2969 */
2970 static ale_accum match_summary() {
34add5e1 David Hilvert2007-10-17 21:47:00 +00002971 return match_sum / (ale_accum) match_count;
30afe4b6 dhilvert2005-01-07 06:42:00 +00002972 }
2973};
2974
f8864302
DH
David Hilvert2008-04-11 18:15:57 +00002975template<class diff_trans>
2976void *d2::align::diff_stat_generic<diff_trans>::diff_subdomain(void *args) {
2977
2978 subdomain_args *sargs = (subdomain_args *) args;
2979
2980 struct scale_cluster c = sargs->c;
2981 std::vector<run> runs = sargs->runs;
2982 int ax_count = sargs->ax_count;
2983 int f = sargs->f;
2984 int i_min = sargs->i_min;
2985 int i_max = sargs->i_max;
2986 int j_min = sargs->j_min;
2987 int j_max = sargs->j_max;
2988 int subdomain = sargs->subdomain;
2989
2990 assert (reference_image);
2991
2992 point offset = c.accum->offset();
2993
2994 for (mc_iterate m(i_min, i_max, j_min, j_max, subdomain); !m.done(); m++) {
2995
2996 int i = m.get_i();
2997 int j = m.get_j();
2998
2999 /*
3000 * Check reference frame definition.
3001 */
3002
3003 if (!((pixel) c.accum->get_pixel(i, j)).finite()
3004 || !(((pixel) c.certainty->get_pixel(i, j)).minabs_norm() > 0))
3005 continue;
3006
3007 /*
3008 * Check for exclusion in render coordinates.
3009 */
3010
3011 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
3012 continue;
3013
3014 /*
3015 * Transform
3016 */
3017
3018 struct point q, r = point::undefined();
3019
3020 q = (c.input_scale < 1.0 && interpolant == NULL)
3021 ? runs.back().offset.scaled_inverse_transform(
3022 point(i + offset[0], j + offset[1]))
3023 : runs.back().offset.unscaled_inverse_transform(
3024 point(i + offset[0], j + offset[1]));
3025
3026 if (runs.size() == 2) {
3027 r = (c.input_scale < 1.0)
3028 ? runs.front().offset.scaled_inverse_transform(
3029 point(i + offset[0], j + offset[1]))
3030 : runs.front().offset.unscaled_inverse_transform(
3031 point(i + offset[0], j + offset[1]));
3032 }
3033
3034 ale_pos ti = q[0];
3035 ale_pos tj = q[1];
3036
3037 /*
3038 * Check that the transformed coordinates are within
3039 * the boundaries of array c.input and that they
3040 * are not subject to exclusion.
3041 *
3042 * Also, check that the weight value in the accumulated array
3043 * is nonzero, unless we know it is nonzero by virtue of the
3044 * fact that it falls within the region of the original frame
3045 * (e.g. when we're not increasing image extents).
3046 */
3047
3048 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
3049 continue;
3050
3051 if (input_excluded(r[0], r[1], c.ax_parameters, ax_count))
3052 r = point::undefined();
3053
3054 /*
3055 * Check the boundaries of the input frame
3056 */
3057
3058 if (!(ti >= 0
3059 && ti <= c.input->height() - 1
3060 && tj >= 0
3061 && tj <= c.input->width() - 1))
3062 continue;
3063
3064 if (!(r[0] >= 0
3065 && r[0] <= c.input->height() - 1
3066 && r[1] >= 0
3067 && r[1] <= c.input->width() - 1))
3068 r = point::undefined();
3069
3070 sargs->runs.back().sample(f, c, i, j, q, r, runs.front());
3071 }
3072
3073 return NULL;
3074}
3075
30afe4b6 dhilvert2005-01-07 06:42:00 +00003076#endif