d2::align: Fix active channel determination in scale cluster initialization.
[Ale.git] / d2 / align.h
blob2553b7cb60b60e506205656955e9655af24e5923
1 // Copyright 2002, 2004, 2007 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 3 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 #define D2_ALIGN_IMPRECISE_COVERAGE 0.3
38 class align {
39 private:
42 * Private data members
45 static ale_pos scale_factor;
48 * Original frame transformation
50 static transformation orig_t;
53 * Keep data older than latest
55 static int _keep;
56 static transformation *kept_t;
57 static int *kept_ok;
60 * Transformation file handlers
63 static tload_t *tload;
64 static tsave_t *tsave;
67 * Control point variables
70 static const point **cp_array;
71 static unsigned int cp_count;
74 * Reference rendering to align against
77 static render *reference;
78 static filter::scaled_filter *interpolant;
79 static const image *reference_image;
80 static const image *reference_defined;
83 * Per-pixel alignment weight map
86 static const image *weight_map;
89 * Frequency-dependent alignment weights
92 static double horiz_freq_cut;
93 static double vert_freq_cut;
94 static double avg_freq_cut;
95 static const char *fw_output;
98 * Algorithmic alignment weighting
101 static const char *wmx_exec;
102 static const char *wmx_file;
103 static const char *wmx_defs;
106 * Non-certainty alignment weights
109 static image *alignment_weights;
112 * Latest transformation.
115 static transformation latest_t;
118 * Flag indicating whether the latest transformation
119 * resulted in a match.
122 static int latest_ok;
125 * Frame number most recently aligned.
128 static int latest;
131 * Exposure registration
133 * 0. Preserve the original exposure of images.
135 * 1. Match exposure between images.
137 * 2. Use only image metadata for registering exposure.
140 static int _exp_register;
143 * Alignment class.
145 * 0. Translation only. Only adjust the x and y position of images.
146 * Do not rotate input images or perform projective transformations.
148 * 1. Euclidean transformations only. Adjust the x and y position
149 * of images and the orientation of the image about the image center.
151 * 2. Perform general projective transformations. See the file gpt.h
152 * for more information about general projective transformations.
155 static int alignment_class;
158 * Default initial alignment type.
160 * 0. Identity transformation.
162 * 1. Most recently accepted frame's final transformation.
165 static int default_initial_alignment_type;
168 * Projective group behavior
170 * 0. Perturb in output coordinates.
172 * 1. Perturb in source coordinates
175 static int perturb_type;
178 * Alignment element
180 * This structure contains variables necessary for handling a
181 * multi-alignment element. The change between the non-default old
182 * initial alignment and old final alignment is used to adjust the
183 * non-default current initial alignment. If either the old or new
184 * initial alignment is a default alignment, the old --follow semantics
185 * are preserved.
188 struct element_t {
189 int is_default, old_is_default;
190 int is_primary;
191 int old_lod;
192 transformation old_initial_alignment;
193 transformation old_final_alignment;
194 transformation default_initial_alignment;
195 const image *input_frame;
197 public:
198 element_t() {
199 is_default = 1;
200 input_frame = NULL;
205 * Alignment for failed frames -- default or optimal?
207 * A frame that does not meet the match threshold can be assigned the
208 * best alignment found, or can be assigned its alignment default.
211 static int is_fail_default;
214 * Alignment code.
216 * 0. Align images with an error contribution from each color channel.
218 * 1. Align images with an error contribution only from the green channel.
219 * Other color channels do not affect alignment.
221 * 2. Align images using a summation of channels. May be useful when dealing
222 * with images that have high frequency color ripples due to color aliasing.
225 static int channel_alignment_type;
228 * Error metric exponent
231 static float metric_exponent;
234 * Match threshold
237 static float match_threshold;
240 * Perturbation lower and upper bounds.
243 static ale_pos perturb_lower;
244 static int perturb_lower_percent;
245 static ale_pos perturb_upper;
246 static int perturb_upper_percent;
249 * Maximum level-of-detail scale factor is 2^lod_max/perturb.
252 static int lod_max;
255 * Maximum rotational perturbation
258 static ale_pos rot_max;
261 * Barrel distortion alignment multiplier
264 static ale_pos bda_mult;
267 * Barrel distortion maximum adjustment rate
270 static ale_pos bda_rate;
273 * Alignment match sum
276 static ale_accum match_sum;
279 * Alignment match count.
282 static int match_count;
285 * Exposure registration and final match precision flag
287 * 0. Do not require precise calculation.
289 * 1. Require precise exposure registration and final match.
292 static int precise_calculation;
295 * Certainty weight flag
297 * 0. Don't use certainty weights for alignment.
299 * 1. Use certainty weights for alignment.
302 static int certainty_weights;
305 * Global search parameter
307 * 0. Local: Local search only.
308 * 1. Inner: Alignment reference image inner region
309 * 2. Outer: Alignment reference image outer region
310 * 3. All: Alignment reference image inner and outer regions.
311 * 4. Central: Inner if possible; else, best of inner and outer.
312 * 5. Points: Align by control points.
315 static int _gs;
318 * Multi-alignment cardinality.
321 static unsigned int _ma_card;
324 * Multi-alignment contiguity.
327 static double _ma_cont;
330 * Minimum overlap for global searches
333 static ale_pos _gs_mo;
334 static int gs_mo_percent;
337 * Exclusion regions
340 static exclusion *ax_parameters;
341 static int ax_count;
344 * Types for scale clusters.
347 struct nl_scale_cluster {
348 const image *accum_max;
349 const image *accum_min;
350 const image *certainty_max;
351 const image *certainty_min;
352 const image *aweight_max;
353 const image *aweight_min;
354 exclusion *ax_parameters;
356 ale_pos input_scale;
357 const image *input_certainty_max;
358 const image *input_certainty_min;
359 const image *input_max;
360 const image *input_min;
363 struct scale_cluster {
364 const image *accum;
365 const image *certainty;
366 const image *aweight;
367 exclusion *ax_parameters;
369 ale_pos input_scale;
370 const image *input_certainty;
371 const image *input;
373 nl_scale_cluster *nl_scale_clusters;
377 * Check for exclusion region coverage in the reference
378 * array.
380 static int ref_excluded(int i, int j, point offset, exclusion *params, int param_count) {
381 for (int idx = 0; idx < param_count; idx++)
382 if (params[idx].type == exclusion::RENDER
383 && i + offset[0] >= params[idx].x[0]
384 && i + offset[0] <= params[idx].x[1]
385 && j + offset[1] >= params[idx].x[2]
386 && j + offset[1] <= params[idx].x[3])
387 return 1;
389 return 0;
393 * Check for exclusion region coverage in the input
394 * array.
396 static int input_excluded(ale_pos ti, ale_pos tj, exclusion *params, int param_count) {
397 for (int idx = 0; idx < param_count; idx++)
398 if (params[idx].type == exclusion::FRAME
399 && ti >= params[idx].x[0]
400 && ti <= params[idx].x[1]
401 && tj >= params[idx].x[2]
402 && tj <= params[idx].x[3])
403 return 1;
405 return 0;
409 * Overlap function. Determines the number of pixels in areas where
410 * the arrays overlap. Uses the reference array's notion of pixel
411 * positions.
413 static unsigned int overlap(struct scale_cluster c, transformation t, int ax_count) {
414 assert (reference_image);
416 unsigned int result = 0;
418 point offset = c.accum->offset();
420 for (unsigned int i = 0; i < c.accum->height(); i++)
421 for (unsigned int j = 0; j < c.accum->width(); j++) {
423 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
424 continue;
427 * Transform
430 struct point q;
432 q = (c.input_scale < 1.0 && interpolant == NULL)
433 ? t.scaled_inverse_transform(
434 point(i + offset[0], j + offset[1]))
435 : t.unscaled_inverse_transform(
436 point(i + offset[0], j + offset[1]));
438 ale_pos ti = q[0];
439 ale_pos tj = q[1];
442 * Check that the transformed coordinates are within
443 * the boundaries of array c.input, and check that the
444 * weight value in the accumulated array is nonzero,
445 * unless we know it is nonzero by virtue of the fact
446 * that it falls within the region of the original
447 * frame (e.g. when we're not increasing image
448 * extents). Also check for frame exclusion.
451 if (input_excluded(ti, tj, c.ax_parameters, ax_count))
452 continue;
454 if (ti >= 0
455 && ti <= c.input->height() - 1
456 && tj >= 0
457 && tj <= c.input->width() - 1
458 && c.certainty->get_pixel(i, j)[0] != 0)
459 result++;
462 return result;
466 * Calculate the region associated with the current multi-alignment
467 * element.
469 static void calculate_element_region(transformation *t, scale_cluster si,
470 int local_ax_count) {
472 unsigned int i_max = si.accum->height();
473 unsigned int j_max = si.accum->width();
474 point offset = si.accum->offset();
476 if (si.input_scale < 1.0 && interpolant == NULL)
477 t->begin_calculate_scaled_region(i_max, j_max, offset);
478 else
479 t->begin_calculate_unscaled_region(i_max, j_max, offset);
481 for (unsigned int i = 0; i < i_max; i++)
482 for (unsigned int j = 0; j < j_max; j++) {
484 if (ref_excluded(i, j, offset, si.ax_parameters, local_ax_count))
485 continue;
487 point q;
489 while ((q = t->get_query_point((int) (i + offset[0]),
490 (int) (j + offset[1]))).defined()) {
492 ale_pos ti = q[0];
493 ale_pos tj = q[1];
495 if (input_excluded(ti, tj, si.ax_parameters, ax_count))
496 continue;
498 if (ti >= 0
499 && ti <= si.input->height() - 1
500 && tj >= 0
501 && tj <= si.input->width() - 1
502 && si.certainty->get_pixel(i, j)[0] != 0) {
504 assert(0);
509 t->end_calculate_region();
513 * Monte carlo iteration class.
515 * Monte Carlo alignment has been used for statistical comparisons in
516 * spatial registration, and is now used for tonal registration
517 * and final match calculation.
521 * We use a random process for which the expected number of sampled
522 * pixels is +/- .000003 from the coverage in the range [.005,.995] for
523 * an image with 100,000 pixels. (The actual number may still deviate
524 * from the expected number by more than this amount, however.) The
525 * method is as follows:
527 * We have coverage == USE/ALL, or (expected # pixels to use)/(# total
528 * pixels). We derive from this SKIP/USE.
530 * SKIP/USE == (SKIP/ALL)/(USE/ALL) == (1 - (USE/ALL))/(USE/ALL)
532 * Once we have SKIP/USE, we know the expected number of pixels to skip
533 * in each iteration. We use a random selection process that provides
534 * SKIP/USE close to this calculated value.
536 * If we can draw uniformly to select the number of pixels to skip, we
537 * do. In this case, the maximum number of pixels to skip is twice the
538 * expected number.
540 * If we cannot draw uniformly, we still assign equal probability to
541 * each of the integer values in the interval [0, 2 * (SKIP/USE)], but
542 * assign an unequal amount to the integer value ceil(2 * SKIP/USE) +
543 * 1.
547 * When reseeding the random number generator, we want the same set of
548 * pixels to be used in cases where two alignment options are compared.
549 * If we wanted to avoid bias from repeatedly utilizing the same seed,
550 * we could seed with the number of the frame most recently aligned:
552 * srand(latest);
554 * However, in cursory tests, it seems okay to just use the default
555 * seed of 1, and so we do this, since it is simpler; both of these
556 * approaches to reseeding achieve better results than not reseeding.
557 * (1 is the default seed according to the GNU Manual Page for
558 * rand(3).)
560 * For subdomain calculations, we vary the seed by adding the subdomain
561 * index.
564 class mc_iterate {
565 ale_pos mc_max;
566 unsigned int index;
567 unsigned int index_max;
568 int i_min;
569 int i_max;
570 int j_min;
571 int j_max;
573 rng_t rng;
575 public:
576 mc_iterate(int _i_min, int _i_max, int _j_min, int _j_max, unsigned int subdomain)
577 : rng() {
579 ale_pos coverage;
581 i_min = _i_min;
582 i_max = _i_max;
583 j_min = _j_min;
584 j_max = _j_max;
586 index_max = (i_max - i_min) * (j_max - j_min);
588 if (index_max < 500 || precise_calculation)
589 coverage = 1;
590 else
591 coverage = D2_ALIGN_IMPRECISE_COVERAGE;
593 ale_pos su = (1 - coverage) / coverage;
595 mc_max = (floor(2*su) * (1 + floor(2*su)) + 2*su)
596 / (2 + 2 * floor(2*su) - 2*su);
598 rng.seed(1 + subdomain);
600 index = -1 + (int) ceil((mc_max+1)
601 * ( (1 + ((ale_pos) (rng.get())) )
602 / (1 + ((ale_pos) RAND_MAX)) ));
605 int get_i() {
606 return index / (j_max - j_min) + i_min;
609 int get_j() {
610 return index % (j_max - j_min) + j_min;
613 void operator++(int whats_this_for) {
614 index += (int) ceil((mc_max+1)
615 * ( (1 + ((ale_pos) (rng.get())) )
616 / (1 + ((ale_pos) RAND_MAX)) ));
619 int done() {
620 return (index >= index_max);
625 * Not-quite-symmetric difference function. Determines the difference in areas
626 * where the arrays overlap. Uses the reference array's notion of pixel positions.
628 * For the purposes of determining the difference, this function divides each
629 * pixel value by the corresponding image's average pixel magnitude, unless we
630 * are:
632 * a) Extending the boundaries of the image, or
634 * b) following the previous frame's transform
636 * If we are doing monte-carlo pixel sampling for alignment, we
637 * typically sample a subset of available pixels; otherwise, we sample
638 * all pixels.
642 class diff_stat_t {
644 struct run {
646 transformation offset;
647 ale_pos perturb;
649 ale_accum result;
650 ale_accum divisor;
652 point max, min;
653 ale_accum centroid[2], centroid_divisor;
654 ale_accum de_centroid[2], de_centroid_v, de_sum;
656 void init() {
658 result = 0;
659 divisor = 0;
661 min = point::posinf();
662 max = point::neginf();
664 centroid[0] = 0;
665 centroid[1] = 0;
666 centroid_divisor = 0;
668 de_centroid[0] = 0;
669 de_centroid[1] = 0;
671 de_centroid_v = 0;
673 de_sum = 0;
676 void init(transformation _offset, ale_pos _perturb) {
677 offset = _offset;
678 perturb = _perturb;
679 init();
683 * Required for STL sanity.
685 run() : offset() {
686 init();
689 run(transformation _offset, ale_pos _perturb) : offset() {
690 init(_offset, _perturb);
693 void add(const run &_run) {
694 result += _run.result;
695 divisor += _run.divisor;
697 for (int d = 0; d < 2; d++) {
698 if (min[d] > _run.min[d])
699 min[d] = _run.min[d];
700 if (max[d] < _run.max[d])
701 max[d] = _run.max[d];
702 centroid[d] += _run.centroid[d];
703 de_centroid[d] += _run.de_centroid[d];
706 centroid_divisor += _run.centroid_divisor;
707 de_centroid_v += _run.de_centroid_v;
708 de_sum += _run.de_sum;
711 run(const run &_run) : offset() {
714 * Initialize
716 init(_run.offset, _run.perturb);
719 * Add
721 add(_run);
724 run &operator=(const run &_run) {
727 * Initialize
729 init(_run.offset, _run.perturb);
732 * Add
734 add(_run);
736 return *this;
739 ~run() {
742 ale_accum get_error() const {
743 return pow(result / divisor, 1/metric_exponent);
746 void sample(int f, scale_cluster c, int i, int j, point t, point u,
747 const run &comparison) {
749 pixel pa = c.accum->get_pixel(i, j);
751 ale_accum this_result[2] = { 0, 0 };
752 ale_accum this_divisor[2] = { 0, 0 };
754 pixel p[2];
755 pixel weight[2];
756 weight[0] = pixel(1, 1, 1);
757 weight[1] = pixel(1, 1, 1);
759 if (interpolant != NULL) {
760 interpolant->filtered(i, j, &p[0], &weight[1], 1, f);
761 } else {
762 p[0] = c.input->get_bl(t);
765 if (u.defined()) {
766 p[1] = c.input->get_bl(u);
771 * Handle certainty.
774 if (certainty_weights == 1) {
777 * For speed, use arithmetic interpolation (get_bl(.))
778 * instead of geometric (get_bl(., 1))
781 weight[0] *= c.input_certainty->get_bl(t);
782 if (u.defined())
783 weight[1] *= c.input_certainty->get_bl(u);
784 weight[0] *= c.certainty->get_pixel(i, j);
785 weight[1] *= c.certainty->get_pixel(i, j);
788 if (c.aweight != NULL) {
789 weight[0] *= c.aweight->get_pixel(i, j);
790 weight[1] *= c.aweight->get_pixel(i, j);
794 * Update sampling area statistics
797 if (min[0] > i)
798 min[0] = i;
799 if (min[1] > j)
800 min[1] = j;
801 if (max[0] < i)
802 max[0] = i;
803 if (max[1] < j)
804 max[1] = j;
806 centroid[0] += (weight[0][0] + weight[0][1] + weight[0][2]) * i;
807 centroid[1] += (weight[0][0] + weight[0][1] + weight[0][2]) * j;
808 centroid_divisor += (weight[0][0] + weight[0][1] + weight[0][2]);
811 * Determine alignment type.
814 for (int m = 0; m < (u.defined() ? 2 : 1); m++)
815 if (channel_alignment_type == 0) {
817 * Align based on all channels.
821 for (int k = 0; k < 3; k++) {
822 ale_real achan = pa[k];
823 ale_real bchan = p[m][k];
825 this_result[m] += weight[m][k] * pow(fabs(achan - bchan), metric_exponent);
826 this_divisor[m] += weight[m][k] * pow(achan > bchan ? achan : bchan, metric_exponent);
828 } else if (channel_alignment_type == 1) {
830 * Align based on the green channel.
833 ale_real achan = pa[1];
834 ale_real bchan = p[m][1];
836 this_result[m] = weight[m][1] * pow(fabs(achan - bchan), metric_exponent);
837 this_divisor[m] = weight[m][1] * pow(achan > bchan ? achan : bchan, metric_exponent);
838 } else if (channel_alignment_type == 2) {
840 * Align based on the sum of all channels.
843 ale_real asum = 0;
844 ale_real bsum = 0;
845 ale_real wsum = 0;
847 for (int k = 0; k < 3; k++) {
848 asum += pa[k];
849 bsum += p[m][k];
850 wsum += weight[m][k] / 3;
853 this_result[m] = wsum * pow(fabs(asum - bsum), metric_exponent);
854 this_divisor[m] = wsum * pow(asum > bsum ? asum : bsum, metric_exponent);
857 if (u.defined()) {
858 // ale_accum de = fabs(this_result[0] / this_divisor[0]
859 // - this_result[1] / this_divisor[1]);
860 ale_accum de = fabs(this_result[0] - this_result[1]);
862 de_centroid[0] += de * i;
863 de_centroid[1] += de * j;
865 de_centroid_v += de * t.lengthto(u);
867 de_sum += de;
870 result += (this_result[0]);
871 divisor += (this_divisor[0]);
874 void rescale(ale_pos scale) {
875 offset.rescale(scale);
877 de_centroid[0] *= scale;
878 de_centroid[1] *= scale;
879 de_centroid_v *= scale;
882 point get_centroid() {
883 point result = point(centroid[0] / centroid_divisor, centroid[1] / centroid_divisor);
885 assert (finite(centroid[0])
886 && finite(centroid[1])
887 && (result.defined() || centroid_divisor == 0));
889 return result;
892 point get_error_centroid() {
893 point result = point(de_centroid[0] / de_sum, de_centroid[1] / de_sum);
894 return result;
898 ale_pos get_error_perturb() {
899 ale_pos result = de_centroid_v / de_sum;
901 return result;
907 * When non-empty, runs.front() is best, runs.back() is
908 * testing.
911 std::vector<run> runs;
914 * old_runs stores the latest available perturbation set for
915 * each multi-alignment element.
918 typedef std::pair<unsigned int, unsigned int> run_index;
919 std::map<run_index, run> old_runs;
921 static void *diff_subdomain(void *args);
923 struct subdomain_args {
924 struct scale_cluster c;
925 std::vector<run> runs;
926 int ax_count;
927 int f;
928 int i_min, i_max, j_min, j_max;
929 int subdomain;
932 int get_current_index() const {
933 assert(runs.size());
934 return runs[0].offset.get_current_index();
937 struct scale_cluster si;
938 int ax_count;
939 int frame;
941 std::vector<ale_pos> perturb_multipliers;
943 public:
944 void diff(struct scale_cluster c, ale_pos perturb,
945 transformation t,
946 int _ax_count, int f) {
948 if (runs.size() == 2)
949 runs.pop_back();
951 runs.push_back(run(t, perturb));
953 si = c;
954 ax_count = _ax_count;
955 frame = f;
957 ui::get()->d2_align_sample_start();
959 if (interpolant != NULL)
960 interpolant->set_parameters(t, c.input, c.accum->offset());
962 int N;
963 #ifdef USE_PTHREAD
964 N = thread::count();
966 pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t) * N);
967 pthread_attr_t *thread_attr = (pthread_attr_t *) malloc(sizeof(pthread_attr_t) * N);
969 #else
970 N = 1;
971 #endif
973 subdomain_args *args = new subdomain_args[N];
975 for (int ti = 0; ti < N; ti++) {
976 args[ti].c = c;
977 args[ti].runs = runs;
978 args[ti].ax_count = ax_count;
979 args[ti].f = f;
980 args[ti].i_min = (c.accum->height() * ti) / N;
981 args[ti].i_max = (c.accum->height() * (ti + 1)) / N;
982 args[ti].j_min = 0;
983 args[ti].j_max = c.accum->width();
984 args[ti].subdomain = ti;
985 #ifdef USE_PTHREAD
986 pthread_attr_init(&thread_attr[ti]);
987 pthread_attr_setdetachstate(&thread_attr[ti], PTHREAD_CREATE_JOINABLE);
988 pthread_create(&threads[ti], &thread_attr[ti], diff_subdomain, &args[ti]);
989 #else
990 diff_subdomain(&args[ti]);
991 #endif
994 for (int ti = 0; ti < N; ti++) {
995 #ifdef USE_PTHREAD
996 pthread_join(threads[ti], NULL);
997 #endif
998 runs.back().add(args[ti].runs.back());
1001 delete[] args;
1003 ui::get()->d2_align_sample_stop();
1007 private:
1008 void rediff() {
1009 std::vector<transformation> t_array;
1010 std::vector<ale_pos> p_array;
1012 for (unsigned int r = 0; r < runs.size(); r++) {
1013 t_array.push_back(runs[r].offset);
1014 p_array.push_back(runs[r].perturb);
1017 runs.clear();
1019 for (unsigned int r = 0; r < t_array.size(); r++)
1020 diff(si, p_array[r], t_array[r], ax_count, frame);
1024 public:
1025 int better() {
1026 assert(runs.size() >= 2);
1027 assert(runs[0].offset.scale() == runs[1].offset.scale());
1029 return (runs[1].get_error() < runs[0].get_error()
1030 || (!finite(runs[0].get_error()) && finite(runs[1].get_error())));
1033 diff_stat_t() : runs(), old_runs(), perturb_multipliers() {
1036 run_index get_run_index(unsigned int perturb_index) {
1037 return run_index(get_current_index(), perturb_index);
1040 run &get_run(unsigned int perturb_index) {
1041 run_index index = get_run_index(perturb_index);
1043 assert(old_runs.count(index));
1044 return old_runs[index];
1047 void rescale(ale_pos scale, scale_cluster _si) {
1048 assert(runs.size() == 1);
1050 si = _si;
1052 runs[0].rescale(scale);
1054 rediff();
1057 void push_element() {
1058 assert(runs.size() == 1);
1060 runs[0].offset.push_element();
1062 rediff();
1065 unsigned int get_current_index() {
1066 assert (runs.size() > 0);
1068 return runs[0].offset.get_current_index();
1071 void set_current_index(unsigned int i) {
1072 assert(runs.size() == 1);
1073 runs[0].offset.set_current_index(i);
1074 rediff();
1077 void calculate_element_region() {
1078 assert(runs.size() == 1);
1080 if (get_offset().get_current_index() > 0
1081 && get_offset().is_nontrivial())
1082 align::calculate_element_region(&runs[0].offset, si, ax_count);
1085 ~diff_stat_t() {
1088 diff_stat_t &operator=(const diff_stat_t &dst) {
1090 * Copy run information.
1092 runs = dst.runs;
1093 old_runs = dst.old_runs;
1096 * Copy diff variables
1098 si = dst.si;
1099 ax_count = dst.ax_count;
1100 frame = dst.frame;
1101 perturb_multipliers = dst.perturb_multipliers;
1103 return *this;
1106 diff_stat_t(const diff_stat_t &dst) : runs(), old_runs(),
1107 perturb_multipliers() {
1108 operator=(dst);
1111 ale_accum get_result() {
1112 assert(runs.size() == 1);
1113 return runs[0].result;
1116 ale_accum get_divisor() {
1117 assert(runs.size() == 1);
1118 return runs[0].divisor;
1121 transformation get_offset() {
1122 assert(runs.size() == 1);
1123 return runs[0].offset;
1126 int operator!=(diff_stat_t &param) {
1127 return (get_error() != param.get_error());
1130 int operator==(diff_stat_t &param) {
1131 return !(operator!=(param));
1134 ale_pos get_error_perturb() {
1135 assert(runs.size() == 1);
1136 return runs[0].get_error_perturb();
1139 ale_accum get_error() const {
1140 assert(runs.size() == 1);
1141 return runs[0].get_error();
1144 public:
1146 * Get the set of transformations produced by a given perturbation
1148 void get_perturb_set(std::vector<transformation> *set,
1149 ale_pos adj_p, ale_pos adj_o, ale_pos adj_b,
1150 ale_pos *current_bd, ale_pos *modified_bd,
1151 std::vector<ale_pos> multipliers = std::vector<ale_pos>()) {
1153 assert(runs.size() == 1);
1155 transformation test_t;
1158 * Translational or euclidean transformation
1161 for (unsigned int i = 0; i < 2; i++)
1162 for (unsigned int s = 0; s < 2; s++) {
1164 if (!multipliers.size())
1165 multipliers.push_back(1);
1167 assert(finite(multipliers[0]));
1169 test_t = get_offset();
1171 // test_t.eu_modify(i, (s ? -adj_p : adj_p) * multipliers[0]);
1172 test_t.translate((i ? point(1, 0) : point(0, 1))
1173 * (s ? -adj_p : adj_p)
1174 * multipliers[0]);
1176 test_t.snap(adj_p / 2);
1178 set->push_back(test_t);
1179 multipliers.erase(multipliers.begin());
1183 if (alignment_class > 0)
1184 for (unsigned int s = 0; s < 2; s++) {
1186 if (!multipliers.size())
1187 multipliers.push_back(1);
1189 assert(multipliers.size());
1190 assert(finite(multipliers[0]));
1192 if (!(adj_o * multipliers[0] < rot_max))
1193 return;
1195 ale_pos adj_s = (s ? 1 : -1) * adj_o * multipliers[0];
1197 test_t = get_offset();
1199 run_index ori = get_run_index(set->size());
1200 point centroid = point::undefined();
1202 if (!old_runs.count(ori))
1203 ori = get_run_index(0);
1205 if (!centroid.finite() && old_runs.count(ori)) {
1206 centroid = old_runs[ori].get_error_centroid();
1208 if (!centroid.finite())
1209 centroid = old_runs[ori].get_centroid();
1211 centroid *= test_t.scale()
1212 / old_runs[ori].offset.scale();
1215 if (!centroid.finite() && !test_t.is_projective()) {
1216 test_t.eu_modify(2, adj_s);
1217 } else if (!centroid.finite()) {
1218 centroid = point(si.input->height() / 2,
1219 si.input->width() / 2);
1221 test_t.rotate(centroid + si.accum->offset(),
1222 adj_s);
1223 } else {
1224 test_t.rotate(centroid + si.accum->offset(),
1225 adj_s);
1228 test_t.snap(adj_p / 2);
1230 set->push_back(test_t);
1231 multipliers.erase(multipliers.begin());
1234 if (alignment_class == 2) {
1237 * Projective transformation
1240 for (unsigned int i = 0; i < 4; i++)
1241 for (unsigned int j = 0; j < 2; j++)
1242 for (unsigned int s = 0; s < 2; s++) {
1244 if (!multipliers.size())
1245 multipliers.push_back(1);
1247 assert(multipliers.size());
1248 assert(finite(multipliers[0]));
1250 ale_pos adj_s = (s ? -1 : 1) * adj_p * multipliers [0];
1252 test_t = get_offset();
1254 if (perturb_type == 0)
1255 test_t.gpt_modify(j, i, adj_s);
1256 else if (perturb_type == 1)
1257 test_t.gr_modify(j, i, adj_s);
1258 else
1259 assert(0);
1261 test_t.snap(adj_p / 2);
1263 set->push_back(test_t);
1264 multipliers.erase(multipliers.begin());
1270 * Barrel distortion
1273 if (bda_mult != 0 && adj_b != 0) {
1275 for (unsigned int d = 0; d < get_offset().bd_count(); d++)
1276 for (unsigned int s = 0; s < 2; s++) {
1278 if (!multipliers.size())
1279 multipliers.push_back(1);
1281 assert (multipliers.size());
1282 assert (finite(multipliers[0]));
1284 ale_pos adj_s = (s ? -1 : 1) * adj_b * multipliers[0];
1286 if (bda_rate > 0 && fabs(modified_bd[d] + adj_s - current_bd[d]) > bda_rate)
1287 continue;
1289 transformation test_t = get_offset();
1291 test_t.bd_modify(d, adj_s);
1293 set->push_back(test_t);
1298 void confirm() {
1299 assert(runs.size() == 2);
1300 runs[0] = runs[1];
1301 runs.pop_back();
1304 void discard() {
1305 assert(runs.size() == 2);
1306 runs.pop_back();
1309 void perturb_test(ale_pos perturb, ale_pos adj_p, ale_pos adj_o, ale_pos adj_b,
1310 ale_pos *current_bd, ale_pos *modified_bd, int stable) {
1312 assert(runs.size() == 1);
1314 std::vector<transformation> t_set;
1316 if (perturb_multipliers.size() == 0) {
1317 get_perturb_set(&t_set, adj_p, adj_o, adj_b,
1318 current_bd, modified_bd);
1320 for (unsigned int i = 0; i < t_set.size(); i++) {
1321 diff_stat_t test = *this;
1323 test.diff(si, perturb, t_set[i], ax_count, frame);
1325 test.confirm();
1327 if (finite(adj_p / test.get_error_perturb()))
1328 perturb_multipliers.push_back(adj_p / test.get_error_perturb());
1329 else
1330 perturb_multipliers.push_back(1);
1334 t_set.clear();
1337 get_perturb_set(&t_set, adj_p, adj_o, adj_b, current_bd, modified_bd,
1338 perturb_multipliers);
1340 int found_unreliable = 1;
1341 std::vector<int> tested(t_set.size(), 0);
1343 for (unsigned int i = 0; i < t_set.size(); i++) {
1344 run_index ori = get_run_index(i);
1347 * Check for stability
1349 if (stable
1350 && old_runs.count(ori)
1351 && old_runs[ori].offset == t_set[i])
1352 tested[i] = 1;
1355 std::vector<ale_pos> perturb_multipliers_original = perturb_multipliers;
1357 while (found_unreliable) {
1359 found_unreliable = 0;
1361 for (unsigned int i = 0; i < t_set.size(); i++) {
1363 if (tested[i])
1364 continue;
1366 diff(si, perturb, t_set[i], ax_count, frame);
1368 if (!(i < perturb_multipliers.size())
1369 || !finite(perturb_multipliers[i])) {
1371 perturb_multipliers.resize(i + 1);
1373 perturb_multipliers[i] =
1374 adj_p / runs[1].get_error_perturb();
1376 if (finite(perturb_multipliers[i]))
1377 found_unreliable = 1;
1379 continue;
1382 run_index ori = get_run_index(i);
1384 if (old_runs.count(ori) == 0)
1385 old_runs.insert(std::pair<run_index, run>(ori, runs[1]));
1386 else
1387 old_runs[ori] = runs[1];
1389 perturb_multipliers[i] = perturb_multipliers_original[i]
1390 * adj_p / runs[1].get_error_perturb();
1392 if (!finite(perturb_multipliers[i]))
1393 perturb_multipliers[i] = 1;
1395 tested[i] = 1;
1397 if (better()
1398 && runs[1].get_error() < runs[0].get_error()
1399 && perturb_multipliers[i]
1400 / perturb_multipliers_original[i] < 2) {
1401 runs[0] = runs[1];
1402 runs.pop_back();
1403 return;
1408 if (runs.size() > 1)
1409 runs.pop_back();
1411 if (!found_unreliable)
1412 return;
1417 * Attempt to make the current element non-trivial, by finding a nearby
1418 * alignment admitting a non-empty element region.
1420 void make_element_nontrivial(ale_pos adj_p, ale_pos adj_o) {
1421 assert(runs.size() == 1);
1423 transformation *t = &runs[0].offset;
1425 if (t->is_nontrivial())
1426 return;
1428 calculate_element_region();
1430 if (t->is_nontrivial())
1431 return;
1433 std::vector<transformation> t_set;
1434 get_perturb_set(&t_set, adj_p, adj_o, 0, NULL, NULL);
1436 for (unsigned int i = 0; i < t_set.size(); i++) {
1438 align::calculate_element_region(&t_set[i], si, ax_count);
1440 if (t_set[i].is_nontrivial()) {
1441 *t = t_set[i];
1442 return;
1451 * Adjust exposure for an aligned frame B against reference A.
1453 * Expects full-LOD images.
1455 * Note: This method does not use any weighting, by certainty or
1456 * otherwise, in the first exposure registration pass, as any bias of
1457 * weighting according to color may also bias the exposure registration
1458 * result; it does use weighting, including weighting by certainty
1459 * (even if certainty weighting is not specified), in the second pass,
1460 * under the assumption that weighting by certainty improves handling
1461 * of out-of-range highlights, and that bias of exposure measurements
1462 * according to color may generally be less harmful after spatial
1463 * registration has been performed.
1465 class exposure_ratio_iterate : public thread::decompose_domain {
1466 pixel_accum *asums;
1467 pixel_accum *bsums;
1468 pixel_accum *asum;
1469 pixel_accum *bsum;
1470 struct scale_cluster c;
1471 transformation t;
1472 int ax_count;
1473 int pass_number;
1474 protected:
1475 void prepare_subdomains(unsigned int N) {
1476 asums = new pixel_accum[N];
1477 bsums = new pixel_accum[N];
1479 void subdomain_algorithm(unsigned int thread,
1480 int i_min, int i_max, int j_min, int j_max) {
1482 point offset = c.accum->offset();
1484 for (mc_iterate m(i_min, i_max, j_min, j_max, thread); !m.done(); m++) {
1486 unsigned int i = (unsigned int) m.get_i();
1487 unsigned int j = (unsigned int) m.get_j();
1489 if (ref_excluded(i, j, offset, c.ax_parameters, ax_count))
1490 continue;
1493 * Transform
1496 struct point q;
1498 q = (c.input_scale < 1.0 && interpolant == NULL)
1499 ? t.scaled_inverse_transform(
1500 point(i + offset[0], j + offset[1]))
1501 : t.unscaled_inverse_transform(
1502 point(i + offset[0], j + offset[1]));
1505 * Check that the transformed coordinates are within
1506 * the boundaries of array c.input, that they are not
1507 * subject to exclusion, and that the weight value in
1508 * the accumulated array is nonzero.
1511 if (input_excluded(q[0], q[1], c.ax_parameters, ax_count))
1512 continue;
1514 if (q[0] >= 0
1515 && q[0] <= c.input->height() - 1
1516 && q[1] >= 0
1517 && q[1] <= c.input->width() - 1
1518 && c.certainty->get_pixel(i, j).minabs_norm() != 0) {
1519 pixel a = c.accum->get_pixel(i, j);
1520 pixel b;
1522 b = c.input->get_bl(q);
1524 pixel weight = ((c.aweight && pass_number)
1525 ? c.aweight->get_pixel(i, j)
1526 : pixel(1, 1, 1))
1527 * (pass_number
1528 ? ppow(c.certainty->get_pixel(i, j)
1529 * c.input_certainty->get_bl(q, 1), 0.5)
1530 : pixel(1, 1, 1));
1532 asums[thread] += a * weight;
1533 bsums[thread] += b * weight;
1538 void finish_subdomains(unsigned int N) {
1539 for (unsigned int n = 0; n < N; n++) {
1540 *asum += asums[n];
1541 *bsum += bsums[n];
1543 delete asums;
1544 delete bsums;
1546 public:
1547 exposure_ratio_iterate(pixel_accum *_asum,
1548 pixel_accum *_bsum,
1549 struct scale_cluster _c,
1550 transformation _t,
1551 int _ax_count,
1552 int _pass_number) : decompose_domain(0, _c.accum->height(),
1553 0, _c.accum->width()){
1555 asum = _asum;
1556 bsum = _bsum;
1557 c = _c;
1558 t = _t;
1559 ax_count = _ax_count;
1560 pass_number = _pass_number;
1564 static void set_exposure_ratio(unsigned int m, struct scale_cluster c,
1565 transformation t, int ax_count, int pass_number) {
1567 if (_exp_register == 2) {
1569 * Use metadata only.
1571 ale_real gain_multiplier = image_rw::exp(m).get_gain_multiplier();
1572 pixel multiplier = pixel(gain_multiplier, gain_multiplier, gain_multiplier);
1574 image_rw::exp(m).set_multiplier(multiplier);
1575 ui::get()->exp_multiplier(multiplier[0],
1576 multiplier[1],
1577 multiplier[2]);
1579 return;
1582 pixel_accum asum(0, 0, 0), bsum(0, 0, 0);
1584 exposure_ratio_iterate eri(&asum, &bsum, c, t, ax_count, pass_number);
1585 eri.run();
1587 // std::cerr << (asum / bsum) << " ";
1589 pixel_accum new_multiplier;
1591 new_multiplier = asum / bsum * image_rw::exp(m).get_multiplier();
1593 if (finite(new_multiplier[0])
1594 && finite(new_multiplier[1])
1595 && finite(new_multiplier[2])) {
1596 image_rw::exp(m).set_multiplier(new_multiplier);
1597 ui::get()->exp_multiplier(new_multiplier[0],
1598 new_multiplier[1],
1599 new_multiplier[2]);
1604 * Copy all ax parameters.
1606 static exclusion *copy_ax_parameters(int local_ax_count, exclusion *source) {
1608 exclusion *dest = (exclusion *) malloc(local_ax_count * sizeof(exclusion));
1610 assert (dest);
1612 if (!dest)
1613 ui::get()->memory_error("exclusion regions");
1615 for (int idx = 0; idx < local_ax_count; idx++)
1616 dest[idx] = source[idx];
1618 return dest;
1622 * Copy ax parameters according to frame.
1624 static exclusion *filter_ax_parameters(int frame, int *local_ax_count) {
1626 exclusion *dest = (exclusion *) malloc(ax_count * sizeof(exclusion));
1628 assert (dest);
1630 if (!dest)
1631 ui::get()->memory_error("exclusion regions");
1633 *local_ax_count = 0;
1635 for (int idx = 0; idx < ax_count; idx++) {
1636 if (ax_parameters[idx].x[4] > frame
1637 || ax_parameters[idx].x[5] < frame)
1638 continue;
1640 dest[*local_ax_count] = ax_parameters[idx];
1642 (*local_ax_count)++;
1645 return dest;
1648 static void scale_ax_parameters(int local_ax_count, exclusion *ax_parameters,
1649 ale_pos ref_scale, ale_pos input_scale) {
1650 for (int i = 0; i < local_ax_count; i++) {
1651 ale_pos scale = (ax_parameters[i].type == exclusion::RENDER)
1652 ? ref_scale
1653 : input_scale;
1655 for (int n = 0; n < 6; n++) {
1656 ax_parameters[i].x[n] = ax_parameters[i].x[n] * scale;
1662 * Prepare the next level of detail for ordinary images.
1664 static const image *prepare_lod(const image *current) {
1665 if (current == NULL)
1666 return NULL;
1668 return current->scale_by_half("prepare_lod");
1672 * Prepare the next level of detail for definition maps.
1674 static const image *prepare_lod_def(const image *current) {
1675 if (current == NULL)
1676 return NULL;
1678 return current->defined_scale_by_half("prepare_lod_def");
1682 * Initialize scale cluster data structures.
1685 static void init_nl_cluster(struct scale_cluster *sc) {
1688 static struct scale_cluster *init_clusters(int frame, ale_real scale_factor,
1689 const image *input_frame, unsigned int steps,
1690 int *local_ax_count) {
1693 * Allocate memory for the array.
1696 struct scale_cluster *scale_clusters =
1697 (struct scale_cluster *) malloc(steps * sizeof(struct scale_cluster));
1699 assert (scale_clusters);
1701 if (!scale_clusters)
1702 ui::get()->memory_error("alignment");
1705 * Prepare images and exclusion regions for the highest level
1706 * of detail.
1709 scale_clusters[0].accum = reference_image;
1711 ui::get()->constructing_lod_clusters(0.0);
1712 scale_clusters[0].input_scale = scale_factor;
1713 if (scale_factor < 1.0 && interpolant == NULL)
1714 scale_clusters[0].input = input_frame->scale(scale_factor, "alignment");
1715 else
1716 scale_clusters[0].input = input_frame;
1718 scale_clusters[0].certainty = reference_defined->clone("certainty");
1719 scale_clusters[0].aweight = alignment_weights;
1720 scale_clusters[0].ax_parameters = filter_ax_parameters(frame, local_ax_count);
1723 * Allocate and determine input frame certainty.
1726 if (scale_clusters[0].input->get_bayer() != IMAGE_BAYER_NONE) {
1727 scale_clusters[0].input_certainty = new image_bayer_ale_real(
1728 scale_clusters[0].input->height(),
1729 scale_clusters[0].input->width(),
1730 scale_clusters[0].input->depth(),
1731 scale_clusters[0].input->get_bayer());
1732 } else {
1733 scale_clusters[0].input_certainty = scale_clusters[0].input->clone("certainty");
1736 for (unsigned int i = 0; i < scale_clusters[0].input_certainty->height(); i++)
1737 for (unsigned int j = 0; j < scale_clusters[0].input_certainty->width(); j++)
1738 for (unsigned int k = 0; k < 3; k++)
1739 if (scale_clusters[0].input->get_channels(i, j) & (1 << k))
1740 ((image *) scale_clusters[0].input_certainty)->chan(i, j, k) =
1741 scale_clusters[0].input->
1742 exp().confidence(scale_clusters[0].input->get_pixel(i, j))[k];
1744 scale_ax_parameters(*local_ax_count, scale_clusters[0].ax_parameters, scale_factor,
1745 (scale_factor < 1.0 && interpolant == NULL) ? scale_factor : 1);
1747 init_nl_cluster(&(scale_clusters[0]));
1750 * Prepare reduced-detail images and exclusion
1751 * regions.
1754 for (unsigned int step = 1; step < steps; step++) {
1755 ui::get()->constructing_lod_clusters(step);
1756 scale_clusters[step].accum = prepare_lod(scale_clusters[step - 1].accum);
1757 scale_clusters[step].certainty = prepare_lod_def(scale_clusters[step - 1].certainty);
1758 scale_clusters[step].aweight = prepare_lod_def(scale_clusters[step - 1].aweight);
1759 scale_clusters[step].ax_parameters
1760 = copy_ax_parameters(*local_ax_count, scale_clusters[step - 1].ax_parameters);
1762 double sf = scale_clusters[step - 1].input_scale / 2;
1763 scale_clusters[step].input_scale = sf;
1765 if (sf >= 1.0 || interpolant != NULL) {
1766 scale_clusters[step].input = scale_clusters[step - 1].input;
1767 scale_clusters[step].input_certainty = scale_clusters[step - 1].input_certainty;
1768 scale_ax_parameters(*local_ax_count, scale_clusters[step].ax_parameters, 0.5, 1);
1769 } else if (sf > 0.5) {
1770 scale_clusters[step].input = scale_clusters[step - 1].input->scale(sf, "alignment");
1771 scale_clusters[step].input_certainty = scale_clusters[step - 1].input->scale(sf, "alignment", 1);
1772 scale_ax_parameters(*local_ax_count, scale_clusters[step].ax_parameters, 0.5, sf);
1773 } else {
1774 scale_clusters[step].input = scale_clusters[step - 1].input->scale(0.5, "alignment");
1775 scale_clusters[step].input_certainty = scale_clusters[step - 1].input_certainty->scale(0.5, "alignment", 1);
1776 scale_ax_parameters(*local_ax_count, scale_clusters[step].ax_parameters, 0.5, 0.5);
1779 init_nl_cluster(&(scale_clusters[step]));
1782 return scale_clusters;
1786 * Destroy the first element in the scale cluster data structure.
1788 static void final_clusters(struct scale_cluster *scale_clusters, ale_real scale_factor,
1789 unsigned int steps) {
1791 if (scale_clusters[0].input_scale < 1.0)
1792 delete scale_clusters[0].input;
1794 free((void *)scale_clusters[0].ax_parameters);
1796 delete scale_clusters[0].certainty;
1798 for (unsigned int step = 1; step < steps; step++) {
1799 delete scale_clusters[step].accum;
1800 delete scale_clusters[step].certainty;
1801 delete scale_clusters[step].aweight;
1803 if (scale_clusters[step].input_scale < 1.0)
1804 delete scale_clusters[step].input;
1806 free((void *)scale_clusters[step].ax_parameters);
1809 free(scale_clusters);
1813 * Calculate the centroid of a control point for the set of frames
1814 * having index lower than m. Divide by any scaling of the output.
1816 static point unscaled_centroid(unsigned int m, unsigned int p) {
1817 assert(_keep);
1819 point point_sum(0, 0);
1820 ale_accum divisor = 0;
1822 for(unsigned int j = 0; j < m; j++) {
1823 point pp = cp_array[p][j];
1825 if (pp.defined()) {
1826 point_sum += kept_t[j].transform_unscaled(pp)
1827 / kept_t[j].scale();
1828 divisor += 1;
1832 if (divisor == 0)
1833 return point::undefined();
1835 return point_sum / divisor;
1839 * Calculate centroid of this frame, and of all previous frames,
1840 * from points common to both sets.
1842 static void centroids(unsigned int m, point *current, point *previous) {
1844 * Calculate the translation
1846 point other_centroid(0, 0);
1847 point this_centroid(0, 0);
1848 ale_pos divisor = 0;
1850 for (unsigned int i = 0; i < cp_count; i++) {
1851 point other_c = unscaled_centroid(m, i);
1852 point this_c = cp_array[i][m];
1854 if (!other_c.defined() || !this_c.defined())
1855 continue;
1857 other_centroid += other_c;
1858 this_centroid += this_c;
1859 divisor += 1;
1863 if (divisor == 0) {
1864 *current = point::undefined();
1865 *previous = point::undefined();
1866 return;
1869 *current = this_centroid / divisor;
1870 *previous = other_centroid / divisor;
1874 * Calculate the RMS error of control points for frame m, with
1875 * transformation t, against control points for earlier frames.
1877 static ale_accum cp_rms_error(unsigned int m, transformation t) {
1878 assert (_keep);
1880 ale_accum err = 0;
1881 ale_accum divisor = 0;
1883 for (unsigned int i = 0; i < cp_count; i++)
1884 for (unsigned int j = 0; j < m; j++) {
1885 const point *p = cp_array[i];
1886 point p_ref = kept_t[j].transform_unscaled(p[j]);
1887 point p_cur = t.transform_unscaled(p[m]);
1889 if (!p_ref.defined() || !p_cur.defined())
1890 continue;
1892 err += p_ref.lengthtosq(p_cur);
1893 divisor += 1;
1896 return sqrt(err / divisor);
1900 * Implement new delta --follow semantics.
1902 * If we have a transformation T such that
1904 * prev_final == T(prev_init)
1906 * Then we also have
1908 * current_init_follow == T(current_init)
1910 * We can calculate T as follows:
1912 * T == prev_final(prev_init^-1)
1914 * Where ^-1 is the inverse operator.
1916 static transformation follow(element_t *element, transformation offset, int lod) {
1918 transformation new_offset = offset;
1921 * Criteria for using following.
1924 if (!element->old_is_default && !element->is_default &&
1925 default_initial_alignment_type == 1) {
1927 * Ensure that the lod for the old initial and final
1928 * alignments are equal to the lod for the new initial
1929 * alignment.
1932 ui::get()->following();
1934 element->old_final_alignment.rescale (1 / pow(2, lod));
1935 element->old_initial_alignment.rescale(1 / pow(2, lod - element->old_lod));
1937 for (offset.set_current_index(0),
1938 element->old_initial_alignment.set_current_index(0),
1939 element->old_final_alignment.set_current_index(0),
1940 new_offset.set_current_index(0);
1942 offset.get_current_index() < _ma_card;
1944 offset.push_element(),
1945 new_offset.push_element()) {
1947 if (alignment_class == 0) {
1949 * Translational transformations
1952 ale_pos t0 = -element->old_initial_alignment.eu_get(0)
1953 + element->old_final_alignment.eu_get(0);
1954 ale_pos t1 = -element->old_initial_alignment.eu_get(1)
1955 + element->old_final_alignment.eu_get(1);
1957 new_offset.eu_modify(0, t0);
1958 new_offset.eu_modify(1, t1);
1960 } else if (alignment_class == 1) {
1962 * Euclidean transformations
1965 ale_pos t2 = -element->old_initial_alignment.eu_get(2)
1966 + element->old_final_alignment.eu_get(2);
1968 new_offset.eu_modify(2, t2);
1970 point p( offset.scaled_height()/2 + offset.eu_get(0) - element->old_initial_alignment.eu_get(0),
1971 offset.scaled_width()/2 + offset.eu_get(1) - element->old_initial_alignment.eu_get(1) );
1973 p = element->old_final_alignment.transform_scaled(p);
1975 new_offset.eu_modify(0, p[0] - offset.scaled_height()/2 - offset.eu_get(0));
1976 new_offset.eu_modify(1, p[1] - offset.scaled_width()/2 - offset.eu_get(1));
1978 } else if (alignment_class == 2) {
1980 * Projective transformations
1983 point p[4];
1985 p[0] = element->old_final_alignment.transform_scaled(element->old_initial_alignment
1986 . scaled_inverse_transform(offset.get_current_element().transform_scaled(point( 0 , 0 ))));
1987 p[1] = element->old_final_alignment.transform_scaled(element->old_initial_alignment
1988 . scaled_inverse_transform(offset.get_current_element().transform_scaled(point(offset.scaled_height(), 0 ))));
1989 p[2] = element->old_final_alignment.transform_scaled(element->old_initial_alignment
1990 . scaled_inverse_transform(offset.get_current_element().transform_scaled(point(offset.scaled_height(), offset.scaled_width()))));
1991 p[3] = element->old_final_alignment.transform_scaled(element->old_initial_alignment
1992 . scaled_inverse_transform(offset.get_current_element().transform_scaled(point( 0 , offset.scaled_width()))));
1994 new_offset.gpt_set(p);
1998 ui::get()->set_offset(offset);
2001 return new_offset;
2004 static void test_global(diff_stat_t *here, scale_cluster si, transformation t,
2005 int local_ax_count, int m, ale_pos local_gs_mo, ale_pos perturb) {
2007 diff_stat_t test(*here);
2009 test.diff(si, perturb, t, local_ax_count, m);
2011 unsigned int ovl = overlap(si, t, local_ax_count);
2013 if (ovl >= local_gs_mo && test.better()) {
2014 test.confirm();
2015 *here = test;
2016 ui::get()->set_match(here->get_error());
2017 ui::get()->set_offset(here->get_offset());
2018 } else {
2019 test.discard();
2025 * Get the set of global transformations for a given density
2027 static void test_globals(diff_stat_t *here,
2028 scale_cluster si, transformation t, int local_gs, ale_pos adj_p,
2029 int local_ax_count, int m, ale_pos local_gs_mo, ale_pos perturb) {
2031 transformation offset = t;
2033 point min, max;
2035 transformation offset_p = offset;
2037 if (!offset_p.is_projective())
2038 offset_p.eu_to_gpt();
2040 min = max = offset_p.gpt_get(0);
2041 for (int p_index = 1; p_index < 4; p_index++) {
2042 point p = offset_p.gpt_get(p_index);
2043 if (p[0] < min[0])
2044 min[0] = p[0];
2045 if (p[1] < min[1])
2046 min[1] = p[1];
2047 if (p[0] > max[0])
2048 max[0] = p[0];
2049 if (p[1] > max[1])
2050 max[1] = p[1];
2053 point inner_min_t = -min;
2054 point inner_max_t = -max + point(si.accum->height(), si.accum->width());
2055 point outer_min_t = -max + point(adj_p - 1, adj_p - 1);
2056 point outer_max_t = point(si.accum->height(), si.accum->width()) - point(adj_p, adj_p);
2058 if (local_gs == 1 || local_gs == 3 || local_gs == 4 || local_gs == 6) {
2061 * Inner
2064 for (ale_pos i = inner_min_t[0]; i <= inner_max_t[0]; i += adj_p)
2065 for (ale_pos j = inner_min_t[1]; j <= inner_max_t[1]; j += adj_p) {
2066 transformation test_t = offset;
2067 test_t.translate(point(i, j));
2068 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
2072 if (local_gs == 2 || local_gs == 3 || local_gs == -1 || local_gs == 6) {
2075 * Outer
2078 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
2079 for (ale_pos j = outer_min_t[1]; j < inner_min_t[1]; j += adj_p) {
2080 transformation test_t = offset;
2081 test_t.translate(point(i, j));
2082 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
2084 for (ale_pos i = outer_min_t[0]; i <= outer_max_t[0]; i += adj_p)
2085 for (ale_pos j = outer_max_t[1]; j > inner_max_t[1]; j -= adj_p) {
2086 transformation test_t = offset;
2087 test_t.translate(point(i, j));
2088 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
2090 for (ale_pos i = outer_min_t[0]; i < inner_min_t[0]; i += adj_p)
2091 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
2092 transformation test_t = offset;
2093 test_t.translate(point(i, j));
2094 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
2096 for (ale_pos i = outer_max_t[0]; i > inner_max_t[0]; i -= adj_p)
2097 for (ale_pos j = outer_min_t[1]; j <= outer_max_t[1]; j += adj_p) {
2098 transformation test_t = offset;
2099 test_t.translate(point(i, j));
2100 test_global(here, si, test_t, local_ax_count, m, local_gs_mo, perturb);
2105 static void get_translational_set(std::vector<transformation> *set,
2106 transformation t, ale_pos adj_p) {
2108 ale_pos adj_s;
2110 transformation offset = t;
2111 transformation test_t;
2113 for (int i = 0; i < 2; i++)
2114 for (adj_s = -adj_p; adj_s <= adj_p; adj_s += 2 * adj_p) {
2116 test_t = offset;
2118 test_t.translate(i ? point(adj_s, 0) : point(0, adj_s));
2120 set->push_back(test_t);
2124 static int threshold_ok(ale_accum error) {
2125 if ((1 - error) * 100 >= match_threshold)
2126 return 1;
2128 if (!(match_threshold >= 0))
2129 return 1;
2131 return 0;
2135 * Align frame m against the reference.
2137 * XXX: the transformation class currently combines ordinary
2138 * transformations with scaling. This is somewhat convenient for
2139 * some things, but can also be confusing. This method, _align(), is
2140 * one case where special care must be taken to ensure that the scale
2141 * is always set correctly (by using the 'rescale' method).
2143 static diff_stat_t _align(int m, int local_gs, element_t *element) {
2145 const image *input_frame = element->input_frame;
2148 * Local upper/lower data, possibly dependent on image
2149 * dimensions.
2152 ale_pos local_lower, local_upper, local_gs_mo;
2155 * Select the minimum dimension as the reference.
2158 ale_pos reference_size = input_frame->height();
2159 if (input_frame->width() < reference_size)
2160 reference_size = input_frame->width();
2161 ale_pos reference_area = input_frame->height()
2162 * input_frame->width();
2164 if (perturb_lower_percent)
2165 local_lower = perturb_lower
2166 * reference_size
2167 * 0.01
2168 * scale_factor;
2169 else
2170 local_lower = perturb_lower;
2172 if (perturb_upper_percent)
2173 local_upper = perturb_upper
2174 * reference_size
2175 * 0.01
2176 * scale_factor;
2177 else
2178 local_upper = perturb_upper;
2180 local_upper = pow(2, floor(log(local_upper) / log(2)));
2182 if (gs_mo_percent)
2183 local_gs_mo = _gs_mo
2184 * reference_area
2185 * 0.01
2186 * scale_factor;
2187 else
2188 local_gs_mo = _gs_mo;
2191 * Logarithms aren't exact, so we divide repeatedly to discover
2192 * how many steps will occur, and pass this information to the
2193 * user interface.
2196 int step_count = 0;
2197 double step_variable = local_upper;
2198 while (step_variable >= local_lower) {
2199 step_variable /= 2;
2200 step_count++;
2203 ui::get()->set_steps(step_count);
2205 ale_pos perturb = local_upper;
2206 int lod;
2208 if (_keep) {
2209 kept_t[latest] = latest_t;
2210 kept_ok[latest] = latest_ok;
2214 * Maximum level-of-detail. Use a level of detail at most
2215 * 2^lod_diff finer than the adjustment resolution. lod_diff
2216 * is a synonym for lod_max.
2219 const int lod_diff = lod_max;
2222 * Determine how many levels of detail should be prepared.
2226 * Plain (unsigned int) casting seems to be broken in some cases.
2229 unsigned int steps = (perturb > pow(2, lod_max))
2230 ? (unsigned int) lrint(log(perturb) / log(2)) - lod_max + 1 : 1;
2233 * Prepare multiple levels of detail.
2236 int local_ax_count;
2237 struct scale_cluster *scale_clusters = init_clusters(m,
2238 scale_factor, input_frame, steps,
2239 &local_ax_count);
2242 * Initialize variables used in the main loop.
2245 lod = (steps - 1);
2248 * Initialize the default initial transform
2251 if (default_initial_alignment_type == 0) {
2254 * Follow the transformation of the original frame,
2255 * setting new image dimensions.
2258 // element->default_initial_alignment = orig_t;
2259 element->default_initial_alignment.set_current_element(orig_t.get_element(0));
2260 element->default_initial_alignment.set_dimensions(input_frame);
2262 } else if (default_initial_alignment_type == 1)
2265 * Follow previous transformation, setting new image
2266 * dimensions.
2269 element->default_initial_alignment.set_dimensions(input_frame);
2271 else
2272 assert(0);
2274 element->old_is_default = element->is_default;
2277 * Scale default initial transform for lod
2280 element->default_initial_alignment.rescale(1 / pow(2, lod));
2283 * Set the default transformation.
2286 transformation offset = element->default_initial_alignment;
2289 * Load any file-specified transformations
2292 for (offset.set_current_index(0);
2293 offset.get_current_index() < _ma_card;
2294 offset.push_element()) {
2296 offset = tload_next(tload, alignment_class == 2,
2297 offset,
2298 &element->is_default,
2299 offset.get_current_index() == 0);
2303 offset.set_current_index(0);
2305 ui::get()->set_offset(offset);
2307 if (perturb > 0) {
2310 * Apply following logic
2313 transformation new_offset = follow(element, offset, lod);
2315 new_offset.set_current_index(0);
2317 element->old_initial_alignment = offset;
2318 element->old_lod = lod;
2319 offset = new_offset;
2321 } else {
2322 element->old_initial_alignment = offset;
2323 element->old_lod = lod;
2326 struct scale_cluster si = scale_clusters[lod];
2329 * Projective adjustment value
2332 ale_pos adj_p = (perturb >= pow(2, lod_diff))
2333 ? pow(2, lod_diff) : (double) perturb;
2336 * Orientational adjustment value in degrees.
2338 * Since rotational perturbation is now specified as an
2339 * arclength, we have to convert.
2342 ale_pos adj_o = 2 * perturb
2343 / sqrt(pow(scale_clusters[0].input->height(), 2)
2344 + pow(scale_clusters[0].input->width(), 2))
2345 * 180
2346 / M_PI;
2349 * Barrel distortion adjustment value
2352 ale_pos adj_b = perturb * bda_mult;
2355 * Global search overlap requirements.
2358 local_gs_mo /= pow(pow(2, lod), 2);
2361 * Pre-alignment exposure adjustment
2364 if (_exp_register) {
2365 ui::get()->exposure_1();
2366 transformation o = offset;
2367 for (int k = lod; k > 0; k--)
2368 o.rescale(2);
2369 set_exposure_ratio(m, scale_clusters[0], o, local_ax_count, 0);
2373 * Alignment statistics.
2376 diff_stat_t here;
2379 * Current difference (error) value
2382 ui::get()->prematching();
2383 here.diff(si, perturb, offset, local_ax_count, m);
2384 ui::get()->set_match(here.get_error());
2387 * Current and modified barrel distortion parameters
2390 ale_pos current_bd[BARREL_DEGREE];
2391 ale_pos modified_bd[BARREL_DEGREE];
2392 offset.bd_get(current_bd);
2393 offset.bd_get(modified_bd);
2396 * Translational global search step
2399 if (perturb >= local_lower && local_gs != 0 && local_gs != 5
2400 && (local_gs != 6 || element->is_default)) {
2402 ui::get()->global_alignment(perturb, lod);
2403 ui::get()->gs_mo(local_gs_mo);
2405 test_globals(&here, si, here.get_offset(), local_gs, adj_p,
2406 local_ax_count, m, local_gs_mo, perturb);
2408 ui::get()->set_match(here.get_error());
2409 ui::get()->set_offset(here.get_offset());
2413 * Control point alignment
2416 if (local_gs == 5) {
2418 transformation o = here.get_offset();
2420 for (int k = lod; k > 0; k--)
2421 o.rescale(2);
2424 * Determine centroid data
2427 point current, previous;
2428 centroids(m, &current, &previous);
2430 if (current.defined() && previous.defined()) {
2431 o = orig_t;
2432 o.set_dimensions(input_frame);
2433 o.translate((previous - current) * o.scale());
2434 current = previous;
2438 * Determine rotation for alignment classes other than translation.
2441 ale_accum lowest_error = cp_rms_error(m, o);
2443 ale_pos rot_lower = 2 * local_lower
2444 / sqrt(pow(scale_clusters[0].input->height(), 2)
2445 + pow(scale_clusters[0].input->width(), 2))
2446 * 180
2447 / M_PI;
2449 if (alignment_class > 0)
2450 for (ale_pos rot = 30; rot > rot_lower; rot /= 2)
2451 for (ale_pos srot = -rot; srot < rot * 1.5; srot += rot * 2) {
2452 int is_improved = 1;
2453 while (is_improved) {
2454 is_improved = 0;
2455 transformation test_t = o;
2457 * XXX: is this right?
2459 test_t.rotate(current * o.scale(), srot);
2460 ale_pos test_v = cp_rms_error(m, test_t);
2462 if (test_v < lowest_error) {
2463 lowest_error = test_v;
2464 o = test_t;
2465 srot += 3 * rot;
2466 is_improved = 1;
2472 * Determine projective parameters through a local
2473 * minimum search.
2476 if (alignment_class == 2) {
2477 ale_accum adj_p = lowest_error;
2479 if (adj_p < local_lower)
2480 adj_p = local_lower;
2482 while (adj_p >= local_lower) {
2483 transformation test_t = o;
2484 int is_improved = 1;
2485 ale_accum test_v;
2486 ale_accum adj_s;
2488 while (is_improved) {
2489 is_improved = 0;
2491 for (int i = 0; i < 4; i++)
2492 for (int j = 0; j < 2; j++)
2493 for (adj_s = -adj_p; adj_s <= adj_p; adj_s += 2 * adj_p) {
2495 test_t = o;
2497 if (perturb_type == 0)
2498 test_t.gpt_modify(j, i, adj_s);
2499 else if (perturb_type == 1)
2500 test_t.gr_modify(j, i, adj_s);
2501 else
2502 assert(0);
2504 test_v = cp_rms_error(m, test_t);
2506 if (test_v < lowest_error) {
2507 lowest_error = test_v;
2508 o = test_t;
2509 adj_s += 3 * adj_p;
2510 is_improved = 1;
2514 adj_p /= 2;
2518 if (_exp_register)
2519 set_exposure_ratio(m, scale_clusters[0], o, local_ax_count, 0);
2521 for (int k = lod; k > 0; k--)
2522 o.rescale(0.5);
2524 here.diff(si, perturb, o, local_ax_count, m);
2525 here.confirm();
2526 ui::get()->set_match(here.get_error());
2527 ui::get()->set_offset(here.get_offset());
2531 * Announce perturbation size
2534 ui::get()->aligning(perturb, lod);
2537 * Run initial tests to get perturbation multipliers and error
2538 * centroids.
2541 std::vector<transformation> t_set;
2543 here.get_perturb_set(&t_set, adj_p, adj_o, adj_b, current_bd, modified_bd);
2546 * Perturbation adjustment loop.
2549 int stable_count = 0;
2551 while (perturb >= local_lower) {
2554 * Orientational adjustment value in degrees.
2556 * Since rotational perturbation is now specified as an
2557 * arclength, we have to convert.
2560 ale_pos adj_o = 2 * perturb
2561 / sqrt(pow(scale_clusters[0].input->height(), 2)
2562 + pow(scale_clusters[0].input->width(), 2))
2563 * 180
2564 / M_PI;
2567 * Barrel distortion adjustment value
2570 ale_pos adj_b = perturb * bda_mult;
2572 diff_stat_t old_here = here;
2574 here.perturb_test(perturb, adj_p, adj_o, adj_b, current_bd, modified_bd,
2575 stable_count);
2577 if (here.get_offset() == old_here.get_offset())
2578 stable_count++;
2579 else
2580 stable_count = 0;
2582 if (stable_count == 3) {
2584 stable_count = 0;
2586 here.calculate_element_region();
2588 if (here.get_current_index() + 1 < _ma_card) {
2589 here.push_element();
2590 here.make_element_nontrivial(adj_p, adj_o);
2591 element->is_primary = 0;
2592 } else {
2594 here.set_current_index(0);
2596 element->is_primary = 1;
2598 perturb *= 0.5;
2600 if (lod > 0) {
2603 * Work with images twice as large
2606 lod--;
2607 si = scale_clusters[lod];
2610 * Rescale the transforms.
2613 here.rescale(2, si);
2614 element->default_initial_alignment.rescale(2);
2616 } else {
2617 adj_p = perturb;
2621 * Announce changes
2624 ui::get()->alignment_perturbation_level(perturb, lod);
2629 ui::get()->set_match(here.get_error());
2630 ui::get()->set_offset(here.get_offset());
2633 here.set_current_index(0);
2635 offset = here.get_offset();
2637 if (lod > 0) {
2638 here.rescale(pow(2, lod), scale_clusters[0]);
2639 element->default_initial_alignment.rescale(pow(2, lod));
2643 * Post-alignment exposure adjustment
2646 if (_exp_register == 1) {
2647 ui::get()->exposure_2();
2648 set_exposure_ratio(m, scale_clusters[0], offset, local_ax_count, 1);
2652 * Recalculate error
2655 ui::get()->postmatching();
2656 offset.use_full_support();
2657 here.diff(scale_clusters[0], perturb, offset, local_ax_count, m);
2658 here.confirm();
2659 offset.use_restricted_support();
2660 ui::get()->set_match(here.get_error());
2663 * Free the level-of-detail structures
2666 final_clusters(scale_clusters, scale_factor, steps);
2669 * Ensure that the match meets the threshold.
2672 if (threshold_ok(here.get_error())) {
2674 * Update alignment variables
2676 latest_ok = 1;
2677 element->default_initial_alignment = offset;
2678 element->old_final_alignment = offset;
2679 ui::get()->alignment_match_ok();
2680 } else if (local_gs == 4) {
2683 * Align with outer starting points.
2687 * XXX: This probably isn't exactly the right thing to do,
2688 * since variables like old_initial_value have been overwritten.
2691 diff_stat_t nested_result = _align(m, -1, element);
2693 if (threshold_ok(nested_result.get_error())) {
2694 return nested_result;
2695 } else if (nested_result.get_error() < here.get_error()) {
2696 here = nested_result;
2699 if (is_fail_default)
2700 offset = element->default_initial_alignment;
2702 ui::get()->set_match(here.get_error());
2703 ui::get()->alignment_no_match();
2705 } else if (local_gs == -1) {
2707 latest_ok = 0;
2708 latest_t = offset;
2709 return here;
2711 } else {
2712 if (is_fail_default)
2713 offset = element->default_initial_alignment;
2714 latest_ok = 0;
2715 ui::get()->alignment_no_match();
2719 * Write the tonal registration multiplier as a comment.
2722 pixel trm = image_rw::exp(m).get_multiplier();
2723 tsave_trm(tsave, trm[0], trm[1], trm[2]);
2726 * Save the transformation information
2729 for (offset.set_current_index(0);
2730 offset.get_current_index() < _ma_card;
2731 offset.push_element()) {
2733 tsave_next(tsave, offset, alignment_class == 2,
2734 offset.get_current_index() == 0);
2737 offset.set_current_index(0);
2739 latest_t = offset;
2742 * Update match statistics.
2745 match_sum += (1 - here.get_error()) * 100;
2746 match_count++;
2747 latest = m;
2749 return here;
2752 #ifdef USE_FFTW
2754 * High-pass filter for frequency weights
2756 static void hipass(int rows, int cols, fftw_complex *inout) {
2757 for (int i = 0; i < rows * vert_freq_cut; i++)
2758 for (int j = 0; j < cols; j++)
2759 for (int k = 0; k < 2; k++)
2760 inout[i * cols + j][k] = 0;
2761 for (int i = 0; i < rows; i++)
2762 for (int j = 0; j < cols * horiz_freq_cut; j++)
2763 for (int k = 0; k < 2; k++)
2764 inout[i * cols + j][k] = 0;
2765 for (int i = 0; i < rows; i++)
2766 for (int j = 0; j < cols; j++)
2767 for (int k = 0; k < 2; k++)
2768 if (i / (double) rows + j / (double) cols < 2 * avg_freq_cut)
2769 inout[i * cols + j][k] = 0;
2771 #endif
2775 * Reset alignment weights
2777 static void reset_weights() {
2778 if (alignment_weights != NULL)
2779 delete alignment_weights;
2781 alignment_weights = NULL;
2785 * Initialize alignment weights
2787 static void init_weights() {
2788 if (alignment_weights != NULL)
2789 return;
2791 int rows = reference_image->height();
2792 int cols = reference_image->width();
2793 int colors = reference_image->depth();
2795 alignment_weights = new image_ale_real(rows, cols,
2796 colors, "alignment_weights");
2798 assert (alignment_weights);
2800 for (int i = 0; i < rows; i++)
2801 for (int j = 0; j < cols; j++)
2802 alignment_weights->set_pixel(i, j, pixel(1, 1, 1));
2806 * Update alignment weights with weight map
2808 static void map_update() {
2810 if (weight_map == NULL)
2811 return;
2813 init_weights();
2815 point map_offset = reference_image->offset() - weight_map->offset();
2817 int rows = reference_image->height();
2818 int cols = reference_image->width();
2820 for (int i = 0; i < rows; i++)
2821 for (int j = 0; j < cols; j++) {
2822 point map_weight_position = map_offset + point(i, j);
2823 if (map_weight_position[0] >= 0
2824 && map_weight_position[1] >= 0
2825 && map_weight_position[0] <= weight_map->height() - 1
2826 && map_weight_position[1] <= weight_map->width() - 1)
2827 alignment_weights->pix(i, j) *= weight_map->get_bl(map_weight_position);
2832 * Update alignment weights with algorithmic weights
2834 static void wmx_update() {
2835 #ifdef USE_UNIX
2837 static exposure *exp_def = new exposure_default();
2838 static exposure *exp_bool = new exposure_boolean();
2840 if (wmx_file == NULL || wmx_exec == NULL || wmx_defs == NULL)
2841 return;
2843 unsigned int rows = reference_image->height();
2844 unsigned int cols = reference_image->width();
2846 image_rw::write_image(wmx_file, reference_image);
2847 image_rw::write_image(wmx_defs, reference_defined, exp_bool);
2849 /* execute ... */
2850 int exit_status = 1;
2851 if (!fork()) {
2852 execlp(wmx_exec, wmx_exec, wmx_file, wmx_defs, NULL);
2853 ui::get()->exec_failure(wmx_exec, wmx_file, wmx_defs);
2856 wait(&exit_status);
2858 if (exit_status)
2859 ui::get()->fork_failure("d2::align");
2861 image *wmx_weights = image_rw::read_image(wmx_file, exp_def);
2863 if (wmx_weights->height() != rows || wmx_weights->width() != cols)
2864 ui::get()->error("algorithmic weighting must not change image size");
2866 if (alignment_weights == NULL)
2867 alignment_weights = wmx_weights;
2868 else
2869 for (unsigned int i = 0; i < rows; i++)
2870 for (unsigned int j = 0; j < cols; j++)
2871 alignment_weights->pix(i, j) *= wmx_weights->pix(i, j);
2872 #endif
2876 * Update alignment weights with frequency weights
2878 static void fw_update() {
2879 #ifdef USE_FFTW
2880 if (horiz_freq_cut == 0
2881 && vert_freq_cut == 0
2882 && avg_freq_cut == 0)
2883 return;
2886 * Required for correct operation of --fwshow
2889 assert (alignment_weights == NULL);
2891 int rows = reference_image->height();
2892 int cols = reference_image->width();
2893 int colors = reference_image->depth();
2895 alignment_weights = new image_ale_real(rows, cols,
2896 colors, "alignment_weights");
2898 fftw_complex *inout = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * rows * cols);
2900 assert (inout);
2902 fftw_plan pf = fftw_plan_dft_2d(rows, cols,
2903 inout, inout,
2904 FFTW_FORWARD, FFTW_ESTIMATE);
2906 fftw_plan pb = fftw_plan_dft_2d(rows, cols,
2907 inout, inout,
2908 FFTW_BACKWARD, FFTW_ESTIMATE);
2910 for (int k = 0; k < colors; k++) {
2911 for (int i = 0; i < rows * cols; i++) {
2912 inout[i][0] = reference_image->get_pixel(i / cols, i % cols)[k];
2913 inout[i][1] = 0;
2916 fftw_execute(pf);
2917 hipass(rows, cols, inout);
2918 fftw_execute(pb);
2920 for (int i = 0; i < rows * cols; i++) {
2921 #if 0
2922 alignment_weights->pix(i / cols, i % cols)[k] = fabs(inout[i][0] / (rows * cols));
2923 #else
2924 alignment_weights->pix(i / cols, i % cols)[k] =
2925 sqrt(pow(inout[i][0] / (rows * cols), 2)
2926 + pow(inout[i][1] / (rows * cols), 2));
2927 #endif
2931 fftw_destroy_plan(pf);
2932 fftw_destroy_plan(pb);
2933 fftw_free(inout);
2935 if (fw_output != NULL)
2936 image_rw::write_image(fw_output, alignment_weights);
2937 #endif
2941 * Update alignment to frame N.
2943 static void update_to(int n) {
2945 assert (n <= latest + 1);
2946 assert (n >= 0);
2948 static std::vector<element_t> elements;
2950 if (latest < 0) {
2952 elements.resize(1);
2955 * Handle the initial frame
2958 elements[0].input_frame = image_rw::open(n);
2960 const image *i = elements[0].input_frame;
2961 int is_default;
2962 transformation result = alignment_class == 2
2963 ? transformation::gpt_identity(i, scale_factor)
2964 : transformation::eu_identity(i, scale_factor);
2965 result = tload_first(tload, alignment_class == 2, result, &is_default);
2966 tsave_first(tsave, result, alignment_class == 2);
2968 if (_keep > 0) {
2969 kept_t = new transformation[image_rw::count()];
2970 kept_ok = (int *) malloc(image_rw::count()
2971 * sizeof(int));
2972 assert (kept_t);
2973 assert (kept_ok);
2975 if (!kept_t || !kept_ok)
2976 ui::get()->memory_error("alignment");
2978 kept_ok[0] = 1;
2979 kept_t[0] = result;
2982 latest = 0;
2983 latest_ok = 1;
2984 latest_t = result;
2986 elements[0].default_initial_alignment = result;
2987 orig_t = result;
2989 image_rw::close(n);
2992 for (int i = latest + 1; i <= n; i++) {
2993 int j = 0;
2996 * Handle supplemental frames.
2999 assert (reference != NULL);
3001 ui::get()->set_arender_current();
3002 reference->sync(i - 1);
3003 ui::get()->clear_arender_current();
3004 reference_image = reference->get_image();
3005 reference_defined = reference->get_defined();
3007 reset_weights();
3008 fw_update();
3009 wmx_update();
3010 map_update();
3012 assert (reference_image != NULL);
3013 assert (reference_defined != NULL);
3015 elements[j].input_frame = image_rw::open(i);
3016 elements[j].is_primary = 1;
3018 _align(i, _gs, &elements[j]);
3020 image_rw::close(n);
3023 if (elements.size() > _ma_card)
3024 elements.resize(_ma_card);
3027 public:
3030 * Set the control point count
3032 static void set_cp_count(unsigned int n) {
3033 assert (cp_array == NULL);
3035 cp_count = n;
3036 cp_array = (const point **) malloc(n * sizeof(const point *));
3040 * Set control points.
3042 static void set_cp(unsigned int i, const point *p) {
3043 cp_array[i] = p;
3047 * Register exposure
3049 static void exp_register() {
3050 _exp_register = 1;
3054 * Register exposure only based on metadata
3056 static void exp_meta_only() {
3057 _exp_register = 2;
3061 * Don't register exposure
3063 static void exp_noregister() {
3064 _exp_register = 0;
3068 * Set alignment class to translation only. Only adjust the x and y
3069 * position of images. Do not rotate input images or perform
3070 * projective transformations.
3072 static void class_translation() {
3073 alignment_class = 0;
3077 * Set alignment class to Euclidean transformations only. Adjust the x
3078 * and y position of images and the orientation of the image about the
3079 * image center.
3081 static void class_euclidean() {
3082 alignment_class = 1;
3086 * Set alignment class to perform general projective transformations.
3087 * See the file gpt.h for more information about general projective
3088 * transformations.
3090 static void class_projective() {
3091 alignment_class = 2;
3095 * Set the default initial alignment to the identity transformation.
3097 static void initial_default_identity() {
3098 default_initial_alignment_type = 0;
3102 * Set the default initial alignment to the most recently matched
3103 * frame's final transformation.
3105 static void initial_default_follow() {
3106 default_initial_alignment_type = 1;
3110 * Perturb output coordinates.
3112 static void perturb_output() {
3113 perturb_type = 0;
3117 * Perturb source coordinates.
3119 static void perturb_source() {
3120 perturb_type = 1;
3124 * Frames under threshold align optimally
3126 static void fail_optimal() {
3127 is_fail_default = 0;
3131 * Frames under threshold keep their default alignments.
3133 static void fail_default() {
3134 is_fail_default = 1;
3138 * Align images with an error contribution from each color channel.
3140 static void all() {
3141 channel_alignment_type = 0;
3145 * Align images with an error contribution only from the green channel.
3146 * Other color channels do not affect alignment.
3148 static void green() {
3149 channel_alignment_type = 1;
3153 * Align images using a summation of channels. May be useful when
3154 * dealing with images that have high frequency color ripples due to
3155 * color aliasing.
3157 static void sum() {
3158 channel_alignment_type = 2;
3162 * Error metric exponent
3165 static void set_metric_exponent(float me) {
3166 metric_exponent = me;
3170 * Match threshold
3173 static void set_match_threshold(float mt) {
3174 match_threshold = mt;
3178 * Perturbation lower and upper bounds.
3181 static void set_perturb_lower(ale_pos pl, int plp) {
3182 perturb_lower = pl;
3183 perturb_lower_percent = plp;
3186 static void set_perturb_upper(ale_pos pu, int pup) {
3187 perturb_upper = pu;
3188 perturb_upper_percent = pup;
3192 * Maximum rotational perturbation.
3195 static void set_rot_max(int rm) {
3198 * Obtain the largest power of two not larger than rm.
3201 rot_max = pow(2, floor(log(rm) / log(2)));
3205 * Barrel distortion adjustment multiplier
3208 static void set_bda_mult(ale_pos m) {
3209 bda_mult = m;
3213 * Barrel distortion maximum rate of change
3216 static void set_bda_rate(ale_pos m) {
3217 bda_rate = m;
3221 * Level-of-detail
3224 static void set_lod_max(int lm) {
3225 lod_max = lm;
3229 * Set the scale factor
3231 static void set_scale(ale_pos s) {
3232 scale_factor = s;
3236 * Set reference rendering to align against
3238 static void set_reference(render *r) {
3239 reference = r;
3243 * Set the interpolant
3245 static void set_interpolant(filter::scaled_filter *f) {
3246 interpolant = f;
3250 * Set alignment weights image
3252 static void set_weight_map(const image *i) {
3253 weight_map = i;
3257 * Set frequency cuts
3259 static void set_frequency_cut(double h, double v, double a) {
3260 horiz_freq_cut = h;
3261 vert_freq_cut = v;
3262 avg_freq_cut = a;
3266 * Set algorithmic alignment weighting
3268 static void set_wmx(const char *e, const char *f, const char *d) {
3269 wmx_exec = e;
3270 wmx_file = f;
3271 wmx_defs = d;
3275 * Show frequency weights
3277 static void set_fl_show(const char *filename) {
3278 fw_output = filename;
3282 * Set transformation file loader.
3284 static void set_tload(tload_t *tl) {
3285 tload = tl;
3289 * Set transformation file saver.
3291 static void set_tsave(tsave_t *ts) {
3292 tsave = ts;
3296 * Get match statistics for frame N.
3298 static int match(int n) {
3299 update_to(n);
3301 if (n == latest)
3302 return latest_ok;
3303 else if (_keep)
3304 return kept_ok[n];
3305 else {
3306 assert(0);
3307 exit(1);
3312 * Message that old alignment data should be kept.
3314 static void keep() {
3315 assert (latest == -1);
3316 _keep = 1;
3320 * Get alignment for frame N.
3322 static transformation of(int n) {
3323 update_to(n);
3324 if (n == latest)
3325 return latest_t;
3326 else if (_keep)
3327 return kept_t[n];
3328 else {
3329 assert(0);
3330 exit(1);
3335 * Set calculation precision
3337 static void set_precise(int p) {
3338 precise_calculation = p;
3342 * Set the certainty-weighted flag.
3344 static void certainty_weighted(int flag) {
3345 certainty_weights = flag;
3349 * Set the global search type.
3351 static void gs(const char *type) {
3352 if (!strcmp(type, "local")) {
3353 _gs = 0;
3354 } else if (!strcmp(type, "inner")) {
3355 _gs = 1;
3356 } else if (!strcmp(type, "outer")) {
3357 _gs = 2;
3358 } else if (!strcmp(type, "all")) {
3359 _gs = 3;
3360 } else if (!strcmp(type, "central")) {
3361 _gs = 4;
3362 } else if (!strcmp(type, "defaults")) {
3363 _gs = 6;
3364 } else if (!strcmp(type, "points")) {
3365 _gs = 5;
3366 keep();
3367 } else {
3368 ui::get()->error("bad global search type");
3373 * Multi-alignment contiguity
3375 static void ma_cont(double value) {
3376 _ma_cont = value;
3380 * Multi-alignment cardinality
3382 static void ma_card(unsigned int value) {
3383 assert (value >= 1);
3384 _ma_card = value;
3388 * Set the minimum overlap for global searching
3390 static void gs_mo(ale_pos value, int _gs_mo_percent) {
3391 _gs_mo = value;
3392 gs_mo_percent = _gs_mo_percent;
3396 * Set alignment exclusion regions
3398 static void set_exclusion(exclusion *_ax_parameters, int _ax_count) {
3399 ax_count = _ax_count;
3400 ax_parameters = _ax_parameters;
3404 * Get match summary statistics.
3406 static ale_accum match_summary() {
3407 return match_sum / match_count;
3411 #endif