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.
29 #include "transformation.h"
36 #define D2_ALIGN_IMPRECISE_COVERAGE 0.3
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
56 static transformation
*kept_t
;
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.
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
;
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
;
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
189 int is_default
, old_is_default
;
192 transformation old_initial_alignment
;
193 transformation old_final_alignment
;
194 transformation default_initial_alignment
;
195 const image
*input_frame
;
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
;
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
;
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.
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.
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
;
340 static exclusion
*ax_parameters
;
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
;
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
{
365 const image
*certainty
;
366 const image
*aweight
;
367 exclusion
*ax_parameters
;
370 const image
*input_certainty
;
373 nl_scale_cluster
*nl_scale_clusters
;
377 * Check for exclusion region coverage in the reference
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])
393 * Check for exclusion region coverage in the input
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])
409 * Overlap function. Determines the number of pixels in areas where
410 * the arrays overlap. Uses the reference array's notion of pixel
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
))
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]));
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
))
455 && ti
<= c
.input
->height() - 1
457 && tj
<= c
.input
->width() - 1
458 && c
.certainty
->get_pixel(i
, j
)[0] != 0)
466 * Calculate the region associated with the current multi-alignment
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
);
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
))
489 while ((q
= t
->get_query_point((int) (i
+ offset
[0]),
490 (int) (j
+ offset
[1]))).defined()) {
495 if (input_excluded(ti
, tj
, si
.ax_parameters
, ax_count
))
499 && ti
<= si
.input
->height() - 1
501 && tj
<= si
.input
->width() - 1
502 && si
.certainty
->get_pixel(i
, j
)[0] != 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
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) +
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:
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
560 * For subdomain calculations, we vary the seed by adding the subdomain
567 unsigned int index_max
;
576 mc_iterate(int _i_min
, int _i_max
, int _j_min
, int _j_max
, unsigned int subdomain
)
586 index_max
= (i_max
- i_min
) * (j_max
- j_min
);
588 if (index_max
< 500 || precise_calculation
)
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
)) ));
606 return index
/ (j_max
- j_min
) + i_min
;
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
)) ));
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
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
646 transformation offset
;
653 ale_accum centroid
[2], centroid_divisor
;
654 ale_accum de_centroid
[2], de_centroid_v
, de_sum
;
661 min
= point::posinf();
662 max
= point::neginf();
666 centroid_divisor
= 0;
676 void init(transformation _offset
, ale_pos _perturb
) {
683 * Required for STL sanity.
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() {
716 init(_run
.offset
, _run
.perturb
);
724 run
&operator=(const run
&_run
) {
729 init(_run
.offset
, _run
.perturb
);
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 };
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
);
762 p
[0] = c
.input
->get_bl(t
);
766 p
[1] = c
.input
->get_bl(u
);
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
);
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
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.
847 for (int k
= 0; k
< 3; 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
);
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
);
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));
892 point
get_error_centroid() {
893 point result
= point(de_centroid
[0] / de_sum
, de_centroid
[1] / de_sum
);
898 ale_pos
get_error_perturb() {
899 ale_pos result
= de_centroid_v
/ de_sum
;
907 * When non-empty, runs.front() is best, runs.back() is
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
;
928 int i_min
, i_max
, j_min
, j_max
;
932 int get_current_index() const {
934 return runs
[0].offset
.get_current_index();
937 struct scale_cluster si
;
941 std::vector
<ale_pos
> perturb_multipliers
;
944 void diff(struct scale_cluster c
, ale_pos perturb
,
946 int _ax_count
, int f
) {
948 if (runs
.size() == 2)
951 runs
.push_back(run(t
, perturb
));
954 ax_count
= _ax_count
;
957 ui::get()->d2_align_sample_start();
959 if (interpolant
!= NULL
)
960 interpolant
->set_parameters(t
, c
.input
, c
.accum
->offset());
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
);
973 subdomain_args
*args
= new subdomain_args
[N
];
975 for (int ti
= 0; ti
< N
; ti
++) {
977 args
[ti
].runs
= runs
;
978 args
[ti
].ax_count
= ax_count
;
980 args
[ti
].i_min
= (c
.accum
->height() * ti
) / N
;
981 args
[ti
].i_max
= (c
.accum
->height() * (ti
+ 1)) / N
;
983 args
[ti
].j_max
= c
.accum
->width();
984 args
[ti
].subdomain
= ti
;
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
]);
990 diff_subdomain(&args
[ti
]);
994 for (int ti
= 0; ti
< N
; ti
++) {
996 pthread_join(threads
[ti
], NULL
);
998 runs
.back().add(args
[ti
].runs
.back());
1003 ui::get()->d2_align_sample_stop();
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
);
1019 for (unsigned int r
= 0; r
< t_array
.size(); r
++)
1020 diff(si
, p_array
[r
], t_array
[r
], ax_count
, frame
);
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);
1052 runs
[0].rescale(scale
);
1057 void push_element() {
1058 assert(runs
.size() == 1);
1060 runs
[0].offset
.push_element();
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
);
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
);
1088 diff_stat_t
&operator=(const diff_stat_t
&dst
) {
1090 * Copy run information.
1093 old_runs
= dst
.old_runs
;
1096 * Copy diff variables
1099 ax_count
= dst
.ax_count
;
1101 perturb_multipliers
= dst
.perturb_multipliers
;
1106 diff_stat_t(const diff_stat_t
&dst
) : runs(), old_runs(),
1107 perturb_multipliers() {
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
¶m
) {
1127 return (get_error() != param
.get_error());
1130 int operator==(diff_stat_t
¶m
) {
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();
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
)
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
))
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(),
1224 test_t
.rotate(centroid
+ si
.accum
->offset(),
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
);
1261 test_t
.snap(adj_p
/ 2);
1263 set
->push_back(test_t
);
1264 multipliers
.erase(multipliers
.begin());
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
)
1289 transformation test_t
= get_offset();
1291 test_t
.bd_modify(d
, adj_s
);
1293 set
->push_back(test_t
);
1299 assert(runs
.size() == 2);
1305 assert(runs
.size() == 2);
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
);
1327 if (finite(adj_p
/ test
.get_error_perturb()))
1328 perturb_multipliers
.push_back(adj_p
/ test
.get_error_perturb());
1330 perturb_multipliers
.push_back(1);
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
1350 && old_runs
.count(ori
)
1351 && old_runs
[ori
].offset
== t_set
[i
])
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
++) {
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;
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]));
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;
1398 && runs
[1].get_error() < runs
[0].get_error()
1399 && perturb_multipliers
[i
]
1400 / perturb_multipliers_original
[i
] < 2) {
1408 if (runs
.size() > 1)
1411 if (!found_unreliable
)
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())
1428 calculate_element_region();
1430 if (t
->is_nontrivial())
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()) {
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
{
1470 struct scale_cluster c
;
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
))
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
))
1515 && q
[0] <= c
.input
->height() - 1
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
);
1522 b
= c
.input
->get_bl(q
);
1524 pixel weight
= ((c
.aweight
&& pass_number
)
1525 ? c
.aweight
->get_pixel(i
, j
)
1528 ? ppow(c
.certainty
->get_pixel(i
, j
)
1529 * c
.input_certainty
->get_bl(q
, 1), 0.5)
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
++) {
1547 exposure_ratio_iterate(pixel_accum
*_asum
,
1549 struct scale_cluster _c
,
1552 int _pass_number
) : decompose_domain(0, _c
.accum
->height(),
1553 0, _c
.accum
->width()){
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],
1582 pixel_accum
asum(0, 0, 0), bsum(0, 0, 0);
1584 exposure_ratio_iterate
eri(&asum
, &bsum
, c
, t
, ax_count
, pass_number
);
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],
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
));
1613 ui::get()->memory_error("exclusion regions");
1615 for (int idx
= 0; idx
< local_ax_count
; idx
++)
1616 dest
[idx
] = source
[idx
];
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
));
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
)
1640 dest
[*local_ax_count
] = ax_parameters
[idx
];
1642 (*local_ax_count
)++;
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
)
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
)
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
)
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
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");
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());
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
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
);
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
) {
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
];
1826 point_sum
+= kept_t
[j
].transform_unscaled(pp
)
1827 / kept_t
[j
].scale();
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())
1857 other_centroid
+= other_c
;
1858 this_centroid
+= this_c
;
1864 *current
= point::undefined();
1865 *previous
= point::undefined();
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
) {
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())
1892 err
+= p_ref
.lengthtosq(p_cur
);
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)
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
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
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
);
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()) {
2016 ui::get()->set_match(here
->get_error());
2017 ui::get()->set_offset(here
->get_offset());
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
;
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
);
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) {
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) {
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
) {
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
) {
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
)
2128 if (!(match_threshold
>= 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
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
2170 local_lower
= perturb_lower
;
2172 if (perturb_upper_percent
)
2173 local_upper
= perturb_upper
2178 local_upper
= perturb_upper
;
2180 local_upper
= pow(2, floor(log(local_upper
) / log(2)));
2183 local_gs_mo
= _gs_mo
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
2197 double step_variable
= local_upper
;
2198 while (step_variable
>= local_lower
) {
2203 ui::get()->set_steps(step_count
);
2205 ale_pos perturb
= local_upper
;
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.
2237 struct scale_cluster
*scale_clusters
= init_clusters(m
,
2238 scale_factor
, input_frame
, steps
,
2242 * Initialize variables used in the main loop.
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
2269 element
->default_initial_alignment
.set_dimensions(input_frame
);
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,
2298 &element
->is_default
,
2299 offset
.get_current_index() == 0);
2303 offset
.set_current_index(0);
2305 ui::get()->set_offset(offset
);
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
;
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))
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
--)
2369 set_exposure_ratio(m
, scale_clusters
[0], o
, local_ax_count
, 0);
2373 * Alignment statistics.
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
--)
2424 * Determine centroid data
2427 point current
, previous
;
2428 centroids(m
, ¤t
, &previous
);
2430 if (current
.defined() && previous
.defined()) {
2432 o
.set_dimensions(input_frame
);
2433 o
.translate((previous
- current
) * o
.scale());
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))
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
) {
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
;
2472 * Determine projective parameters through a local
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;
2488 while (is_improved
) {
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
) {
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
);
2504 test_v
= cp_rms_error(m
, test_t
);
2506 if (test_v
< lowest_error
) {
2507 lowest_error
= test_v
;
2519 set_exposure_ratio(m
, scale_clusters
[0], o
, local_ax_count
, 0);
2521 for (int k
= lod
; k
> 0; k
--)
2524 here
.diff(si
, perturb
, o
, local_ax_count
, m
);
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
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))
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
,
2577 if (here
.get_offset() == old_here
.get_offset())
2582 if (stable_count
== 3) {
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;
2594 here
.set_current_index(0);
2596 element
->is_primary
= 1;
2603 * Work with images twice as large
2607 si
= scale_clusters
[lod
];
2610 * Rescale the transforms.
2613 here
.rescale(2, si
);
2614 element
->default_initial_alignment
.rescale(2);
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();
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);
2655 ui::get()->postmatching();
2656 offset
.use_full_support();
2657 here
.diff(scale_clusters
[0], perturb
, offset
, local_ax_count
, m
);
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
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) {
2712 if (is_fail_default
)
2713 offset
= element
->default_initial_alignment
;
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);
2742 * Update match statistics.
2745 match_sum
+= (1 - here
.get_error()) * 100;
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;
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
)
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
)
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() {
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
)
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
);
2850 int exit_status
= 1;
2852 execlp(wmx_exec
, wmx_exec
, wmx_file
, wmx_defs
, NULL
);
2853 ui::get()->exec_failure(wmx_exec
, wmx_file
, wmx_defs
);
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
;
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
);
2876 * Update alignment weights with frequency weights
2878 static void fw_update() {
2880 if (horiz_freq_cut
== 0
2881 && vert_freq_cut
== 0
2882 && avg_freq_cut
== 0)
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
);
2902 fftw_plan pf
= fftw_plan_dft_2d(rows
, cols
,
2904 FFTW_FORWARD
, FFTW_ESTIMATE
);
2906 fftw_plan pb
= fftw_plan_dft_2d(rows
, cols
,
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
];
2917 hipass(rows
, cols
, inout
);
2920 for (int i
= 0; i
< rows
* cols
; i
++) {
2922 alignment_weights
->pix(i
/ cols
, i
% cols
)[k
] = fabs(inout
[i
][0] / (rows
* cols
));
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));
2931 fftw_destroy_plan(pf
);
2932 fftw_destroy_plan(pb
);
2935 if (fw_output
!= NULL
)
2936 image_rw::write_image(fw_output
, alignment_weights
);
2941 * Update alignment to frame N.
2943 static void update_to(int n
) {
2945 assert (n
<= latest
+ 1);
2948 static std::vector
<element_t
> elements
;
2955 * Handle the initial frame
2958 elements
[0].input_frame
= image_rw::open(n
);
2960 const image
*i
= elements
[0].input_frame
;
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);
2969 kept_t
= new transformation
[image_rw::count()];
2970 kept_ok
= (int *) malloc(image_rw::count()
2975 if (!kept_t
|| !kept_ok
)
2976 ui::get()->memory_error("alignment");
2986 elements
[0].default_initial_alignment
= result
;
2992 for (int i
= latest
+ 1; i
<= n
; i
++) {
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();
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
]);
3023 if (elements
.size() > _ma_card
)
3024 elements
.resize(_ma_card
);
3030 * Set the control point count
3032 static void set_cp_count(unsigned int n
) {
3033 assert (cp_array
== NULL
);
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
) {
3049 static void exp_register() {
3054 * Register exposure only based on metadata
3056 static void exp_meta_only() {
3061 * Don't register exposure
3063 static void exp_noregister() {
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
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
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() {
3117 * Perturb source coordinates.
3119 static void perturb_source() {
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.
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
3158 channel_alignment_type
= 2;
3162 * Error metric exponent
3165 static void set_metric_exponent(float me
) {
3166 metric_exponent
= me
;
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
) {
3183 perturb_lower_percent
= plp
;
3186 static void set_perturb_upper(ale_pos pu
, int pup
) {
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
) {
3213 * Barrel distortion maximum rate of change
3216 static void set_bda_rate(ale_pos m
) {
3224 static void set_lod_max(int lm
) {
3229 * Set the scale factor
3231 static void set_scale(ale_pos s
) {
3236 * Set reference rendering to align against
3238 static void set_reference(render
*r
) {
3243 * Set the interpolant
3245 static void set_interpolant(filter::scaled_filter
*f
) {
3250 * Set alignment weights image
3252 static void set_weight_map(const image
*i
) {
3257 * Set frequency cuts
3259 static void set_frequency_cut(double h
, double v
, double a
) {
3266 * Set algorithmic alignment weighting
3268 static void set_wmx(const char *e
, const char *f
, const char *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
) {
3289 * Set transformation file saver.
3291 static void set_tsave(tsave_t
*ts
) {
3296 * Get match statistics for frame N.
3298 static int match(int n
) {
3312 * Message that old alignment data should be kept.
3314 static void keep() {
3315 assert (latest
== -1);
3320 * Get alignment for frame N.
3322 static transformation
of(int n
) {
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")) {
3354 } else if (!strcmp(type
, "inner")) {
3356 } else if (!strcmp(type
, "outer")) {
3358 } else if (!strcmp(type
, "all")) {
3360 } else if (!strcmp(type
, "central")) {
3362 } else if (!strcmp(type
, "defaults")) {
3364 } else if (!strcmp(type
, "points")) {
3368 ui::get()->error("bad global search type");
3373 * Multi-alignment contiguity
3375 static void ma_cont(double value
) {
3380 * Multi-alignment cardinality
3382 static void ma_card(unsigned int value
) {
3383 assert (value
>= 1);
3388 * Set the minimum overlap for global searching
3390 static void gs_mo(ale_pos value
, int _gs_mo_percent
) {
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
;