Modify handling of --identity in d2::align so that the element structure of multi...
[Ale.git] / d2 / align.h
blob45482e5152fbbeb5ec9c0999eecedb8b505f6820
1 // Copyright 2002, 2004 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
4 /* This file is part of the Anti-Lamenessing Engine.
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
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
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.
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
22 * align.h: Handle alignment of frames.
25 #ifndef __d2align_h__
26 #define __d2align_h__
28 #include "filter.h"
29 #include "transformation.h"
30 #include "image.h"
31 #include "point.h"
32 #include "render.h"
33 #include "tfile.h"
34 #include "image_rw.h"
36 class align {
37 private:
40 * Private data members
43 static ale_pos scale_factor;
46 * Original frame transformation
48 static transformation orig_t;
51 * Keep data older than latest
53 static int _keep;
54 static transformation *kept_t;
55 static int *kept_ok;
58 * Transformation file handlers
61 static tload_t *tload;
62 static tsave_t *tsave;
65 * Control point variables
68 static const point **cp_array;
69 static unsigned int cp_count;
72 * Reference rendering to align against
75 static render *reference;
76 static filter::scaled_filter *interpolant;
77 static const image *reference_image;
78 static const image *reference_defined;
81 * Per-pixel alignment weight map
84 static const image *weight_map;
87 * Frequency-dependent alignment weights
90 static double horiz_freq_cut;
91 static double vert_freq_cut;
92 static double avg_freq_cut;
93 static const char *fw_output;
96 * Algorithmic alignment weighting
99 static const char *wmx_exec;
100 static const char *wmx_file;
101 static const char *wmx_defs;
104 * Consolidated alignment weights
106 * The final value of alignment_weights_const is the canonical weight
107 * set. If alignment_weights_const is set but alignment_weights is
108 * not, then the memory is not ours, and the object should not be
109 * modified or deleted.
112 static image *alignment_weights;
113 static const image *alignment_weights_const;
116 * Latest transformation.
119 static transformation latest_t;
122 * Flag indicating whether the latest transformation
123 * resulted in a match.
126 static int latest_ok;
129 * Frame number most recently aligned.
132 static int latest;
135 * Exposure registration
137 * 0. Preserve the original exposure of images.
139 * 1. Match exposure between images.
141 * 2. Use only image metadata for registering exposure.
144 static int _exp_register;
147 * Alignment class.
149 * 0. Translation only. Only adjust the x and y position of images.
150 * Do not rotate input images or perform projective transformations.
152 * 1. Euclidean transformations only. Adjust the x and y position
153 * of images and the orientation of the image about the image center.
155 * 2. Perform general projective transformations. See the file gpt.h
156 * for more information about general projective transformations.
159 static int alignment_class;
162 * Default initial alignment type.
164 * 0. Identity transformation.
166 * 1. Most recently accepted frame's final transformation.
169 static int default_initial_alignment_type;
172 * Projective group behavior
174 * 0. Perturb in output coordinates.
176 * 1. Perturb in source coordinates
179 static int perturb_type;
182 * Alignment element
184 * This structure contains variables necessary for handling a
185 * multi-alignment element. The change between the non-default old
186 * initial alignment and old final alignment is used to adjust the
187 * non-default current initial alignment. If either the old or new
188 * initial alignment is a default alignment, the old --follow semantics
189 * are preserved.
192 struct element_t {
193 int is_default, old_is_default;
194 int is_primary;
195 int old_lod;
196 transformation old_initial_alignment;
197 transformation old_final_alignment;
198 transformation default_initial_alignment;
199 const image *input_frame;
201 public:
202 element_t() {
203 is_default = 1;
204 input_frame = NULL;
209 * Alignment for failed frames -- default or optimal?
211 * A frame that does not meet the match threshold can be assigned the
212 * best alignment found, or can be assigned its alignment default.
215 static int is_fail_default;
218 * Alignment code.
220 * 0. Align images with an error contribution from each color channel.
222 * 1. Align images with an error contribution only from the green channel.
223 * Other color channels do not affect alignment.
225 * 2. Align images using a summation of channels. May be useful when dealing
226 * with images that have high frequency color ripples due to color aliasing.
229 static int channel_alignment_type;
232 * Error metric exponent
235 static float metric_exponent;
238 * Match threshold
241 static float match_threshold;
244 * Perturbation lower and upper bounds.
247 static ale_pos perturb_lower;
248 static int perturb_lower_percent;
249 static ale_pos perturb_upper;
250 static int perturb_upper_percent;
253 * Maximum level-of-detail scale factor is 2^lod_max/perturb.
256 static int lod_max;
259 * Maximum rotational perturbation
262 static ale_pos rot_max;
265 * Barrel distortion alignment multiplier
268 static ale_pos bda_mult;
271 * Barrel distortion maximum adjustment rate
274 static ale_pos bda_rate;
277 * Alignment match sum
280 static ale_accum match_sum;
283 * Alignment match count.
286 static int match_count;
289 * Monte Carlo parameter
291 * 0. Don't use monte carlo alignment sampling.
293 * (0,1]. Select, on average, a number of pixels which is the
294 * specified fraction of the number of pixels in the accumulated image.
297 static ale_pos _mc;
298 static int _mcd_limit;
301 * Certainty weight flag
303 * 0. Don't use certainty weights for alignment.
305 * 1. Use certainty weights for alignment.
308 static int certainty_weights;
311 * Global search parameter
313 * 0. Local: Local search only.
314 * 1. Inner: Alignment reference image inner region
315 * 2. Outer: Alignment reference image outer region
316 * 3. All: Alignment reference image inner and outer regions.
317 * 4. Central: Inner if possible; else, best of inner and outer.
318 * 5. Points: Align by control points.
321 static int _gs;
324 * Multi-alignment cardinality.
327 static unsigned int _ma_card;
330 * Multi-alignment contiguity.
333 static double _ma_cont;
336 * Minimum overlap for global searches
339 static unsigned int _gs_mo;
342 * Exclusion regions
345 static exclusion *ax_parameters;
346 static int ax_count;
349 * Type for scale cluster.
352 struct scale_cluster {
353 const image *accum;
354 const image *defined;
355 const image *aweight;
356 exclusion *ax_parameters;
358 ale_pos input_scale;
359 const image *input;
363 * Check for exclusion region coverage in the reference
364 * array.
366 static int ref_excluded(int i, int j, point offset, exclusion *params, int param_count) {
367 for (int idx = 0; idx < param_count; idx++)
368 if (params[idx].type == exclusion::RENDER
369 && i + offset[0] >= params[idx].x[0]
370 && i + offset[0] <= params[idx].x[1]
371 && j + offset[1] >= params[idx].x[2]
372 && j + offset[1] <= params[idx].x[3])
373 return 1;
375 return 0;
379 * Check for exclusion region coverage in the input
380 * array.
382 static int input_excluded(ale_pos ti, ale_pos tj, exclusion *params, int param_count) {
383 for (int idx = 0; idx < param_count; idx++)
384 if (params[idx].type == exclusion::FRAME
385 && ti >= params[idx].x[0]
386 && ti <= params[idx].x[1]
387 && tj >= params[idx].x[2]
388 && tj <= params[idx].x[3])
389 return 1;
391 return 0;
395 * Overlap function. Determines the number of pixels in areas where
396 * the arrays overlap. Uses the reference array's notion of pixel
397 * positions.
399 static unsigned int overlap(struct scale_cluster c, transformation t, int ax_count) {
400 assert (reference_image);
402 unsigned int result = 0;
404 point offset = c.accum->offset();
406 for (unsigned int i = 0; i < c.accum->height(); i++)
407 for (unsigned int j = 0; j < c.accum->width(); j++) {
409 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
410 continue;
413 * Transform
416 struct point q;
418 q = (c.input_scale < 1.0 && interpolant == NULL)
419 ? t.scaled_inverse_transform(
420 point(i + offset[0], j + offset[1]))
421 : t.unscaled_inverse_transform(
422 point(i + offset[0], j + offset[1]));
424 ale_pos ti = q[0];
425 ale_pos tj = q[1];
428 * Check that the transformed coordinates are within
429 * the boundaries of array c.input, and check that the
430 * weight value in the accumulated array is nonzero,
431 * unless we know it is nonzero by virtue of the fact
432 * that it falls within the region of the original
433 * frame (e.g. when we're not increasing image
434 * extents). Also check for frame exclusion.
437 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
438 continue;
440 if (ti >= 0
441 && ti <= c.input->height() - 1
442 && tj >= 0
443 && tj <= c.input->width() - 1
444 && c.defined->get_pixel(i, j)[0] != 0)
445 result++;
448 return result;
452 * Not-quite-symmetric difference function. Determines the difference in areas
453 * where the arrays overlap. Uses the reference array's notion of pixel positions.
455 * For the purposes of determining the difference, this function divides each
456 * pixel value by the corresponding image's average pixel magnitude, unless we
457 * are:
459 * a) Extending the boundaries of the image, or
461 * b) following the previous frame's transform
463 * If we are doing monte-carlo pixel sampling for alignment, we
464 * typically sample a subset of available pixels; otherwise, we sample
465 * all pixels.
469 class diff_stat_t {
470 ale_accum result;
471 ale_accum divisor;
473 point max, min;
474 ale_accum centroid[2], centroid_divisor;
476 typedef unsigned int hist_bin;
478 int hist_min_r;
479 int hist_min_d;
481 hist_bin *histogram;
482 hist_bin *histogram_integral;
483 hist_bin hist_total;
484 int hist_dim;
486 void add_hist(int r, int d, int count) {
488 hist_total += count;
490 int r_shift = 0, d_shift = 0;
492 if (r - hist_min_r >= hist_dim) {
493 r_shift = (r - hist_min_r) - hist_dim + 1;
494 hist_min_r += r_shift;
497 if (d - hist_min_d >= hist_dim) {
498 d_shift = (d - hist_min_d) - hist_dim + 1;
499 hist_min_d += d_shift;
502 assert (r_shift >= 0);
503 assert (d_shift >= 0);
505 if (r_shift || d_shift) {
506 for (int rr = 0; rr < hist_dim; rr++)
507 for (int dd = 0; dd < hist_dim; dd++) {
509 hist_bin value = histogram[rr * hist_dim + dd];
511 histogram[rr * hist_dim + dd] = 0;
513 int rrr = rr - r_shift;
514 int ddd = dd - d_shift;
516 if (rrr < 0)
517 rrr = 0;
518 if (ddd < 0)
519 ddd = 0;
521 histogram[rrr * hist_dim + ddd] += value;
525 r -= hist_min_r;
526 d -= hist_min_d;
528 if (r < 0)
529 r = 0;
530 if (d < 0)
531 d = 0;
533 histogram[r * hist_dim + d] += count;
536 void add_hist(ale_accum result, ale_accum divisor) {
537 ale_accum rbin = log(result) / log(2);
538 ale_accum dbin = log(divisor) / log(2);
540 if (!(rbin > INT_MIN))
541 rbin = INT_MIN;
542 if (!(dbin > INT_MIN))
543 dbin = INT_MIN;
545 add_hist((int) floor(rbin), (int) floor(dbin), 1);
548 public:
549 diff_stat_t() {
550 result = 0;
551 divisor = 0;
552 hist_min_r = INT_MIN;
553 hist_min_d = INT_MIN;
554 hist_dim = 20;
555 hist_total = 0;
556 histogram = (hist_bin *) calloc(hist_dim * hist_dim, sizeof(hist_bin));
558 min = point::posinf();
559 max = point::neginf();
561 centroid[0] = 0;
562 centroid[1] = 0;
563 centroid_divisor = 0;
566 void clear() {
567 free(histogram);
569 result = 0;
570 divisor = 0;
571 hist_min_r = INT_MIN;
572 hist_min_d = INT_MIN;
573 hist_total = 0;
574 histogram = (hist_bin *) calloc(hist_dim * hist_dim, sizeof(hist_bin));
577 ~diff_stat_t() {
578 free(histogram);
581 int check_removal(diff_stat_t *with) {
582 ale_accum bresult, bdivisor, wresult, wdivisor;
583 hist_bin *bhist, *whist;
585 ui::get()->d2_align_sim_start();
587 bhist = (hist_bin *)malloc(sizeof(hist_bin) * hist_dim * hist_dim);
588 whist = (hist_bin *)malloc(sizeof(hist_bin) * with->hist_dim * with->hist_dim);
590 bresult = result;
591 bdivisor = divisor;
592 wresult = with->result;
593 wdivisor = with->divisor;
595 for (int i = 0; i < hist_dim * hist_dim; i++)
596 bhist[i] = histogram[i];
598 for (int i = 0; i < with->hist_dim * with->hist_dim; i++)
599 whist[i] = with->histogram[i];
601 for (int r = 0; r < _mcd_limit; r++) {
602 int max_gradient_bin = -1;
603 int max_gradient_hist = -1;
604 ale_accum max_gradient = 0;
606 for (int i = 0; i < hist_dim * hist_dim; i++) {
607 if (bhist[i] <= 0)
608 continue;
610 ale_accum br = pow(2, hist_min_r + i / hist_dim);
611 ale_accum bd = pow(2, hist_min_d + i % hist_dim);
612 ale_accum b_test_gradient =
613 (bresult - br) / (bdivisor - bd) - bresult / bdivisor;
615 if (b_test_gradient > max_gradient) {
616 max_gradient_bin = i;
617 max_gradient_hist = 0;
618 max_gradient = b_test_gradient;
622 for (int i = 0; i < with->hist_dim * with->hist_dim; i++) {
623 if (whist[i] <= 0)
624 continue;
626 ale_accum wr = pow(2, with->hist_min_r + i / with->hist_dim);
627 ale_accum wd = pow(2, with->hist_min_d + i % with->hist_dim);
628 ale_accum w_test_gradient =
629 wresult / wdivisor - (wresult - wr) / (wdivisor - wd);
631 if (w_test_gradient > max_gradient) {
632 max_gradient_bin = i;
633 max_gradient_hist = 1;
634 max_gradient = w_test_gradient;
638 if (max_gradient_hist == 0) {
639 bhist[max_gradient_bin]--;
640 bresult -= pow(2, hist_min_r + max_gradient_bin / hist_dim);
641 bdivisor -= pow(2, hist_min_d + max_gradient_bin % hist_dim);
642 } else if (max_gradient_hist == 1) {
643 whist[max_gradient_bin]--;
644 wresult -= pow(2, with->hist_min_r + max_gradient_bin / with->hist_dim);
645 wdivisor -= pow(2, with->hist_min_d + max_gradient_bin % with->hist_dim);
649 free(bhist);
650 free(whist);
652 ui::get()->d2_align_sim_stop();
654 if (bresult / bdivisor < wresult / wdivisor)
655 return 1;
657 return 0;
660 int reliable(diff_stat_t *with, ale_pos mc) {
661 return check_removal(with);
664 void add(const diff_stat_t *ds) {
665 result += ds->result;
666 divisor += ds->divisor;
668 for (int r = 0; r < ds->hist_dim; r++)
669 for (int d = 0; d < ds->hist_dim; d++)
670 add_hist(r + ds->hist_min_r, d + ds->hist_min_d,
671 ds->histogram[r * hist_dim + d]);
673 for (int d = 0; d < 2; d++) {
674 if (min[d] > ds->min[d])
675 min[d] = ds->min[d];
676 if (max[d] < ds->max[d])
677 max[d] = ds->max[d];
678 centroid[d] += ds->centroid[d];
681 centroid_divisor += ds->centroid_divisor;
684 ale_accum get_result() {
685 return result;
688 ale_accum get_divisor() {
689 return divisor;
692 point get_centroid() {
693 point result = point(centroid[0] / centroid_divisor, centroid[1] / centroid_divisor);
695 assert (finite(centroid[0])
696 && finite(centroid[1])
697 && (result.defined() || centroid_divisor == 0));
699 return result;
702 ale_accum get_error() {
703 return pow(result / divisor, 1/metric_exponent);
706 void sample(int f, scale_cluster c, int i, int j, ale_pos ti, ale_pos tj) {
707 pixel pa = c.accum->get_pixel(i, j);
708 pixel pb;
709 pixel weight;
710 ale_accum this_result = 0;
711 ale_accum this_divisor = 0;
714 if (interpolant != NULL)
715 interpolant->filtered(i, j, &pb, &weight, 1, f);
716 else {
717 pixel result[2];
718 c.input->get_bl(point(ti, tj), result);
719 pb = result[0];
720 weight = result[1];
724 * Handle certainty.
727 if (certainty_weights == 0)
728 weight = pixel(1, 1, 1);
730 if (c.aweight != NULL)
731 weight *= c.aweight->get_pixel(i, j);
734 * Update sampling area statistics
737 if (min[0] > i)
738 min[0] = i;
739 if (min[1] > j)
740 min[1] = j;
741 if (max[0] < i)
742 max[0] = i;
743 if (max[1] < j)
744 max[1] = j;
746 centroid[0] += (weight[0] + weight[1] + weight[2]) * i;
747 centroid[1] += (weight[0] + weight[1] + weight[2]) * j;
748 centroid_divisor += (weight[0] + weight[1] + weight[2]);
751 * Determine alignment type.
754 if (channel_alignment_type == 0) {
756 * Align based on all channels.
760 for (int k = 0; k < 3; k++) {
761 ale_real achan = pa[k];
762 ale_real bchan = pb[k];
764 this_result += weight[k] * pow(fabs(achan - bchan), metric_exponent);
765 this_divisor += weight[k] * pow(achan > bchan ? achan : bchan, metric_exponent);
767 } else if (channel_alignment_type == 1) {
769 * Align based on the green channel.
772 ale_real achan = pa[1];
773 ale_real bchan = pb[1];
775 this_result = weight[1] * pow(fabs(achan - bchan), metric_exponent);
776 this_divisor = weight[1] * pow(achan > bchan ? achan : bchan, metric_exponent);
777 } else if (channel_alignment_type == 2) {
779 * Align based on the sum of all channels.
782 ale_real asum = 0;
783 ale_real bsum = 0;
784 ale_real wsum = 0;
786 for (int k = 0; k < 3; k++) {
787 asum += pa[k];
788 bsum += pb[k];
789 wsum += weight[k] / 3;
792 this_result = wsum * pow(fabs(asum - bsum), metric_exponent);
793 this_divisor = wsum * pow(asum > bsum ? asum : bsum, metric_exponent);
796 result += this_result;
797 divisor += this_divisor;
799 add_hist(this_result, this_divisor);
802 void print_hist() {
803 fprintf(stderr, "\n");
804 fprintf(stderr, "hist_min_r = %d\n", hist_min_r);
805 fprintf(stderr, "hist_min_d = %d\n", hist_min_d);
806 fprintf(stderr, "hist_dim = %d\n", hist_dim);
807 fprintf(stderr, "hist_total = %d\n", hist_total);
808 fprintf(stderr, "\n");
810 hist_bin recalc_total = 0;
812 for (int r = 0; r < hist_dim; r++) {
813 for (int d = 0; d < hist_dim; d++) {
814 recalc_total += histogram[r * hist_dim + d];
815 fprintf(stderr, "\t%d", histogram[r * hist_dim + d]);
817 fprintf(stderr, "\n");
820 fprintf(stderr, "\n");
821 fprintf(stderr, "recalc_total = %d\n", recalc_total);
825 struct subdomain_args {
826 struct scale_cluster c;
827 transformation t;
828 ale_pos _mc_arg;
829 int ax_count;
830 int f;
831 diff_stat_t* diff_stat;
832 int i_min, i_max, j_min, j_max;
833 int subdomain;
836 static void *diff_subdomain(void *args) {
838 subdomain_args *sargs = (subdomain_args *) args;
840 struct scale_cluster c = sargs->c;
841 transformation t = sargs->t;
842 ale_pos _mc_arg = sargs->_mc_arg;
843 int ax_count = sargs->ax_count;
844 int f = sargs->f;
845 int i_min = sargs->i_min;
846 int i_max = sargs->i_max;
847 int j_min = sargs->j_min;
848 int j_max = sargs->j_max;
849 int subdomain = sargs->subdomain;
851 assert (reference_image);
853 point offset = c.accum->offset();
855 int i, j;
858 * We always use the same code for exhaustive and Monte Carlo
859 * pixel sampling, setting _mc_arg = 1 when all pixels are to
860 * be sampled.
863 if (_mc_arg <= 0 || _mc_arg >= 1)
864 _mc_arg = 1;
866 int index;
868 int index_max = (i_max - i_min) * (j_max - j_min);
871 * We use a random process for which the expected
872 * number of sampled pixels is +/- .000003 from mc_arg
873 * in the range [.005,.995] for an image with 100,000
874 * pixels. (The actual number may still deviate from
875 * the expected number by more than this amount,
876 * however.) The method is as follows:
878 * We have mc_arg == USE/ALL, or (expected # pixels to
879 * use)/(# total pixels). We derive from this
880 * SKIP/USE.
882 * SKIP/USE == (SKIP/ALL)/(USE/ALL) == (1 - (USE/ALL))/(USE/ALL)
884 * Once we have SKIP/USE, we know the expected number
885 * of pixels to skip in each iteration. We use a random
886 * selection process that provides SKIP/USE close to
887 * this calculated value.
889 * If we can draw uniformly to select the number of
890 * pixels to skip, we do. In this case, the maximum
891 * number of pixels to skip is twice the expected
892 * number.
894 * If we cannot draw uniformly, we still assign equal
895 * probability to each of the integer values in the
896 * interval [0, 2 * (SKIP/USE)], but assign an unequal
897 * amount to the integer value ceil(2 * SKIP/USE) + 1.
900 ale_pos u = (1 - _mc_arg) / _mc_arg;
902 ale_pos mc_max = (floor(2*u) * (1 + floor(2*u)) + 2*u)
903 / (2 + 2 * floor(2*u) - 2*u);
906 * Reseed the random number generator; we want the
907 * same set of pixels to be used when comparing two
908 * alignment options. If we wanted to avoid bias from
909 * repeatedly utilizing the same seed, we could seed
910 * with the number of the frame most recently aligned:
912 * srand(latest);
914 * However, in cursory tests, it seems okay to just use
915 * the default seed of 1, and so we do this, since it
916 * is simpler; both of these approaches to reseeding
917 * achieve better results than not reseeding. (1 is
918 * the default seed according to the GNU Manual Page
919 * for rand(3).)
921 * For subdomain calculations, we vary the seed by subdomain.
924 rng_t rng;
926 rng.seed(1 + subdomain);
928 for(index = -1 + (int) ceil((mc_max+1)
929 * ( (1 + ((ale_pos) (rng.get())) )
930 / (1 + ((ale_pos) RAND_MAX)) ));
931 index < index_max;
932 index += (int) ceil((mc_max+1)
933 * ( (1 + ((ale_pos) (rng.get())) )
934 / (1 + ((ale_pos) RAND_MAX)) ))){
936 i = index / (j_max - j_min) + i_min;
937 j = index % (j_max - j_min) + j_min;
940 * Check for exclusion in render coordinates.
943 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
944 continue;
947 * Check transformation support.
950 if (!t.supported((int) (i + offset[0]), (int) (j + offset[1])))
951 continue;
954 * Transform
957 struct point q;
959 q = (c.input_scale < 1.0 && interpolant == NULL)
960 ? t.scaled_inverse_transform(
961 point(i + offset[0], j + offset[1]))
962 : t.unscaled_inverse_transform(
963 point(i + offset[0], j + offset[1]));
965 ale_pos ti = q[0];
966 ale_pos tj = q[1];
969 * Check that the transformed coordinates are within
970 * the boundaries of array c.input and that they
971 * are not subject to exclusion.
973 * Also, check that the weight value in the accumulated array
974 * is nonzero, unless we know it is nonzero by virtue of the
975 * fact that it falls within the region of the original frame
976 * (e.g. when we're not increasing image extents).
979 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
980 continue;
982 if (ti >= 0
983 && ti <= c.input->height() - 1
984 && tj >= 0
985 && tj <= c.input->width() - 1
986 && c.defined->get_pixel(i, j)[0] != 0)
988 sargs->diff_stat->sample(f, c, i, j, ti, tj);
992 return NULL;
995 static ale_accum diff(struct scale_cluster c, transformation t,
996 ale_pos _mc_arg, int ax_count, int f, diff_stat_t *diff_stat_in = NULL) {
998 diff_stat_t *diff_stat = diff_stat_in;
1000 if (diff_stat == NULL)
1001 diff_stat = new diff_stat_t();
1003 diff_stat->clear();
1005 ui::get()->d2_align_sample_start();
1007 if (interpolant != NULL)
1008 interpolant->set_parameters(t, c.input, c.accum->offset());
1010 int N;
1011 #ifdef USE_PTHREAD
1012 N = thread::count();
1014 pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t) * N);
1015 pthread_attr_t *thread_attr = (pthread_attr_t *) malloc(sizeof(pthread_attr_t) * N);
1017 #else
1018 N = 1;
1019 #endif
1021 subdomain_args *args = new subdomain_args[N];
1023 for (int ti = 0; ti < N; ti++) {
1024 args[ti].c = c;
1025 args[ti].t = t;
1026 args[ti]._mc_arg = _mc_arg;
1027 args[ti].ax_count = ax_count;
1028 args[ti].f = f;
1029 args[ti].diff_stat = new diff_stat_t();
1030 args[ti].i_min = (c.accum->height() * ti) / N;
1031 args[ti].i_max = (c.accum->height() * (ti + 1)) / N;
1032 args[ti].j_min = 0;
1033 args[ti].j_max = c.accum->width();
1034 args[ti].subdomain = ti;
1036 #ifdef USE_PTHREAD
1037 pthread_attr_init(&thread_attr[ti]);
1038 pthread_attr_setdetachstate(&thread_attr[ti], PTHREAD_CREATE_JOINABLE);
1039 pthread_create(&threads[ti], &thread_attr[ti], diff_subdomain, &args[ti]);
1040 #else
1041 diff_subdomain(&args[ti]);
1042 #endif
1045 for (int ti = 0; ti < N; ti++) {
1046 #ifdef USE_PTHREAD
1047 pthread_join(threads[ti], NULL);
1048 #endif
1049 diff_stat->add(args[ti].diff_stat);
1051 delete args[ti].diff_stat;
1054 delete[] args;
1056 ui::get()->d2_align_sample_stop();
1058 ale_accum result = diff_stat->get_error();
1060 if (diff_stat_in == NULL)
1061 delete diff_stat;
1063 return result;
1068 * Adjust exposure for an aligned frame B against reference A.
1070 * Expects full-LOD images.
1072 * This function is a bit of a mess, as it reflects rather ad-hoc rules
1073 * regarding what seems to work w.r.t. certainty. Using certainty in the
1074 * first pass seems to result in worse alignment, while not using certainty
1075 * in the second pass results in incorrect determination of exposure.
1077 * [Note that this may have been due to a bug in certainty determination
1078 * within this function.]
1080 static void set_exposure_ratio(unsigned int m, struct scale_cluster c,
1081 transformation t, int ax_count, int pass_number) {
1083 if (_exp_register == 2) {
1085 * Use metadata only.
1087 ale_real gain_multiplier = image_rw::exp(m).get_gain_multiplier();
1088 pixel multiplier = pixel(gain_multiplier, gain_multiplier, gain_multiplier);
1090 image_rw::exp(m).set_multiplier(multiplier);
1091 ui::get()->exp_multiplier(multiplier[0],
1092 multiplier[1],
1093 multiplier[2]);
1095 return;
1098 pixel_accum asum, bsum;
1100 point offset = c.accum->offset();
1102 for (unsigned int i = 0; i < c.accum->height(); i++)
1103 for (unsigned int j = 0; j < c.accum->width(); j++) {
1105 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
1106 continue;
1109 * Transform
1112 struct point q;
1114 q = (c.input_scale < 1.0 && interpolant == NULL)
1115 ? t.scaled_inverse_transform(
1116 point(i + offset[0], j + offset[1]))
1117 : t.unscaled_inverse_transform(
1118 point(i + offset[0], j + offset[1]));
1121 * Check that the transformed coordinates are within
1122 * the boundaries of array c.input, that they are not
1123 * subject to exclusion, and that the weight value in
1124 * the accumulated array is nonzero.
1127 if (input_excluded(q[0], q[1], c.ax_parameters, ax_count))
1128 continue;
1130 if (q[0] >= 0
1131 && q[0] <= c.input->height() - 1
1132 && q[1] >= 0
1133 && q[1] <= c.input->width() - 1
1134 && c.defined->get_pixel(i, j).minabs_norm() != 0) {
1135 pixel a = c.accum->get_pixel(i, j);
1136 pixel b[2];
1138 c.input->get_bl(q, b);
1140 #if 1
1141 pixel weight = (c.aweight
1142 ? c.aweight->get_pixel(i, j)
1143 : pixel(1, 1, 1))
1144 * ((!certainty_weights && pass_number)
1145 ? c.defined->get_pixel(i, j)
1146 : pixel(1, 1, 1))
1147 * (pass_number
1148 ? b[1]
1149 : pixel(1, 1, 1));
1150 #else
1151 pixel weight = pixel(1, 1, 1);
1152 #endif
1154 asum += a * weight;
1155 bsum += b[0] * weight;
1159 // std::cerr << (asum / bsum) << " ";
1161 pixel_accum new_multiplier;
1163 new_multiplier = asum / bsum * image_rw::exp(m).get_multiplier();
1165 if (finite(new_multiplier[0])
1166 && finite(new_multiplier[1])
1167 && finite(new_multiplier[2])) {
1168 image_rw::exp(m).set_multiplier(new_multiplier);
1169 ui::get()->exp_multiplier(new_multiplier[0],
1170 new_multiplier[1],
1171 new_multiplier[2]);
1176 * Copy all ax parameters.
1178 static exclusion *copy_ax_parameters(int local_ax_count, exclusion *source) {
1180 exclusion *dest = (exclusion *) malloc(local_ax_count * sizeof(exclusion));
1182 assert (dest);
1184 if (!dest)
1185 ui::get()->memory_error("exclusion regions");
1187 for (int idx = 0; idx < local_ax_count; idx++)
1188 dest[idx] = source[idx];
1190 return dest;
1194 * Copy ax parameters according to frame.
1196 static exclusion *filter_ax_parameters(int frame, int *local_ax_count) {
1198 exclusion *dest = (exclusion *) malloc(ax_count * sizeof(exclusion));
1200 assert (dest);
1202 if (!dest)
1203 ui::get()->memory_error("exclusion regions");
1205 *local_ax_count = 0;
1207 for (int idx = 0; idx < ax_count; idx++) {
1208 if (ax_parameters[idx].x[4] > frame
1209 || ax_parameters[idx].x[5] < frame)
1210 continue;
1212 dest[*local_ax_count] = ax_parameters[idx];
1214 (*local_ax_count)++;
1217 return dest;
1220 static void scale_ax_parameters(int local_ax_count, exclusion *ax_parameters,
1221 ale_pos ref_scale, ale_pos input_scale) {
1222 for (int i = 0; i < local_ax_count; i++) {
1223 ale_pos scale = (ax_parameters[i].type == exclusion::RENDER)
1224 ? ref_scale
1225 : input_scale;
1227 for (int n = 0; n < 6; n++) {
1228 ax_parameters[i].x[n] = (int) floor(ax_parameters[i].x[n]
1229 * scale);
1235 * Prepare the next level of detail for ordinary images.
1237 static const image *prepare_lod(const image *current) {
1238 if (current == NULL)
1239 return NULL;
1241 return current->scale_by_half("prepare_lod");
1245 * Prepare the next level of detail for weighted images.
1247 static const image *prepare_lod(const image *current, const image *weights) {
1248 if (current == NULL)
1249 return NULL;
1251 return current->scale_by_half(weights, "prepare_lod");
1255 * Prepare the next level of detail for definition maps.
1257 static const image *prepare_lod_def(const image *current) {
1258 assert(current);
1260 return current->defined_scale_by_half("prepare_lod_def");
1264 * Initialize the scale cluster data structure.
1266 static struct scale_cluster *init_clusters(int frame, ale_real scale_factor,
1267 const image *input_frame, unsigned int steps,
1268 int *local_ax_count) {
1271 * Allocate memory for the array.
1274 struct scale_cluster *scale_clusters =
1275 (struct scale_cluster *) malloc(steps * sizeof(struct scale_cluster));
1277 assert (scale_clusters);
1279 if (!scale_clusters)
1280 ui::get()->memory_error("alignment");
1283 * Prepare images and exclusion regions for the highest level
1284 * of detail.
1287 scale_clusters[0].accum = reference_image;
1289 ui::get()->constructing_lod_clusters(0.0);
1290 scale_clusters[0].input_scale = scale_factor;
1291 if (scale_factor < 1.0 && interpolant == NULL)
1292 scale_clusters[0].input = input_frame->scale(scale_factor, "alignment");
1293 else
1294 scale_clusters[0].input = input_frame;
1296 scale_clusters[0].defined = reference_defined;
1297 scale_clusters[0].aweight = alignment_weights_const;
1298 scale_clusters[0].ax_parameters = filter_ax_parameters(frame, local_ax_count);
1300 scale_ax_parameters(*local_ax_count, scale_clusters[0].ax_parameters, scale_factor,
1301 (scale_factor < 1.0 && interpolant == NULL) ? scale_factor : 1);
1304 * Prepare reduced-detail images and exclusion
1305 * regions.
1308 for (unsigned int step = 1; step < steps; step++) {
1309 ui::get()->constructing_lod_clusters(step);
1310 scale_clusters[step].accum = prepare_lod(scale_clusters[step - 1].accum, scale_clusters[step - 1].aweight);
1311 scale_clusters[step].defined = prepare_lod_def(scale_clusters[step - 1].defined);
1312 scale_clusters[step].aweight = prepare_lod(scale_clusters[step - 1].aweight);
1313 scale_clusters[step].ax_parameters
1314 = copy_ax_parameters(*local_ax_count, scale_clusters[step - 1].ax_parameters);
1316 double sf = scale_clusters[step - 1].input_scale / 2;
1317 scale_clusters[step].input_scale = sf;
1319 if (sf >= 1.0 || interpolant != NULL) {
1320 scale_clusters[step].input = scale_clusters[step - 1].input;
1321 scale_ax_parameters(*local_ax_count, scale_clusters[step].ax_parameters, 0.5, 1);
1322 } else if (sf > 0.5) {
1323 scale_clusters[step].input = scale_clusters[step - 1].input->scale(sf, "alignment");
1324 scale_ax_parameters(*local_ax_count, scale_clusters[step].ax_parameters, 0.5, sf);
1325 } else {
1326 scale_clusters[step].input = scale_clusters[step - 1].input->scale(0.5, "alignment");
1327 scale_ax_parameters(*local_ax_count, scale_clusters[step].ax_parameters, 0.5, 0.5);
1331 return scale_clusters;
1335 * Destroy the first element in the scale cluster data structure.
1337 static void final_clusters(struct scale_cluster *scale_clusters, ale_real scale_factor,
1338 unsigned int steps) {
1340 if (scale_clusters[0].input_scale < 1.0)
1341 delete scale_clusters[0].input;
1343 free((void *)scale_clusters[0].ax_parameters);
1345 for (unsigned int step = 1; step < steps; step++) {
1346 delete scale_clusters[step].accum;
1347 delete scale_clusters[step].defined;
1348 delete scale_clusters[step].aweight;
1350 if (scale_clusters[step].input_scale < 1.0)
1351 delete scale_clusters[step].input;
1353 free((void *)scale_clusters[step].ax_parameters);
1356 free(scale_clusters);
1360 * Calculate the centroid of a control point for the set of frames
1361 * having index lower than m. Divide by any scaling of the output.
1363 static point unscaled_centroid(unsigned int m, unsigned int p) {
1364 assert(_keep);
1366 point point_sum(0, 0);
1367 ale_accum divisor = 0;
1369 for(unsigned int j = 0; j < m; j++) {
1370 point pp = cp_array[p][j];
1372 if (pp.defined()) {
1373 point_sum += kept_t[j].transform_unscaled(pp)
1374 / kept_t[j].scale();
1375 divisor += 1;
1379 if (divisor == 0)
1380 return point::undefined();
1382 return point_sum / divisor;
1386 * Calculate centroid of this frame, and of all previous frames,
1387 * from points common to both sets.
1389 static void centroids(unsigned int m, point *current, point *previous) {
1391 * Calculate the translation
1393 point other_centroid(0, 0);
1394 point this_centroid(0, 0);
1395 ale_pos divisor = 0;
1397 for (unsigned int i = 0; i < cp_count; i++) {
1398 point other_c = unscaled_centroid(m, i);
1399 point this_c = cp_array[i][m];
1401 if (!other_c.defined() || !this_c.defined())
1402 continue;
1404 other_centroid += other_c;
1405 this_centroid += this_c;
1406 divisor += 1;
1410 if (divisor == 0) {
1411 *current = point::undefined();
1412 *previous = point::undefined();
1413 return;
1416 *current = this_centroid / divisor;
1417 *previous = other_centroid / divisor;
1421 * Calculate the RMS error of control points for frame m, with
1422 * transformation t, against control points for earlier frames.
1424 static ale_accum cp_rms_error(unsigned int m, transformation t) {
1425 assert (_keep);
1427 ale_accum err = 0;
1428 ale_accum divisor = 0;
1430 for (unsigned int i = 0; i < cp_count; i++)
1431 for (unsigned int j = 0; j < m; j++) {
1432 const point *p = cp_array[i];
1433 point p_ref = kept_t[j].transform_unscaled(p[j]);
1434 point p_cur = t.transform_unscaled(p[m]);
1436 if (!p_ref.defined() || !p_cur.defined())
1437 continue;
1439 err += p_ref.lengthtosq(p_cur);
1440 divisor += 1;
1443 return sqrt(err / divisor);
1447 * Align frame m against the reference.
1449 * XXX: the transformation class currently combines ordinary
1450 * transformations with scaling. This is somewhat convenient for
1451 * some things, but can also be confusing. This method, _align(), is
1452 * one case where special care must be taken to ensure that the scale
1453 * is always set correctly (by using the 'rescale' method).
1455 static ale_accum _align(int m, int local_gs, element_t *element) {
1457 const image *input_frame = element->input_frame;
1460 * Local upper/lower data, possibly dependent on image
1461 * dimensions.
1464 ale_pos local_lower, local_upper;
1467 * Select the minimum dimension as the reference.
1470 ale_pos reference_size = input_frame->height();
1471 if (input_frame->width() < reference_size)
1472 reference_size = input_frame->width();
1474 if (perturb_lower_percent)
1475 local_lower = perturb_lower
1476 * reference_size
1477 * 0.01
1478 * scale_factor;
1479 else
1480 local_lower = perturb_lower;
1482 if (perturb_upper_percent)
1483 local_upper = perturb_upper
1484 * reference_size
1485 * 0.01
1486 * scale_factor;
1487 else
1488 local_upper = perturb_upper;
1490 local_upper = pow(2, floor(log(local_upper) / log(2)));
1493 * Logarithms aren't exact, so we divide repeatedly to discover
1494 * how many steps will occur, and pass this information to the
1495 * user interface.
1498 int step_count = 0;
1499 double step_variable = local_upper;
1500 while (step_variable >= local_lower) {
1501 step_variable /= 2;
1502 step_count++;
1505 ui::get()->set_steps(step_count);
1507 ale_pos perturb = local_upper;
1508 transformation offset;
1509 ale_accum here;
1510 diff_stat_t *here_diff_stat = new diff_stat_t();
1511 int lod;
1513 if (_keep) {
1514 kept_t[latest] = latest_t;
1515 kept_ok[latest] = latest_ok;
1519 * Maximum level-of-detail. Use a level of detail at most
1520 * 2^lod_diff finer than the adjustment resolution. lod_diff
1521 * is a synonym for lod_max.
1524 const int lod_diff = lod_max;
1527 * Determine how many levels of detail should be prepared.
1530 unsigned int steps = (perturb > pow(2, lod_max))
1531 ? (unsigned int) (log(perturb) / log(2)) - lod_max + 1 : 1;
1535 * Prepare multiple levels of detail.
1538 int local_ax_count;
1539 struct scale_cluster *scale_clusters = init_clusters(m,
1540 scale_factor, input_frame, steps,
1541 &local_ax_count);
1544 * Initialize variables used in the main loop.
1547 lod = (steps - 1);
1550 * Initialize the default initial transform
1553 if (default_initial_alignment_type == 0) {
1556 * Follow the transformation of the original frame,
1557 * setting new image dimensions.
1560 // element->default_initial_alignment = orig_t;
1561 element->default_initial_alignment.set_current_element(orig_t.get_element(0));
1562 element->default_initial_alignment.set_dimensions(input_frame);
1564 } else if (default_initial_alignment_type == 1)
1567 * Follow previous transformation, setting new image
1568 * dimensions.
1571 element->default_initial_alignment.set_dimensions(input_frame);
1573 else
1574 assert(0);
1576 element->old_is_default = element->is_default;
1579 * Scale default initial transform for lod
1582 element->default_initial_alignment.rescale(1 / pow(2, lod));
1585 * Load any file-specified transformation
1588 offset = tload_next(tload, alignment_class == 2, element->default_initial_alignment,
1589 &element->is_default, element->is_primary);
1591 transformation new_offset = offset;
1593 if (!element->old_is_default && !element->is_default &&
1594 default_initial_alignment_type == 1) {
1597 * Implement new delta --follow semantics.
1599 * If we have a transformation T such that
1601 * prev_final == T(prev_init)
1603 * Then we also have
1605 * current_init_follow == T(current_init)
1607 * We can calculate T as follows:
1609 * T == prev_final(prev_init^-1)
1611 * Where ^-1 is the inverse operator.
1615 * Ensure that the lod for the old initial and final
1616 * alignments are equal to the lod for the new initial
1617 * alignment.
1620 element->old_final_alignment.rescale (1 / pow(2, lod));
1621 element->old_initial_alignment.rescale(1 / pow(2, lod - element->old_lod));
1623 if (alignment_class == 0) {
1625 * Translational transformations
1628 ale_pos t0 = -element->old_initial_alignment.eu_get(0)
1629 + element->old_final_alignment.eu_get(0);
1630 ale_pos t1 = -element->old_initial_alignment.eu_get(1)
1631 + element->old_final_alignment.eu_get(1);
1633 new_offset.eu_modify(0, t0);
1634 new_offset.eu_modify(1, t1);
1636 } else if (alignment_class == 1) {
1638 * Euclidean transformations
1641 ale_pos t2 = -element->old_initial_alignment.eu_get(2)
1642 + element->old_final_alignment.eu_get(2);
1644 new_offset.eu_modify(2, t2);
1646 point p( offset.scaled_height()/2 + offset.eu_get(0) - element->old_initial_alignment.eu_get(0),
1647 offset.scaled_width()/2 + offset.eu_get(1) - element->old_initial_alignment.eu_get(1) );
1649 p = element->old_final_alignment.transform_scaled(p);
1651 new_offset.eu_modify(0, p[0] - offset.scaled_height()/2 - offset.eu_get(0));
1652 new_offset.eu_modify(1, p[1] - offset.scaled_width()/2 - offset.eu_get(1));
1654 } else if (alignment_class == 2) {
1656 * Projective transformations
1659 point p[4];
1661 p[0] = element->old_final_alignment.transform_scaled(element->old_initial_alignment
1662 . scaled_inverse_transform(offset.transform_scaled(point( 0 , 0 ))));
1663 p[1] = element->old_final_alignment.transform_scaled(element->old_initial_alignment
1664 . scaled_inverse_transform(offset.transform_scaled(point(offset.scaled_height(), 0 ))));
1665 p[2] = element->old_final_alignment.transform_scaled(element->old_initial_alignment
1666 . scaled_inverse_transform(offset.transform_scaled(point(offset.scaled_height(), offset.scaled_width()))));
1667 p[3] = element->old_final_alignment.transform_scaled(element->old_initial_alignment
1668 . scaled_inverse_transform(offset.transform_scaled(point( 0 , offset.scaled_width()))));
1670 new_offset.gpt_set(p);
1674 element->old_initial_alignment = offset;
1675 element->old_lod = lod;
1676 offset = new_offset;
1678 struct scale_cluster si = scale_clusters[lod];
1679 ale_pos _mc_arg = (_mc > 0) ? (_mc * pow(2, 2 * lod))
1680 /* : ((double)_mcd_min / (si.accum->height() * si.accum->width())); */
1681 : 1;
1683 ui::get()->alignment_monte_carlo_parameter(_mc_arg);
1686 * Projective adjustment value
1689 ale_pos adj_p = (perturb >= pow(2, lod_diff))
1690 ? pow(2, lod_diff) : (double) perturb;
1693 * Pre-alignment exposure adjustment
1696 if (_exp_register) {
1697 ui::get()->exposure_1();
1698 transformation o = offset;
1699 for (int k = lod; k > 0; k--)
1700 o.rescale(2);
1701 set_exposure_ratio(m, scale_clusters[0], o, local_ax_count, 0);
1705 * Current difference (error) value
1708 ui::get()->prematching();
1709 here = diff(si, offset, _mc_arg, local_ax_count, m, here_diff_stat);
1710 ui::get()->set_match(here);
1713 * Current and modified barrel distortion parameters
1716 ale_pos current_bd[BARREL_DEGREE];
1717 ale_pos modified_bd[BARREL_DEGREE];
1718 offset.bd_get(current_bd);
1719 offset.bd_get(modified_bd);
1722 * Translational global search step
1725 if (perturb >= local_lower && local_gs != 0 && local_gs != 5) {
1727 ui::get()->aligning(perturb, lod);
1729 transformation lowest_t = offset;
1730 ale_accum lowest_v = here;
1732 point min, max;
1734 transformation offset_p = offset;
1736 if (!offset_p.is_projective())
1737 offset_p.eu_to_gpt();
1739 min = max = offset_p.gpt_get(0);
1740 for (int p_index = 1; p_index < 4; p_index++) {
1741 point p = offset_p.gpt_get(p_index);
1742 if (p[0] < min[0])
1743 min[0] = p[0];
1744 if (p[1] < min[1])
1745 min[1] = p[1];
1746 if (p[0] > max[0])
1747 max[0] = p[0];
1748 if (p[1] > max[1])
1749 max[1] = p[1];
1752 point inner_min_t = -min;
1753 point inner_max_t = -max + point(si.accum->height(), si.accum->width());
1754 point outer_min_t = -max + point(adj_p - 1, adj_p - 1);
1755 point outer_max_t = point(si.accum->height(), si.accum->width()) - point(adj_p, adj_p);
1757 if (local_gs == 1 || local_gs == 3 || local_gs == 4) {
1760 * Inner
1763 for (ale_pos i = inner_min_t[0]; i <= inner_max_t[0]; i += adj_p)
1764 for (ale_pos j = inner_min_t[1]; j <= inner_max_t[1]; j += adj_p) {
1765 transformation t = offset;
1766 t.translate(point(i, j));
1767 ale_accum v = diff(si, t, _mc_arg, local_ax_count, m);
1768 unsigned int ovl = overlap(si, t, local_ax_count);
1770 if ((v < lowest_v && ovl >= _gs_mo)
1771 || (!finite(lowest_v) && finite(v))) {
1772 lowest_v = v;
1773 lowest_t = t;
1778 if (local_gs == 2 || local_gs == 3 || local_gs == -1) {
1781 * Outer
1784 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
1785 for (ale_pos j = outer_min_t[1]; j < inner_min_t[1]; j += adj_p) {
1786 transformation t = offset;
1787 t.translate(point(i, j));
1788 ale_accum v = diff(si, t, _mc_arg, local_ax_count, m);
1789 unsigned int ovl = overlap(si, t, local_ax_count);
1791 if ((v < lowest_v && ovl >= _gs_mo)
1792 || (!finite(lowest_v) && finite(v))) {
1793 lowest_v = v;
1794 lowest_t = t;
1797 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
1798 for (ale_pos j = outer_max_t[1]; j > inner_max_t[1]; j -= adj_p) {
1799 transformation t = offset;
1800 t.translate(point(i, j));
1801 ale_accum v = diff(si, t, _mc_arg, local_ax_count, m);
1802 unsigned int ovl = overlap(si, t, local_ax_count);
1804 if ((v < lowest_v && ovl >= _gs_mo)
1805 || (!finite(lowest_v) && finite(v))) {
1806 lowest_v = v;
1807 lowest_t = t;
1810 for (ale_pos i = outer_min_t[0]; i < inner_min_t[0]; i += adj_p)
1811 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
1812 transformation t = offset;
1813 t.translate(point(i, j));
1814 ale_accum v = diff(si, t, _mc_arg, local_ax_count, m);
1815 unsigned int ovl = overlap(si, t, local_ax_count);
1817 if ((v < lowest_v && ovl >= _gs_mo)
1818 || (!finite(lowest_v) && finite(v))) {
1819 lowest_v = v;
1820 lowest_t = t;
1823 for (ale_pos i = outer_max_t[0]; i > inner_max_t[0]; i -= adj_p)
1824 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
1825 transformation t = offset;
1826 t.translate(point(i, j));
1827 ale_accum v = diff(si, t, _mc_arg, local_ax_count, m);
1828 unsigned int ovl = overlap(si, t, local_ax_count);
1830 if ((v < lowest_v && ovl >= _gs_mo)
1831 || (!finite(lowest_v) && finite(v))) {
1832 lowest_v = v;
1833 lowest_t = t;
1838 offset = lowest_t;
1839 here = lowest_v;
1841 ui::get()->set_match(here);
1845 * Control point alignment
1848 if (local_gs == 5) {
1850 transformation o = offset;
1851 for (int k = lod; k > 0; k--)
1852 o.rescale(2);
1855 * Determine centroid data
1858 point current, previous;
1859 centroids(m, &current, &previous);
1861 if (current.defined() && previous.defined()) {
1862 o = orig_t;
1863 o.set_dimensions(input_frame);
1864 o.translate((previous - current) * o.scale());
1865 current = previous;
1869 * Determine rotation for alignment classes other than translation.
1872 ale_accum lowest_error = cp_rms_error(m, o);
1874 ale_pos rot_lower = 2 * local_lower
1875 / sqrt(pow(scale_clusters[0].input->height(), 2)
1876 + pow(scale_clusters[0].input->width(), 2))
1877 * 180
1878 / M_PI;
1880 if (alignment_class > 0)
1881 for (ale_pos rot = 30; rot > rot_lower; rot /= 2)
1882 for (ale_pos srot = -rot; srot <= rot; srot += rot * 2) {
1883 int is_improved = 1;
1884 while (is_improved) {
1885 is_improved = 0;
1886 transformation test_t = o;
1887 test_t.rotate(current * o.scale(), srot);
1888 ale_pos test_v = cp_rms_error(m, test_t);
1890 if (test_v < lowest_error) {
1891 lowest_error = test_v;
1892 o = test_t;
1893 srot += 3 * rot;
1894 is_improved = 1;
1900 * Determine projective parameters through a local
1901 * minimum search.
1904 if (alignment_class == 2) {
1905 ale_accum adj_p = lowest_error;
1907 if (adj_p < local_lower)
1908 adj_p = local_lower;
1910 while (adj_p >= local_lower) {
1911 transformation test_t = o;
1912 int is_improved = 1;
1913 ale_accum test_v;
1914 ale_accum adj_s;
1916 while (is_improved) {
1917 is_improved = 0;
1919 for (int i = 0; i < 4; i++)
1920 for (int j = 0; j < 2; j++)
1921 for (adj_s = -adj_p; adj_s <= adj_p; adj_s += 2 * adj_p) {
1923 test_t = o;
1925 if (perturb_type == 0)
1926 test_t.gpt_modify(j, i, adj_s);
1927 else if (perturb_type == 1)
1928 test_t.gr_modify(j, i, adj_s);
1929 else
1930 assert(0);
1932 test_v = cp_rms_error(m, test_t);
1934 if (test_v < lowest_error) {
1935 lowest_error = test_v;
1936 o = test_t;
1937 adj_s += 3 * adj_p;
1938 is_improved = 1;
1942 adj_p /= 2;
1946 if (_exp_register)
1947 set_exposure_ratio(m, scale_clusters[0], o, local_ax_count, 0);
1949 for (int k = lod; k > 0; k--)
1950 o.rescale(0.5);
1952 offset = o;
1956 * Perturbation adjustment loop.
1959 ui::get()->aligning(perturb, lod);
1961 while (perturb >= local_lower) {
1963 ale_pos adj_s;
1966 * Orientational adjustment value in degrees.
1968 * Since rotational perturbation is now specified as an
1969 * arclength, we have to convert.
1972 ale_pos adj_o = 2 * perturb
1973 / sqrt(pow(scale_clusters[0].input->height(), 2)
1974 + pow(scale_clusters[0].input->width(), 2))
1975 * 180
1976 / M_PI;
1979 * Barrel distortion adjustment value
1982 ale_pos adj_b = perturb * bda_mult;
1984 transformation test_t;
1985 transformation old_offset = offset;
1986 ale_accum test_d;
1987 ale_accum old_here = here;
1988 diff_stat_t *old_here_diff_stat = here_diff_stat;
1989 here_diff_stat = new diff_stat_t();
1990 int found_better = 0;
1991 int found_reliable_better = 0;
1992 int found_reliable_worse = 0;
1993 int found_unreliable_worse = 0;
1995 if (alignment_class < 2 && alignment_class >= 0) {
1998 * Translational or euclidean transformation
2001 for (int i = 0; i < 2; i++)
2002 for (adj_s = -adj_p; adj_s <= adj_p; adj_s += 2 * adj_p) {
2004 test_t = offset;
2006 test_t.eu_modify(i, adj_s);
2008 test_d = diff(si, test_t, _mc_arg, local_ax_count, m, here_diff_stat);
2010 if (test_d < here || (!finite(here) && finite(test_d))) {
2011 found_better = 1;
2012 if (_mc > 0
2013 || _mc_arg >= 1
2014 || here_diff_stat->reliable(old_here_diff_stat, _mc_arg)) {
2015 found_reliable_better = 1;
2016 here = test_d;
2017 offset = test_t;
2018 goto done;
2022 if (_mc <= 0 && test_d > here) {
2023 if (_mc_arg >= 1
2024 || old_here_diff_stat->reliable(here_diff_stat, _mc_arg))
2025 found_reliable_worse = 1;
2026 else
2027 found_unreliable_worse = 1;
2031 if (alignment_class == 1 && adj_o < rot_max)
2032 for (adj_s = -adj_o; adj_s <= adj_o; adj_s += 2 * adj_o) {
2034 point sample_centroid = old_here_diff_stat->get_centroid() + si.accum->offset();
2035 test_t = offset;
2037 if (sample_centroid.defined()) {
2038 test_t.eu_rotate_about_scaled(sample_centroid, adj_s);
2039 } else {
2040 test_t.eu_modify(2, adj_s);
2043 test_d = diff(si, test_t, _mc_arg, local_ax_count, m, here_diff_stat);
2045 if (test_d < here || (!finite(here) && finite(test_d))) {
2046 found_better = 1;
2047 if (_mc > 0
2048 || _mc_arg >= 1
2049 || here_diff_stat->reliable(old_here_diff_stat, _mc_arg)) {
2050 found_reliable_better = 1;
2051 here = test_d;
2052 offset = test_t;
2053 goto done;
2057 if (_mc <= 0 && test_d > here) {
2058 if (_mc_arg >= 1
2059 || old_here_diff_stat->reliable(here_diff_stat, _mc_arg))
2060 found_reliable_worse = 1;
2061 else
2062 found_unreliable_worse = 1;
2066 } else if (alignment_class == 2) {
2069 * Projective transformation
2072 for (int i = 0; i < 4; i++)
2073 for (int j = 0; j < 2; j++)
2074 for (adj_s = -adj_p; adj_s <= adj_p; adj_s += 2 * adj_p) {
2076 test_t = offset;
2078 if (perturb_type == 0)
2079 test_t.gpt_modify(j, i, adj_s);
2080 else if (perturb_type == 1)
2081 test_t.gr_modify(j, i, adj_s);
2082 else
2083 assert(0);
2085 test_d = diff(si, test_t, _mc_arg, local_ax_count, m, here_diff_stat);
2087 #if 0
2088 fprintf(stderr, "old\n");
2089 old_here_diff_stat->print_hist();
2090 fprintf(stderr, "new\n");
2091 here_diff_stat->print_hist();
2092 #endif
2094 if (test_d < here || (!finite(here) && finite(test_d))) {
2095 // fprintf(stderr, "found better\n");
2096 found_better = 1;
2097 if (_mc > 0
2098 || _mc_arg >= 1
2099 || here_diff_stat->reliable(old_here_diff_stat, _mc_arg)) {
2100 // fprintf(stderr, "found reliable better\n");
2101 found_reliable_better = 1;
2102 here = test_d;
2103 offset = test_t;
2104 adj_s += 3 * adj_p;
2108 if (_mc <= 0 && test_d > here) {
2109 if (_mc_arg >= 1
2110 || old_here_diff_stat->reliable(here_diff_stat, _mc_arg))
2111 found_reliable_worse = 1;
2112 else
2113 found_unreliable_worse = 1;
2117 } else assert(0);
2120 * Barrel distortion
2123 if (bda_mult != 0) {
2125 static unsigned int d_rotation = 0;
2127 for (unsigned int d = 0; d < offset.bd_count(); d++)
2128 for (adj_s = -adj_b; adj_s <= adj_b; adj_s += 2 * adj_b) {
2130 unsigned int rd = (d + d_rotation) % offset.bd_count();
2131 d_rotation = (d_rotation + 1) % offset.bd_count();
2133 if (bda_rate > 0 && fabs(modified_bd[rd] + adj_s - current_bd[rd]) > bda_rate)
2134 continue;
2136 test_t = offset;
2138 test_t.bd_modify(rd, adj_s);
2140 test_d = diff(si, test_t, _mc_arg, local_ax_count, m, here_diff_stat);
2142 if (test_d < here || (!finite(here) && finite(test_d))) {
2143 found_better = 1;
2144 if (_mc > 0
2145 || _mc_arg >= 1
2146 || here_diff_stat->reliable(old_here_diff_stat, _mc_arg)) {
2147 found_reliable_better = 1;
2148 here = test_d;
2149 offset = test_t;
2150 modified_bd[rd] += adj_s;
2151 goto done;
2155 if (_mc <= 0 && test_d > here) {
2156 if (_mc_arg >= 1
2157 || old_here_diff_stat->reliable(here_diff_stat, _mc_arg))
2158 found_reliable_worse = 1;
2159 else
2160 found_unreliable_worse = 1;
2165 done:
2167 if (_mc_arg < 1 && _mc <= 0
2168 && (!found_reliable_worse || found_better)
2169 /* && found_unreliable_worse */
2170 && !found_reliable_better) {
2171 _mc_arg *= 2;
2172 ui::get()->alignment_monte_carlo_parameter(_mc_arg);
2173 continue;
2176 if (_mc <= 0
2177 && found_reliable_better) {
2178 diff_stat_t *here_diff_stat_half = new diff_stat_t();
2179 diff_stat_t *old_here_diff_stat_half = new diff_stat_t();
2181 diff(si, offset, _mc_arg / 2, local_ax_count, m, here_diff_stat_half);
2182 diff(si, old_offset, _mc_arg / 2, local_ax_count, m, old_here_diff_stat_half);
2184 if (here_diff_stat_half->reliable(old_here_diff_stat_half, _mc_arg / 2)) {
2185 _mc_arg /= 2;
2186 ui::get()->alignment_monte_carlo_parameter(_mc_arg);
2187 delete here_diff_stat;
2188 delete old_here_diff_stat;
2189 here_diff_stat = here_diff_stat_half;
2190 old_here_diff_stat = old_here_diff_stat_half;
2191 } else {
2192 delete here_diff_stat_half;
2193 delete old_here_diff_stat_half;
2197 if (!(here < old_here) && !(!finite(old_here) && finite(here))) {
2198 perturb *= 0.5;
2200 if (_mc <= 0)
2201 _mc_arg /= 2;
2203 if (lod > 0) {
2206 * We're about to work with images
2207 * twice as large, so rescale the
2208 * transforms.
2211 offset.rescale(2);
2212 element->default_initial_alignment.rescale(2);
2215 * Work with images twice as large
2218 lod--;
2219 si = scale_clusters[lod];
2221 if (_mc > 0)
2222 _mc_arg /= 4;
2224 here = diff(si, offset, _mc_arg, local_ax_count, m, here_diff_stat);
2225 delete old_here_diff_stat;
2227 } else {
2228 delete here_diff_stat;
2229 here_diff_stat = old_here_diff_stat;
2230 adj_p = perturb;
2234 * Announce changes
2237 ui::get()->alignment_monte_carlo_parameter(_mc_arg);
2238 ui::get()->alignment_perturbation_level(perturb, lod);
2240 } else {
2241 delete old_here_diff_stat;
2244 ui::get()->set_match(here);
2247 if (lod > 0) {
2248 offset.rescale(pow(2, lod));
2249 element->default_initial_alignment.rescale(pow(2, lod));
2253 * Post-alignment exposure adjustment
2256 if (_exp_register == 1) {
2257 ui::get()->exposure_2();
2258 set_exposure_ratio(m, scale_clusters[0], offset, local_ax_count, 1);
2262 * Recalculate error
2265 ui::get()->postmatching();
2266 diff_stat_t *new_diff_stat = new diff_stat_t();
2267 offset.use_full_support();
2268 here = diff(scale_clusters[0], offset, _mc_arg, local_ax_count, m, new_diff_stat);
2269 offset.use_restricted_support();
2270 delete new_diff_stat;
2271 ui::get()->set_match(here);
2274 * Free the level-of-detail structures
2277 final_clusters(scale_clusters, scale_factor, steps);
2280 * Ensure that the match meets the threshold.
2283 if ((1 - here) * 100 > match_threshold) {
2285 * Update alignment variables
2287 latest_ok = 1;
2288 element->default_initial_alignment = offset;
2289 element->old_final_alignment = offset;
2290 ui::get()->alignment_match_ok();
2291 } else if (local_gs == 4) {
2294 * Align with outer starting points.
2298 * XXX: This probably isn't exactly the right thing to do,
2299 * since variables like old_initial_value have been overwritten.
2302 ale_accum nested_result = _align(m, -1, element);
2304 if ((1 - nested_result) * 100 > match_threshold) {
2305 return nested_result;
2306 } else if (nested_result < here) {
2307 here = nested_result;
2308 offset = latest_t;
2311 if (is_fail_default)
2312 offset = element->default_initial_alignment;
2314 ui::get()->set_match(here);
2315 ui::get()->alignment_no_match();
2317 } else if (local_gs == -1) {
2319 latest_ok = 0;
2320 latest_t = offset;
2321 return here;
2323 } else {
2324 if (is_fail_default)
2325 offset = element->default_initial_alignment;
2326 latest_ok = 0;
2327 ui::get()->alignment_no_match();
2331 * Write the tonal registration multiplier as a comment.
2334 pixel trm = image_rw::exp(m).get_multiplier();
2335 tsave_trm(tsave, trm[0], trm[1], trm[2]);
2338 * Save the transformation information
2341 tsave_next(tsave, offset, alignment_class == 2, element->is_primary);
2343 latest_t = offset;
2346 * Update match statistics.
2349 match_sum += (1 - here) * 100;
2350 match_count++;
2351 latest = m;
2353 return here;
2356 #ifdef USE_FFTW
2358 * High-pass filter for frequency weights
2360 static void hipass(int rows, int cols, fftw_complex *inout) {
2361 for (int i = 0; i < rows * vert_freq_cut; i++)
2362 for (int j = 0; j < cols; j++)
2363 for (int k = 0; k < 2; k++)
2364 inout[i * cols + j][k] = 0;
2365 for (int i = 0; i < rows; i++)
2366 for (int j = 0; j < cols * horiz_freq_cut; j++)
2367 for (int k = 0; k < 2; k++)
2368 inout[i * cols + j][k] = 0;
2369 for (int i = 0; i < rows; i++)
2370 for (int j = 0; j < cols; j++)
2371 for (int k = 0; k < 2; k++)
2372 if (i / (double) rows + j / (double) cols < 2 * avg_freq_cut)
2373 inout[i * cols + j][k] = 0;
2375 #endif
2379 * Reset alignment weights
2381 static void reset_weights() {
2383 alignment_weights_const = NULL;
2385 if (alignment_weights != NULL)
2386 delete alignment_weights;
2388 alignment_weights = NULL;
2392 * Initialize alignment weights
2394 static void init_weights() {
2395 if (alignment_weights != NULL)
2396 return;
2398 int rows = reference_image->height();
2399 int cols = reference_image->width();
2400 int colors = reference_image->depth();
2402 alignment_weights = new image_ale_real(rows, cols,
2403 colors, "alignment_weights");
2405 assert (alignment_weights);
2407 for (int i = 0; i < rows; i++)
2408 for (int j = 0; j < cols; j++)
2409 alignment_weights->set_pixel(i, j, pixel(1, 1, 1));
2413 * Update alignment weights with weight map
2415 static void map_update() {
2417 if (weight_map == NULL)
2418 return;
2420 init_weights();
2422 point map_offset = reference_image->offset() - weight_map->offset();
2424 int rows = reference_image->height();
2425 int cols = reference_image->width();
2427 for (int i = 0; i < rows; i++)
2428 for (int j = 0; j < cols; j++) {
2429 point map_weight_position = map_offset + point(i, j);
2430 if (map_weight_position[0] >= 0
2431 && map_weight_position[1] >= 0
2432 && map_weight_position[0] <= weight_map->height() - 1
2433 && map_weight_position[1] <= weight_map->width() - 1)
2434 alignment_weights->pix(i, j) *= weight_map->get_bl(map_weight_position);
2439 * Update alignment weights with an internal weight map, reflecting a
2440 * summation of certainty values. Use existing memory structures if
2441 * possible. This function updates alignment_weights_const; hence, it
2442 * should not be called prior to any functions that modify the
2443 * alignment_weights structure.
2445 static void imap_update() {
2446 if (alignment_weights == NULL) {
2447 alignment_weights_const = reference_defined;
2448 } else {
2449 int rows = reference_image->height();
2450 int cols = reference_image->width();
2452 for (int i = 0; i < rows; i++)
2453 for (int j = 0; j < cols; j++)
2454 alignment_weights->pix(i, j) *= reference_defined->get_pixel(i, j);
2456 alignment_weights_const = alignment_weights;
2461 * Update alignment weights with algorithmic weights
2463 static void wmx_update() {
2464 #ifdef USE_UNIX
2466 static exposure *exp_def = new exposure_default();
2467 static exposure *exp_bool = new exposure_boolean();
2469 if (wmx_file == NULL || wmx_exec == NULL || wmx_defs == NULL)
2470 return;
2472 unsigned int rows = reference_image->height();
2473 unsigned int cols = reference_image->width();
2475 image_rw::write_image(wmx_file, reference_image);
2476 image_rw::write_image(wmx_defs, reference_defined, exp_bool);
2478 /* execute ... */
2479 int exit_status = 1;
2480 if (!fork()) {
2481 execlp(wmx_exec, wmx_exec, wmx_file, wmx_defs, NULL);
2482 ui::get()->exec_failure(wmx_exec, wmx_file, wmx_defs);
2485 wait(&exit_status);
2487 if (exit_status)
2488 ui::get()->fork_failure("d2::align");
2490 image *wmx_weights = image_rw::read_image(wmx_file, exp_def);
2492 if (wmx_weights->height() != rows || wmx_weights->width() != cols)
2493 ui::get()->error("algorithmic weighting must not change image size");
2495 if (alignment_weights == NULL)
2496 alignment_weights = wmx_weights;
2497 else
2498 for (unsigned int i = 0; i < rows; i++)
2499 for (unsigned int j = 0; j < cols; j++)
2500 alignment_weights->pix(i, j) *= wmx_weights->pix(i, j);
2501 #endif
2505 * Update alignment weights with frequency weights
2507 static void fw_update() {
2508 #ifdef USE_FFTW
2509 if (horiz_freq_cut == 0
2510 && vert_freq_cut == 0
2511 && avg_freq_cut == 0)
2512 return;
2515 * Required for correct operation of --fwshow
2518 assert (alignment_weights == NULL);
2520 int rows = reference_image->height();
2521 int cols = reference_image->width();
2522 int colors = reference_image->depth();
2524 alignment_weights = new image_ale_real(rows, cols,
2525 colors, "alignment_weights");
2527 fftw_complex *inout = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * rows * cols);
2529 assert (inout);
2531 fftw_plan pf = fftw_plan_dft_2d(rows, cols,
2532 inout, inout,
2533 FFTW_FORWARD, FFTW_ESTIMATE);
2535 fftw_plan pb = fftw_plan_dft_2d(rows, cols,
2536 inout, inout,
2537 FFTW_BACKWARD, FFTW_ESTIMATE);
2539 for (int k = 0; k < colors; k++) {
2540 for (int i = 0; i < rows * cols; i++) {
2541 inout[i][0] = reference_image->get_pixel(i / cols, i % cols)[k];
2542 inout[i][1] = 0;
2545 fftw_execute(pf);
2546 hipass(rows, cols, inout);
2547 fftw_execute(pb);
2549 for (int i = 0; i < rows * cols; i++) {
2550 #if 0
2551 alignment_weights->pix(i / cols, i % cols)[k] = fabs(inout[i][0] / (rows * cols));
2552 #else
2553 alignment_weights->pix(i / cols, i % cols)[k] =
2554 sqrt(pow(inout[i][0] / (rows * cols), 2)
2555 + pow(inout[i][1] / (rows * cols), 2));
2556 #endif
2560 fftw_destroy_plan(pf);
2561 fftw_destroy_plan(pb);
2562 fftw_free(inout);
2564 if (fw_output != NULL)
2565 image_rw::write_image(fw_output, alignment_weights);
2566 #endif
2570 * Update alignment to frame N.
2572 static void update_to(int n) {
2574 assert (n <= latest + 1);
2575 assert (n >= 0);
2577 static std::vector<element_t> elements;
2579 if (latest < 0) {
2581 elements.resize(1);
2584 * Handle the initial frame
2587 ui::get()->loading_file();
2588 elements[0].input_frame = image_rw::open(n);
2590 const image *i = elements[0].input_frame;
2591 int is_default;
2592 transformation result = alignment_class == 2
2593 ? transformation::gpt_identity(i, scale_factor)
2594 : transformation::eu_identity(i, scale_factor);
2595 result = tload_first(tload, alignment_class == 2, result, &is_default);
2596 tsave_first(tsave, result, alignment_class == 2);
2598 if (_keep > 0) {
2599 kept_t = new transformation[image_rw::count()];
2600 kept_ok = (int *) malloc(image_rw::count()
2601 * sizeof(int));
2602 assert (kept_t);
2603 assert (kept_ok);
2605 if (!kept_t || !kept_ok)
2606 ui::get()->memory_error("alignment");
2608 kept_ok[0] = 1;
2609 kept_t[0] = result;
2612 latest = 0;
2613 latest_ok = 1;
2614 latest_t = result;
2616 elements[0].default_initial_alignment = result;
2617 orig_t = result;
2619 image_rw::close(n);
2622 for (int i = latest + 1; i <= n; i++)
2623 for (unsigned int j = 0; j < _ma_card; j++) {
2625 if (j >= elements.size()) {
2626 elements.resize(j + 1);
2627 elements[j] = elements[0];
2628 elements[j].default_initial_alignment =
2629 elements[j - 1].default_initial_alignment;
2630 elements[j].default_initial_alignment.push_element();
2634 * Handle supplemental frames.
2637 assert (reference != NULL);
2639 ui::get()->set_arender_current();
2640 reference->sync(i - 1);
2641 ui::get()->clear_arender_current();
2642 reference_image = reference->get_image();
2643 reference_defined = reference->get_defined();
2645 reset_weights();
2646 fw_update();
2647 wmx_update();
2648 map_update();
2650 if (certainty_weights)
2651 imap_update(); /* Must be called after all other _updates */
2653 assert (reference_image != NULL);
2654 assert (reference_defined != NULL);
2656 ui::get()->loading_file();
2657 elements[j].input_frame = image_rw::open(i);
2658 elements[j].is_primary = (j == 0);
2660 _align(i, _gs, &elements[j]);
2662 image_rw::close(n);
2665 if (elements.size() > _ma_card)
2666 elements.resize(_ma_card);
2669 public:
2672 * Set the control point count
2674 static void set_cp_count(unsigned int n) {
2675 assert (cp_array == NULL);
2677 cp_count = n;
2678 cp_array = (const point **) malloc(n * sizeof(const point *));
2682 * Set control points.
2684 static void set_cp(unsigned int i, const point *p) {
2685 cp_array[i] = p;
2689 * Register exposure
2691 static void exp_register() {
2692 _exp_register = 1;
2696 * Register exposure only based on metadata
2698 static void exp_meta_only() {
2699 _exp_register = 2;
2703 * Don't register exposure
2705 static void exp_noregister() {
2706 _exp_register = 0;
2710 * Set alignment class to translation only. Only adjust the x and y
2711 * position of images. Do not rotate input images or perform
2712 * projective transformations.
2714 static void class_translation() {
2715 alignment_class = 0;
2719 * Set alignment class to Euclidean transformations only. Adjust the x
2720 * and y position of images and the orientation of the image about the
2721 * image center.
2723 static void class_euclidean() {
2724 alignment_class = 1;
2728 * Set alignment class to perform general projective transformations.
2729 * See the file gpt.h for more information about general projective
2730 * transformations.
2732 static void class_projective() {
2733 alignment_class = 2;
2737 * Set the default initial alignment to the identity transformation.
2739 static void initial_default_identity() {
2740 default_initial_alignment_type = 0;
2744 * Set the default initial alignment to the most recently matched
2745 * frame's final transformation.
2747 static void initial_default_follow() {
2748 default_initial_alignment_type = 1;
2752 * Perturb output coordinates.
2754 static void perturb_output() {
2755 perturb_type = 0;
2759 * Perturb source coordinates.
2761 static void perturb_source() {
2762 perturb_type = 1;
2766 * Frames under threshold align optimally
2768 static void fail_optimal() {
2769 is_fail_default = 0;
2773 * Frames under threshold keep their default alignments.
2775 static void fail_default() {
2776 is_fail_default = 1;
2780 * Align images with an error contribution from each color channel.
2782 static void all() {
2783 channel_alignment_type = 0;
2787 * Align images with an error contribution only from the green channel.
2788 * Other color channels do not affect alignment.
2790 static void green() {
2791 channel_alignment_type = 1;
2795 * Align images using a summation of channels. May be useful when
2796 * dealing with images that have high frequency color ripples due to
2797 * color aliasing.
2799 static void sum() {
2800 channel_alignment_type = 2;
2804 * Error metric exponent
2807 static void set_metric_exponent(float me) {
2808 metric_exponent = me;
2812 * Match threshold
2815 static void set_match_threshold(float mt) {
2816 match_threshold = mt;
2820 * Perturbation lower and upper bounds.
2823 static void set_perturb_lower(ale_pos pl, int plp) {
2824 perturb_lower = pl;
2825 perturb_lower_percent = plp;
2828 static void set_perturb_upper(ale_pos pu, int pup) {
2829 perturb_upper = pu;
2830 perturb_upper_percent = pup;
2834 * Maximum rotational perturbation.
2837 static void set_rot_max(int rm) {
2840 * Obtain the largest power of two not larger than rm.
2843 rot_max = pow(2, floor(log(rm) / log(2)));
2847 * Barrel distortion adjustment multiplier
2850 static void set_bda_mult(ale_pos m) {
2851 bda_mult = m;
2855 * Barrel distortion maximum rate of change
2858 static void set_bda_rate(ale_pos m) {
2859 bda_rate = m;
2863 * Level-of-detail
2866 static void set_lod_max(int lm) {
2867 lod_max = lm;
2871 * Set the scale factor
2873 static void set_scale(ale_pos s) {
2874 scale_factor = s;
2878 * Set reference rendering to align against
2880 static void set_reference(render *r) {
2881 reference = r;
2885 * Set the interpolant
2887 static void set_interpolant(filter::scaled_filter *f) {
2888 interpolant = f;
2892 * Set alignment weights image
2894 static void set_weight_map(const image *i) {
2895 weight_map = i;
2899 * Set frequency cuts
2901 static void set_frequency_cut(double h, double v, double a) {
2902 horiz_freq_cut = h;
2903 vert_freq_cut = v;
2904 avg_freq_cut = a;
2908 * Set algorithmic alignment weighting
2910 static void set_wmx(const char *e, const char *f, const char *d) {
2911 wmx_exec = e;
2912 wmx_file = f;
2913 wmx_defs = d;
2917 * Show frequency weights
2919 static void set_fl_show(const char *filename) {
2920 fw_output = filename;
2924 * Set transformation file loader.
2926 static void set_tload(tload_t *tl) {
2927 tload = tl;
2931 * Set transformation file saver.
2933 static void set_tsave(tsave_t *ts) {
2934 tsave = ts;
2938 * Get match statistics for frame N.
2940 static int match(int n) {
2941 update_to(n);
2943 if (n == latest)
2944 return latest_ok;
2945 else if (_keep)
2946 return kept_ok[n];
2947 else {
2948 assert(0);
2949 exit(1);
2954 * Message that old alignment data should be kept.
2956 static void keep() {
2957 assert (latest == -1);
2958 _keep = 1;
2962 * Get alignment for frame N.
2964 static transformation of(int n) {
2965 update_to(n);
2966 if (n == latest)
2967 return latest_t;
2968 else if (_keep)
2969 return kept_t[n];
2970 else {
2971 assert(0);
2972 exit(1);
2977 * Use Monte Carlo alignment sampling with argument N.
2979 static void mc(ale_pos n) {
2980 _mc = n;
2983 static void mcd_limit(int n) {
2984 _mcd_limit = n;
2988 * Set the certainty-weighted flag.
2990 static void certainty_weighted(int flag) {
2991 certainty_weights = flag;
2995 * Set the global search type.
2997 static void gs(const char *type) {
2998 if (!strcmp(type, "local")) {
2999 _gs = 0;
3000 } else if (!strcmp(type, "inner")) {
3001 _gs = 1;
3002 } else if (!strcmp(type, "outer")) {
3003 _gs = 2;
3004 } else if (!strcmp(type, "all")) {
3005 _gs = 3;
3006 } else if (!strcmp(type, "central")) {
3007 _gs = 4;
3008 } else if (!strcmp(type, "points")) {
3009 _gs = 5;
3010 keep();
3011 } else {
3012 ui::get()->error("bad global search type");
3017 * Multi-alignment contiguity
3019 static void ma_cont(double value) {
3020 _ma_cont = value;
3024 * Multi-alignment cardinality
3026 static void ma_card(unsigned int value) {
3027 assert (value >= 1);
3028 _ma_card = value;
3032 * Set the minimum overlap for global searching
3034 static void gs_mo(unsigned int value) {
3035 _gs_mo = value;
3039 * Don't use Monte Carlo alignment sampling.
3041 static void no_mc() {
3042 _mc = 0;
3046 * Set alignment exclusion regions
3048 static void set_exclusion(exclusion *_ax_parameters, int _ax_count) {
3049 ax_count = _ax_count;
3050 ax_parameters = _ax_parameters;
3054 * Get match summary statistics.
3056 static ale_accum match_summary() {
3057 return match_sum / match_count;
3061 #endif