1 // Copyright 2002, 2004 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
4 /* This file is part of the Anti-Lamenessing Engine.
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * align.h: Handle alignment of frames.
29 #include "transformation.h"
40 * Private data members
43 static ale_pos scale_factor
;
46 * Original frame transformation
48 static transformation orig_t
;
51 * Keep data older than latest
54 static transformation
*kept_t
;
58 * Transformation file handlers
61 static tload_t
*tload
;
62 static tsave_t
*tsave
;
65 * Control point variables
68 static const point
**cp_array
;
69 static unsigned int cp_count
;
72 * Reference rendering to align against
75 static render
*reference
;
76 static filter::scaled_filter
*interpolant
;
77 static const image
*reference_image
;
78 static const image
*reference_defined
;
81 * Per-pixel alignment weight map
84 static const image
*weight_map
;
87 * Frequency-dependent alignment weights
90 static double horiz_freq_cut
;
91 static double vert_freq_cut
;
92 static double avg_freq_cut
;
93 static const char *fw_output
;
96 * Algorithmic alignment weighting
99 static const char *wmx_exec
;
100 static const char *wmx_file
;
101 static const char *wmx_defs
;
104 * Consolidated alignment weights
106 * The final value of alignment_weights_const is the canonical weight
107 * set. If alignment_weights_const is set but alignment_weights is
108 * not, then the memory is not ours, and the object should not be
109 * modified or deleted.
112 static image
*alignment_weights
;
113 static const image
*alignment_weights_const
;
116 * Latest transformation.
119 static transformation latest_t
;
122 * Flag indicating whether the latest transformation
123 * resulted in a match.
126 static int latest_ok
;
129 * Frame number most recently aligned.
135 * Exposure registration
137 * 0. Preserve the original exposure of images.
139 * 1. Match exposure between images.
141 * 2. Use only image metadata for registering exposure.
144 static int _exp_register
;
149 * 0. Translation only. Only adjust the x and y position of images.
150 * Do not rotate input images or perform projective transformations.
152 * 1. Euclidean transformations only. Adjust the x and y position
153 * of images and the orientation of the image about the image center.
155 * 2. Perform general projective transformations. See the file gpt.h
156 * for more information about general projective transformations.
159 static int alignment_class
;
162 * Default initial alignment.
164 * 0. Identity transformation.
166 * 1. Most recently accepted frame's final transformation.
169 static int default_initial_alignment_type
;
170 static transformation default_initial_alignment
;
173 * Projective group behavior
175 * 0. Perturb in output coordinates.
177 * 1. Perturb in source coordinates
180 static int perturb_type
;
183 * Helper variables for new --follow semantics (as of 0.5.0).
185 * These variables implement delta following. The change between the
186 * non-default old initial alignment and old final alignment is used to
187 * adjust the non-default current initial alignment. If either the old
188 * or new initial alignment is a default alignment, the old --follow
189 * semantics are preserved.
192 static int is_default
, old_is_default
;
194 static transformation old_initial_alignment
;
195 static transformation old_final_alignment
;
198 * Alignment for failed frames -- default or optimal?
200 * A frame that does not meet the match threshold can be assigned the
201 * best alignment found, or can be assigned its alignment default.
204 static int is_fail_default
;
209 * 0. Align images with an error contribution from each color channel.
211 * 1. Align images with an error contribution only from the green channel.
212 * Other color channels do not affect alignment.
214 * 2. Align images using a summation of channels. May be useful when dealing
215 * with images that have high frequency color ripples due to color aliasing.
218 static int channel_alignment_type
;
221 * Error metric exponent
224 static float metric_exponent
;
230 static float match_threshold
;
233 * Perturbation lower and upper bounds.
236 static ale_pos perturb_lower
;
237 static int perturb_lower_percent
;
238 static ale_pos perturb_upper
;
239 static int perturb_upper_percent
;
242 * Maximum level-of-detail scale factor is 2^lod_max/perturb.
248 * Maximum rotational perturbation
251 static ale_pos rot_max
;
254 * Barrel distortion alignment multiplier
257 static ale_pos bda_mult
;
260 * Barrel distortion maximum adjustment rate
263 static ale_pos bda_rate
;
266 * Alignment match sum
269 static ale_accum match_sum
;
272 * Alignment match count.
275 static int match_count
;
278 * Monte Carlo parameter
280 * 0. Don't use monte carlo alignment sampling.
282 * (0,1]. Select, on average, a number of pixels which is the
283 * specified fraction of the number of pixels in the accumulated image.
289 * Certainty weight flag
291 * 0. Don't use certainty weights for alignment.
293 * 1. Use certainty weights for alignment.
296 static int certainty_weights
;
299 * Global search parameter
301 * 0. Local: Local search only.
302 * 1. Inner: Alignment reference image inner region
303 * 2. Outer: Alignment reference image outer region
304 * 3. All: Alignment reference image inner and outer regions.
305 * 4. Central: Inner if possible; else, best of inner and outer.
306 * 5. Points: Align by control points.
312 * Minimum overlap for global searches
315 static unsigned int _gs_mo
;
321 static exclusion
*ax_parameters
;
325 * Type for scale cluster.
328 struct scale_cluster
{
330 const image
*defined
;
331 const image
*aweight
;
332 exclusion
*ax_parameters
;
339 * Check for exclusion region coverage in the reference
342 static int ref_excluded(int i
, int j
, point offset
, exclusion
*params
, int param_count
) {
343 for (int idx
= 0; idx
< param_count
; idx
++)
344 if (params
[idx
].type
== exclusion::RENDER
345 && i
+ offset
[0] >= params
[idx
].x
[0]
346 && i
+ offset
[0] <= params
[idx
].x
[1]
347 && j
+ offset
[1] >= params
[idx
].x
[2]
348 && j
+ offset
[1] <= params
[idx
].x
[3])
355 * Check for exclusion region coverage in the input
358 static int input_excluded(ale_pos ti
, ale_pos tj
, exclusion
*params
, int param_count
) {
359 for (int idx
= 0; idx
< param_count
; idx
++)
360 if (params
[idx
].type
== exclusion::FRAME
361 && ti
>= params
[idx
].x
[0]
362 && ti
<= params
[idx
].x
[1]
363 && tj
>= params
[idx
].x
[2]
364 && tj
<= params
[idx
].x
[3])
371 * Overlap function. Determines the number of pixels in areas where
372 * the arrays overlap. Uses the reference array's notion of pixel
375 static unsigned int overlap(struct scale_cluster c
, transformation t
, int ax_count
) {
376 assert (reference_image
);
378 unsigned int result
= 0;
380 point offset
= c
.accum
->offset();
382 for (unsigned int i
= 0; i
< c
.accum
->height(); i
++)
383 for (unsigned int j
= 0; j
< c
.accum
->width(); j
++) {
385 if (ref_excluded(i
, j
, offset
, c
.ax_parameters
, ax_count
))
394 q
= (c
.input_scale
< 1.0 && interpolant
== NULL
)
395 ? t
.scaled_inverse_transform(
396 point(i
+ offset
[0], j
+ offset
[1]))
397 : t
.unscaled_inverse_transform(
398 point(i
+ offset
[0], j
+ offset
[1]));
404 * Check that the transformed coordinates are within
405 * the boundaries of array c.input, and check that the
406 * weight value in the accumulated array is nonzero,
407 * unless we know it is nonzero by virtue of the fact
408 * that it falls within the region of the original
409 * frame (e.g. when we're not increasing image
410 * extents). Also check for frame exclusion.
413 if (input_excluded(ti
, tj
, c
.ax_parameters
, ax_count
))
417 && ti
<= c
.input
->height() - 1
419 && tj
<= c
.input
->width() - 1
420 && c
.defined
->get_pixel(i
, j
)[0] != 0)
428 * Not-quite-symmetric difference function. Determines the difference in areas
429 * where the arrays overlap. Uses the reference array's notion of pixel positions.
431 * For the purposes of determining the difference, this function divides each
432 * pixel value by the corresponding image's average pixel magnitude, unless we
435 * a) Extending the boundaries of the image, or
437 * b) following the previous frame's transform
439 * If we are doing monte-carlo pixel sampling for alignment, we
440 * typically sample a subset of available pixels; otherwise, we sample
444 static ale_accum
diff(struct scale_cluster c
, transformation t
,
445 ale_pos _mc_arg
, int ax_count
, int f
) {
447 assert (reference_image
);
448 ale_accum result
= 0;
449 ale_accum divisor
= 0;
451 point offset
= c
.accum
->offset();
455 if (interpolant
!= NULL
)
456 interpolant
->set_parameters(t
, c
.input
, offset
);
459 * We always use the same code for exhaustive and Monte Carlo
460 * pixel sampling, setting _mc_arg = 1 when all pixels are to
464 if (_mc_arg
<= 0 || _mc_arg
>= 1)
468 int index_max
= c
.accum
->height() * c
.accum
->width();
471 * We use a random process for which the expected
472 * number of sampled pixels is +/- .000003 from mc_arg
473 * in the range [.005,.995] for an image with 100,000
474 * pixels. (The actual number may still deviate from
475 * the expected number by more than this amount,
476 * however.) The method is as follows:
478 * We have mc_arg == USE/ALL, or (expected # pixels to
479 * use)/(# total pixels). We derive from this
482 * SKIP/USE == (SKIP/ALL)/(USE/ALL) == (1 - (USE/ALL))/(USE/ALL)
484 * Once we have SKIP/USE, we know the expected number
485 * of pixels to skip in each iteration. We use a random
486 * selection process that provides SKIP/USE close to
487 * this calculated value.
489 * If we can draw uniformly to select the number of
490 * pixels to skip, we do. In this case, the maximum
491 * number of pixels to skip is twice the expected
494 * If we cannot draw uniformly, we still assign equal
495 * probability to each of the integer values in the
496 * interval [0, 2 * (SKIP/USE)], but assign an unequal
497 * amount to the integer value ceil(2 * SKIP/USE) + 1.
500 ale_pos u
= (1 - _mc_arg
) / _mc_arg
;
502 ale_pos mc_max
= (floor(2*u
) * (1 + floor(2*u
)) + 2*u
)
503 / (2 + 2 * floor(2*u
) - 2*u
);
506 * Reseed the random number generator; we want the
507 * same set of pixels to be used when comparing two
508 * alignment options. If we wanted to avoid bias from
509 * repeatedly utilizing the same seed, we could seed
510 * with the number of the frame most recently aligned:
514 * However, in cursory tests, it seems okay to just use
515 * the default seed of 1, and so we do this, since it
516 * is simpler; both of these approaches to reseeding
517 * achieve better results than not reseeding. (1 is
518 * the default seed according to the GNU Manual Page
524 for(index
= -1 + (int) ceil((mc_max
+1)
525 * ( (1 + ((ale_pos
) rand()) )
526 / (1 + ((ale_pos
) RAND_MAX
)) ));
528 index
+= (int) ceil((mc_max
+1)
529 * ( (1 + ((ale_pos
) rand()) )
530 / (1 + ((ale_pos
) RAND_MAX
)) ))){
532 i
= index
/ c
.accum
->width();
533 j
= index
% c
.accum
->width();
536 * Check for exclusion in render coordinates.
539 if (ref_excluded(i
, j
, offset
, c
.ax_parameters
, ax_count
))
548 q
= (c
.input_scale
< 1.0 && interpolant
== NULL
)
549 ? t
.scaled_inverse_transform(
550 point(i
+ offset
[0], j
+ offset
[1]))
551 : t
.unscaled_inverse_transform(
552 point(i
+ offset
[0], j
+ offset
[1]));
558 * Check that the transformed coordinates are within
559 * the boundaries of array c.input and that they
560 * are not subject to exclusion.
562 * Also, check that the weight value in the accumulated array
563 * is nonzero, unless we know it is nonzero by virtue of the
564 * fact that it falls within the region of the original frame
565 * (e.g. when we're not increasing image extents).
568 if (input_excluded(ti
, tj
, c
.ax_parameters
, ax_count
))
572 && ti
<= c
.input
->height() - 1
574 && tj
<= c
.input
->width() - 1
575 && c
.defined
->get_pixel(i
, j
)[0] != 0) {
577 pixel pa
= c
.accum
->get_pixel(i
, j
);
581 if (interpolant
!= NULL
)
582 interpolant
->filtered(i
, j
, &pb
, &weight
, 1, f
);
585 c
.input
->get_bl(point(ti
, tj
), result
);
594 if (certainty_weights
== 0)
595 weight
= pixel(1, 1, 1);
597 if (c
.aweight
!= NULL
)
598 weight
*= c
.aweight
->get_pixel(i
, j
);
601 * Determine alignment type.
604 if (channel_alignment_type
== 0) {
606 * Align based on all channels.
610 for (k
= 0; k
< 3; k
++) {
611 ale_real achan
= pa
[k
];
612 ale_real bchan
= pb
[k
];
614 result
+= weight
[k
] * pow(fabs(achan
- bchan
), metric_exponent
);
615 divisor
+= weight
[k
] * pow(achan
> bchan
? achan
: bchan
, metric_exponent
);
617 } else if (channel_alignment_type
== 1) {
619 * Align based on the green channel.
622 ale_real achan
= pa
[1];
623 ale_real bchan
= pb
[1];
625 result
+= weight
[1] * pow(fabs(achan
- bchan
), metric_exponent
);
626 divisor
+= weight
[1] * pow(achan
> bchan
? achan
: bchan
, metric_exponent
);
627 } else if (channel_alignment_type
== 2) {
629 * Align based on the sum of all channels.
636 for (k
= 0; k
< 3; k
++) {
639 wsum
+= weight
[k
] / 3;
642 result
+= wsum
* pow(fabs(asum
- bsum
), metric_exponent
);
643 divisor
+= wsum
* pow(asum
> bsum
? asum
: bsum
, metric_exponent
);
647 return pow(result
/ divisor
, 1/metric_exponent
);
651 * Adjust exposure for an aligned frame B against reference A.
653 * Expects full-LOD images.
655 * This function is a bit of a mess, as it reflects rather ad-hoc rules
656 * regarding what seems to work w.r.t. certainty. Using certainty in the
657 * first pass seems to result in worse alignment, while not using certainty
658 * in the second pass results in incorrect determination of exposure.
660 * [Note that this may have been due to a bug in certainty determination
661 * within this function.]
663 static void set_exposure_ratio(unsigned int m
, struct scale_cluster c
,
664 transformation t
, int ax_count
, int pass_number
) {
666 if (_exp_register
== 2) {
670 ale_real gain_multiplier
= image_rw::exp(m
).get_gain_multiplier();
671 pixel multiplier
= pixel(gain_multiplier
, gain_multiplier
, gain_multiplier
);
673 image_rw::exp(m
).set_multiplier(multiplier
);
674 ui::get()->exp_multiplier(multiplier
[0],
681 pixel_accum asum
, bsum
;
683 point offset
= c
.accum
->offset();
685 for (unsigned int i
= 0; i
< c
.accum
->height(); i
++)
686 for (unsigned int j
= 0; j
< c
.accum
->width(); j
++) {
688 if (ref_excluded(i
, j
, offset
, c
.ax_parameters
, ax_count
))
697 q
= (c
.input_scale
< 1.0 && interpolant
== NULL
)
698 ? t
.scaled_inverse_transform(
699 point(i
+ offset
[0], j
+ offset
[1]))
700 : t
.unscaled_inverse_transform(
701 point(i
+ offset
[0], j
+ offset
[1]));
704 * Check that the transformed coordinates are within
705 * the boundaries of array c.input, that they are not
706 * subject to exclusion, and that the weight value in
707 * the accumulated array is nonzero.
710 if (input_excluded(q
[0], q
[1], c
.ax_parameters
, ax_count
))
714 && q
[0] <= c
.input
->height() - 1
716 && q
[1] <= c
.input
->width() - 1
717 && c
.defined
->get_pixel(i
, j
).minabs_norm() != 0) {
718 pixel a
= c
.accum
->get_pixel(i
, j
);
721 c
.input
->get_bl(q
, b
);
724 pixel weight
= (c
.aweight
725 ? c
.aweight
->get_pixel(i
, j
)
727 * ((!certainty_weights
&& pass_number
)
728 ? c
.defined
->get_pixel(i
, j
)
734 pixel weight
= pixel(1, 1, 1);
738 bsum
+= b
[0] * weight
;
742 // std::cerr << (asum / bsum) << " ";
744 pixel_accum new_multiplier
;
746 new_multiplier
= asum
/ bsum
* image_rw::exp(m
).get_multiplier();
748 if (finite(new_multiplier
[0])
749 && finite(new_multiplier
[1])
750 && finite(new_multiplier
[2])) {
751 image_rw::exp(m
).set_multiplier(new_multiplier
);
752 ui::get()->exp_multiplier(new_multiplier
[0],
759 * Copy all ax parameters.
761 static exclusion
*copy_ax_parameters(int local_ax_count
, exclusion
*source
) {
763 exclusion
*dest
= (exclusion
*) malloc(local_ax_count
* sizeof(exclusion
));
768 ui::get()->memory_error("exclusion regions");
770 for (int idx
= 0; idx
< local_ax_count
; idx
++)
771 dest
[idx
] = source
[idx
];
777 * Copy ax parameters according to frame.
779 static exclusion
*filter_ax_parameters(int frame
, int *local_ax_count
) {
781 exclusion
*dest
= (exclusion
*) malloc(ax_count
* sizeof(exclusion
));
786 ui::get()->memory_error("exclusion regions");
790 for (int idx
= 0; idx
< ax_count
; idx
++) {
791 if (ax_parameters
[idx
].x
[4] > frame
792 || ax_parameters
[idx
].x
[5] < frame
)
795 dest
[*local_ax_count
] = ax_parameters
[idx
];
803 static void scale_ax_parameters(int local_ax_count
, exclusion
*ax_parameters
,
804 ale_pos ref_scale
, ale_pos input_scale
) {
805 for (int i
= 0; i
< local_ax_count
; i
++) {
806 ale_pos scale
= (ax_parameters
[i
].type
== exclusion::RENDER
)
810 for (int n
= 0; n
< 6; n
++) {
811 ax_parameters
[i
].x
[n
] = (int) floor(ax_parameters
[i
].x
[n
]
818 * Prepare the next level of detail for ordinary images.
820 static const image
*prepare_lod(const image
*current
) {
824 return current
->scale_by_half("prepare_lod");
828 * Prepare the next level of detail for weighted images.
830 static const image
*prepare_lod(const image
*current
, const image
*weights
) {
834 return current
->scale_by_half(weights
, "prepare_lod");
838 * Prepare the next level of detail for definition maps.
840 static const image
*prepare_lod_def(const image
*current
) {
843 return current
->defined_scale_by_half("prepare_lod_def");
847 * Initialize the scale cluster data structure.
849 static struct scale_cluster
*init_clusters(int frame
, ale_real scale_factor
,
850 const image
*input_frame
, unsigned int steps
,
851 int *local_ax_count
) {
854 * Allocate memory for the array.
857 struct scale_cluster
*scale_clusters
=
858 (struct scale_cluster
*) malloc(steps
* sizeof(struct scale_cluster
));
860 assert (scale_clusters
);
863 ui::get()->memory_error("alignment");
866 * Prepare images and exclusion regions for the highest level
870 scale_clusters
[0].accum
= reference_image
;
872 ui::get()->constructing_lod_clusters(0.0);
873 scale_clusters
[0].input_scale
= scale_factor
;
874 if (scale_factor
< 1.0 && interpolant
== NULL
)
875 scale_clusters
[0].input
= input_frame
->scale(scale_factor
, "alignment");
877 scale_clusters
[0].input
= input_frame
;
879 scale_clusters
[0].defined
= reference_defined
;
880 scale_clusters
[0].aweight
= alignment_weights_const
;
881 scale_clusters
[0].ax_parameters
= filter_ax_parameters(frame
, local_ax_count
);
883 scale_ax_parameters(*local_ax_count
, scale_clusters
[0].ax_parameters
, scale_factor
,
884 (scale_factor
< 1.0 && interpolant
== NULL
) ? scale_factor
: 1);
887 * Prepare reduced-detail images and exclusion
891 for (unsigned int step
= 1; step
< steps
; step
++) {
892 ui::get()->constructing_lod_clusters(step
);
893 scale_clusters
[step
].accum
= prepare_lod(scale_clusters
[step
- 1].accum
, scale_clusters
[step
- 1].aweight
);
894 scale_clusters
[step
].defined
= prepare_lod_def(scale_clusters
[step
- 1].defined
);
895 scale_clusters
[step
].aweight
= prepare_lod(scale_clusters
[step
- 1].aweight
);
896 scale_clusters
[step
].ax_parameters
897 = copy_ax_parameters(*local_ax_count
, scale_clusters
[step
- 1].ax_parameters
);
899 double sf
= scale_clusters
[step
- 1].input_scale
/ 2;
900 scale_clusters
[step
].input_scale
= sf
;
902 if (sf
>= 1.0 || interpolant
!= NULL
) {
903 scale_clusters
[step
].input
= scale_clusters
[step
- 1].input
;
904 scale_ax_parameters(*local_ax_count
, scale_clusters
[step
].ax_parameters
, 0.5, 1);
905 } else if (sf
> 0.5) {
906 scale_clusters
[step
].input
= scale_clusters
[step
- 1].input
->scale(sf
, "alignment");
907 scale_ax_parameters(*local_ax_count
, scale_clusters
[step
].ax_parameters
, 0.5, sf
);
909 scale_clusters
[step
].input
= scale_clusters
[step
- 1].input
->scale(0.5, "alignment");
910 scale_ax_parameters(*local_ax_count
, scale_clusters
[step
].ax_parameters
, 0.5, 0.5);
914 return scale_clusters
;
918 * Destroy the first element in the scale cluster data structure.
920 static void final_clusters(struct scale_cluster
*scale_clusters
, ale_real scale_factor
,
921 unsigned int steps
) {
923 if (scale_clusters
[0].input_scale
< 1.0)
924 delete scale_clusters
[0].input
;
926 free((void *)scale_clusters
[0].ax_parameters
);
928 for (unsigned int step
= 1; step
< steps
; step
++) {
929 delete scale_clusters
[step
].accum
;
930 delete scale_clusters
[step
].defined
;
931 delete scale_clusters
[step
].aweight
;
933 if (scale_clusters
[step
].input_scale
< 1.0)
934 delete scale_clusters
[step
].input
;
936 free((void *)scale_clusters
[step
].ax_parameters
);
939 free(scale_clusters
);
943 * Calculate the centroid of a control point for the set of frames
944 * having index lower than m. Divide by any scaling of the output.
946 static point
unscaled_centroid(unsigned int m
, unsigned int p
) {
949 point
point_sum(0, 0);
950 ale_accum divisor
= 0;
952 for(unsigned int j
= 0; j
< m
; j
++) {
953 point pp
= cp_array
[p
][j
];
956 point_sum
+= kept_t
[j
].transform_unscaled(pp
)
963 return point::undefined();
965 return point_sum
/ divisor
;
969 * Calculate centroid of this frame, and of all previous frames,
970 * from points common to both sets.
972 static void centroids(unsigned int m
, point
*current
, point
*previous
) {
974 * Calculate the translation
976 point
other_centroid(0, 0);
977 point
this_centroid(0, 0);
980 for (unsigned int i
= 0; i
< cp_count
; i
++) {
981 point other_c
= unscaled_centroid(m
, i
);
982 point this_c
= cp_array
[i
][m
];
984 if (!other_c
.defined() || !this_c
.defined())
987 other_centroid
+= other_c
;
988 this_centroid
+= this_c
;
994 *current
= point::undefined();
995 *previous
= point::undefined();
999 *current
= this_centroid
/ divisor
;
1000 *previous
= other_centroid
/ divisor
;
1004 * Calculate the RMS error of control points for frame m, with
1005 * transformation t, against control points for earlier frames.
1007 static ale_accum
cp_rms_error(unsigned int m
, transformation t
) {
1011 ale_accum divisor
= 0;
1013 for (unsigned int i
= 0; i
< cp_count
; i
++)
1014 for (unsigned int j
= 0; j
< m
; j
++) {
1015 const point
*p
= cp_array
[i
];
1016 point p_ref
= kept_t
[j
].transform_unscaled(p
[j
]);
1017 point p_cur
= t
.transform_unscaled(p
[m
]);
1019 if (!p_ref
.defined() || !p_cur
.defined())
1022 err
+= p_ref
.lengthtosq(p_cur
);
1026 return sqrt(err
/ divisor
);
1030 * Align frame m against the reference.
1032 * XXX: the transformation class currently combines ordinary
1033 * transformations with scaling. This is somewhat convenient for
1034 * some things, but can also be confusing. This method, _align(), is
1035 * one case where special care must be taken to ensure that the scale
1036 * is always set correctly (by using the 'rescale' method).
1038 static ale_accum
_align(int m
, int local_gs
) {
1041 * Open the input frame.
1045 ui::get()->loading_file();
1046 const image
*input_frame
= image_rw::open(m
);
1049 * Local upper/lower data, possibly dependent on image
1053 ale_pos local_lower
, local_upper
;
1056 * Select the minimum dimension as the reference.
1059 ale_pos reference_size
= input_frame
->height();
1060 if (input_frame
->width() < reference_size
)
1061 reference_size
= input_frame
->width();
1063 if (perturb_lower_percent
)
1064 local_lower
= perturb_lower
1069 local_lower
= perturb_lower
;
1071 if (perturb_upper_percent
)
1072 local_upper
= perturb_upper
1077 local_upper
= perturb_upper
;
1079 local_upper
= pow(2, floor(log(local_upper
) / log(2)));
1082 * Logarithms aren't exact, so we divide repeatedly to discover
1083 * how many steps will occur, and pass this information to the
1088 double step_variable
= local_upper
;
1089 while (step_variable
>= local_lower
) {
1094 ui::get()->set_steps(step_count
);
1096 ale_pos perturb
= local_upper
;
1097 transformation offset
;
1102 kept_t
[latest
] = latest_t
;
1103 kept_ok
[latest
] = latest_ok
;
1107 * Maximum level-of-detail. Use a level of detail at most
1108 * 2^lod_diff finer than the adjustment resolution. lod_diff
1109 * is a synonym for lod_max.
1112 const int lod_diff
= lod_max
;
1115 * Determine how many levels of detail should be prepared.
1118 unsigned int steps
= (perturb
> pow(2, lod_max
))
1119 ? (unsigned int) (log(perturb
) / log(2)) - lod_max
+ 1 : 1;
1123 * Prepare multiple levels of detail.
1127 struct scale_cluster
*scale_clusters
= init_clusters(m
,
1128 scale_factor
, input_frame
, steps
,
1132 * Initialize variables used in the main loop.
1138 * Initialize the default initial transform
1141 if (default_initial_alignment_type
== 0) {
1144 * Follow the transformation of the original frame,
1145 * setting new image dimensions.
1148 default_initial_alignment
= orig_t
;
1149 default_initial_alignment
.set_dimensions(input_frame
);
1151 } else if (default_initial_alignment_type
== 1)
1154 * Follow previous transformation, setting new image
1158 default_initial_alignment
.set_dimensions(input_frame
);
1163 old_is_default
= is_default
;
1166 * Scale default initial transform for lod
1169 default_initial_alignment
.rescale(1 / pow(2, lod
));
1172 * Load any file-specified transformation
1175 offset
= tload_next(tload
, alignment_class
== 2, default_initial_alignment
, &is_default
);
1177 transformation new_offset
= offset
;
1179 if (!old_is_default
&& !is_default
&& default_initial_alignment_type
== 1) {
1182 * Implement new delta --follow semantics.
1184 * If we have a transformation T such that
1186 * prev_final == T(prev_init)
1190 * current_init_follow == T(current_init)
1192 * We can calculate T as follows:
1194 * T == prev_final(prev_init^-1)
1196 * Where ^-1 is the inverse operator.
1200 * Ensure that the lod for the old initial and final
1201 * alignments are equal to the lod for the new initial
1205 old_final_alignment
.rescale (1 / pow(2, lod
));
1206 old_initial_alignment
.rescale(1 / pow(2, lod
- old_lod
));
1208 if (alignment_class
== 0) {
1210 * Translational transformations
1213 ale_pos t0
= -old_initial_alignment
.eu_get(0) + old_final_alignment
.eu_get(0);
1214 ale_pos t1
= -old_initial_alignment
.eu_get(1) + old_final_alignment
.eu_get(1);
1216 new_offset
.eu_modify(0, t0
);
1217 new_offset
.eu_modify(1, t1
);
1219 } else if (alignment_class
== 1) {
1221 * Euclidean transformations
1224 ale_pos t2
= -old_initial_alignment
.eu_get(2) + old_final_alignment
.eu_get(2);
1226 new_offset
.eu_modify(2, t2
);
1228 point
p( offset
.scaled_height()/2 + offset
.eu_get(0) - old_initial_alignment
.eu_get(0),
1229 offset
.scaled_width()/2 + offset
.eu_get(1) - old_initial_alignment
.eu_get(1) );
1231 p
= old_final_alignment
.transform_scaled(p
);
1233 new_offset
.eu_modify(0, p
[0] - offset
.scaled_height()/2 - offset
.eu_get(0));
1234 new_offset
.eu_modify(1, p
[1] - offset
.scaled_width()/2 - offset
.eu_get(1));
1236 } else if (alignment_class
== 2) {
1238 * Projective transformations
1243 p
[0] = old_final_alignment
.transform_scaled(old_initial_alignment
1244 . scaled_inverse_transform(offset
.transform_scaled(point( 0 , 0 ))));
1245 p
[1] = old_final_alignment
.transform_scaled(old_initial_alignment
1246 . scaled_inverse_transform(offset
.transform_scaled(point(offset
.scaled_height(), 0 ))));
1247 p
[2] = old_final_alignment
.transform_scaled(old_initial_alignment
1248 . scaled_inverse_transform(offset
.transform_scaled(point(offset
.scaled_height(), offset
.scaled_width()))));
1249 p
[3] = old_final_alignment
.transform_scaled(old_initial_alignment
1250 . scaled_inverse_transform(offset
.transform_scaled(point( 0 , offset
.scaled_width()))));
1252 new_offset
.gpt_set(p
);
1256 old_initial_alignment
= offset
;
1258 offset
= new_offset
;
1260 ale_pos _mc_arg
= _mc
* pow(2, 2 * lod
);
1261 struct scale_cluster si
= scale_clusters
[lod
];
1264 * Projective adjustment value
1267 ale_pos adj_p
= (perturb
>= pow(2, lod_diff
))
1268 ? pow(2, lod_diff
) : (double) perturb
;
1271 * Pre-alignment exposure adjustment
1274 if (_exp_register
) {
1275 ui::get()->exposure_1();
1276 transformation o
= offset
;
1277 for (int k
= lod
; k
> 0; k
--)
1279 set_exposure_ratio(m
, scale_clusters
[0], o
, local_ax_count
, 0);
1283 * Current difference (error) value
1286 ui::get()->prematching();
1287 here
= diff(si
, offset
, _mc_arg
, local_ax_count
, m
);
1288 ui::get()->set_match(here
);
1291 * Current and modified barrel distortion parameters
1294 ale_pos current_bd
[BARREL_DEGREE
];
1295 ale_pos modified_bd
[BARREL_DEGREE
];
1296 offset
.bd_get(current_bd
);
1297 offset
.bd_get(modified_bd
);
1300 * Translational global search step
1303 if (perturb
>= local_lower
&& local_gs
!= 0 && local_gs
!= 5) {
1305 ui::get()->aligning(perturb
, lod
);
1307 transformation lowest_t
= offset
;
1308 ale_accum lowest_v
= here
;
1312 transformation offset_p
= offset
;
1314 if (!offset_p
.is_projective())
1315 offset_p
.eu_to_gpt();
1317 min
= max
= offset_p
.gpt_get(0);
1318 for (int p_index
= 1; p_index
< 4; p_index
++) {
1319 point p
= offset_p
.gpt_get(p_index
);
1330 point inner_min_t
= -min
;
1331 point inner_max_t
= -max
+ point(si
.accum
->height(), si
.accum
->width());
1332 point outer_min_t
= -max
+ point(adj_p
- 1, adj_p
- 1);
1333 point outer_max_t
= point(si
.accum
->height(), si
.accum
->width()) - point(adj_p
, adj_p
);
1335 if (local_gs
== 1 || local_gs
== 3 || local_gs
== 4) {
1341 for (ale_pos i
= inner_min_t
[0]; i
<= inner_max_t
[0]; i
+= adj_p
)
1342 for (ale_pos j
= inner_min_t
[1]; j
<= inner_max_t
[1]; j
+= adj_p
) {
1343 transformation t
= offset
;
1344 t
.translate(point(i
, j
));
1345 ale_accum v
= diff(si
, t
, _mc_arg
, local_ax_count
, m
);
1346 unsigned int ovl
= overlap(si
, t
, local_ax_count
);
1348 if ((v
< lowest_v
&& ovl
>= _gs_mo
)
1349 || (!finite(lowest_v
) && finite(v
))) {
1356 if (local_gs
== 2 || local_gs
== 3 || local_gs
== -1) {
1362 for (ale_pos i
= outer_min_t
[0]; i
<= outer_max_t
[0]; i
+= adj_p
)
1363 for (ale_pos j
= outer_min_t
[1]; j
< inner_min_t
[1]; j
+= adj_p
) {
1364 transformation t
= offset
;
1365 t
.translate(point(i
, j
));
1366 ale_accum v
= diff(si
, t
, _mc_arg
, local_ax_count
, m
);
1367 unsigned int ovl
= overlap(si
, t
, local_ax_count
);
1369 if ((v
< lowest_v
&& ovl
>= _gs_mo
)
1370 || (!finite(lowest_v
) && finite(v
))) {
1375 for (ale_pos i
= outer_min_t
[0]; i
<= outer_max_t
[0]; i
+= adj_p
)
1376 for (ale_pos j
= outer_max_t
[1]; j
> inner_max_t
[1]; j
-= adj_p
) {
1377 transformation t
= offset
;
1378 t
.translate(point(i
, j
));
1379 ale_accum v
= diff(si
, t
, _mc_arg
, local_ax_count
, m
);
1380 unsigned int ovl
= overlap(si
, t
, local_ax_count
);
1382 if ((v
< lowest_v
&& ovl
>= _gs_mo
)
1383 || (!finite(lowest_v
) && finite(v
))) {
1388 for (ale_pos i
= outer_min_t
[0]; i
< inner_min_t
[0]; i
+= adj_p
)
1389 for (ale_pos j
= outer_min_t
[1]; j
<= outer_max_t
[1]; j
+= adj_p
) {
1390 transformation t
= offset
;
1391 t
.translate(point(i
, j
));
1392 ale_accum v
= diff(si
, t
, _mc_arg
, local_ax_count
, m
);
1393 unsigned int ovl
= overlap(si
, t
, local_ax_count
);
1395 if ((v
< lowest_v
&& ovl
>= _gs_mo
)
1396 || (!finite(lowest_v
) && finite(v
))) {
1401 for (ale_pos i
= outer_max_t
[0]; i
> inner_max_t
[0]; i
-= adj_p
)
1402 for (ale_pos j
= outer_min_t
[1]; j
<= outer_max_t
[1]; j
+= adj_p
) {
1403 transformation t
= offset
;
1404 t
.translate(point(i
, j
));
1405 ale_accum v
= diff(si
, t
, _mc_arg
, local_ax_count
, m
);
1406 unsigned int ovl
= overlap(si
, t
, local_ax_count
);
1408 if ((v
< lowest_v
&& ovl
>= _gs_mo
)
1409 || (!finite(lowest_v
) && finite(v
))) {
1419 ui::get()->set_match(here
);
1423 * Control point alignment
1426 if (local_gs
== 5) {
1428 transformation o
= offset
;
1429 for (int k
= lod
; k
> 0; k
--)
1433 * Determine centroid data
1436 point current
, previous
;
1437 centroids(m
, ¤t
, &previous
);
1439 if (current
.defined() && previous
.defined()) {
1441 o
.set_dimensions(input_frame
);
1442 o
.translate((previous
- current
) * o
.scale());
1447 * Determine rotation for alignment classes other than translation.
1450 ale_accum lowest_error
= cp_rms_error(m
, o
);
1452 ale_pos rot_lower
= 2 * local_lower
1453 / sqrt(pow(scale_clusters
[0].input
->height(), 2)
1454 + pow(scale_clusters
[0].input
->width(), 2))
1458 if (alignment_class
> 0)
1459 for (ale_pos rot
= 30; rot
> rot_lower
; rot
/= 2)
1460 for (ale_pos srot
= -rot
; srot
<= rot
; srot
+= rot
* 2) {
1461 int is_improved
= 1;
1462 while (is_improved
) {
1464 transformation test_t
= o
;
1465 test_t
.rotate(current
* o
.scale(), srot
);
1466 ale_pos test_v
= cp_rms_error(m
, test_t
);
1468 if (test_v
< lowest_error
) {
1469 lowest_error
= test_v
;
1478 * Determine projective parameters through a local
1482 if (alignment_class
== 2) {
1483 ale_accum adj_p
= lowest_error
;
1485 if (adj_p
< local_lower
)
1486 adj_p
= local_lower
;
1488 while (adj_p
>= local_lower
) {
1489 transformation test_t
= o
;
1490 int is_improved
= 1;
1494 while (is_improved
) {
1497 for (int i
= 0; i
< 4; i
++)
1498 for (int j
= 0; j
< 2; j
++)
1499 for (adj_s
= -adj_p
; adj_s
<= adj_p
; adj_s
+= 2 * adj_p
) {
1503 if (perturb_type
== 0)
1504 test_t
.gpt_modify(j
, i
, adj_s
);
1505 else if (perturb_type
== 1)
1506 test_t
.gr_modify(j
, i
, adj_s
);
1510 test_v
= cp_rms_error(m
, test_t
);
1512 if (test_v
< lowest_error
) {
1513 lowest_error
= test_v
;
1525 set_exposure_ratio(m
, scale_clusters
[0], o
, local_ax_count
, 0);
1527 for (int k
= lod
; k
> 0; k
--)
1534 * Perturbation adjustment loop.
1537 while (perturb
>= local_lower
) {
1539 ui::get()->aligning(perturb
, lod
);
1544 * Orientational adjustment value in degrees.
1546 * Since rotational perturbation is now specified as an
1547 * arclength, we have to convert.
1550 ale_pos adj_o
= 2 * perturb
1551 / sqrt(pow(scale_clusters
[0].input
->height(), 2)
1552 + pow(scale_clusters
[0].input
->width(), 2))
1557 * Barrel distortion adjustment value
1560 ale_pos adj_b
= perturb
* bda_mult
;
1562 transformation test_t
;
1564 ale_accum old_here
= here
;
1566 if (alignment_class
< 2 && alignment_class
>= 0) {
1569 * Translational or euclidean transformation
1572 for (int i
= 0; i
< 2; i
++)
1573 for (adj_s
= -adj_p
; adj_s
<= adj_p
; adj_s
+= 2 * adj_p
) {
1577 test_t
.eu_modify(i
, adj_s
);
1579 test_d
= diff(si
, test_t
, _mc_arg
, local_ax_count
, m
);
1581 if (test_d
< here
|| (!finite(here
) && finite(test_d
))) {
1588 if (alignment_class
== 1 && adj_o
< rot_max
)
1589 for (adj_s
= -adj_o
; adj_s
<= adj_o
; adj_s
+= 2 * adj_o
) {
1593 test_t
.eu_modify(2, adj_s
);
1595 test_d
= diff(si
, test_t
, _mc_arg
, local_ax_count
, m
);
1597 if (test_d
< here
|| (!finite(here
) && finite(test_d
))) {
1604 } else if (alignment_class
== 2) {
1607 * Projective transformation
1610 for (int i
= 0; i
< 4; i
++)
1611 for (int j
= 0; j
< 2; j
++)
1612 for (adj_s
= -adj_p
; adj_s
<= adj_p
; adj_s
+= 2 * adj_p
) {
1616 if (perturb_type
== 0)
1617 test_t
.gpt_modify(j
, i
, adj_s
);
1618 else if (perturb_type
== 1)
1619 test_t
.gr_modify(j
, i
, adj_s
);
1623 test_d
= diff(si
, test_t
, _mc_arg
, local_ax_count
, m
);
1625 if (test_d
< here
|| (!finite(here
) && finite(test_d
))) {
1638 if (bda_mult
!= 0) {
1640 static unsigned int d_rotation
= 0;
1642 for (unsigned int d
= 0; d
< offset
.bd_count(); d
++)
1643 for (adj_s
= -adj_b
; adj_s
<= adj_b
; adj_s
+= 2 * adj_b
) {
1645 unsigned int rd
= (d
+ d_rotation
) % offset
.bd_count();
1646 d_rotation
= (d_rotation
+ 1) % offset
.bd_count();
1648 if (bda_rate
> 0 && fabs(modified_bd
[rd
] + adj_s
- current_bd
[rd
]) > bda_rate
)
1653 test_t
.bd_modify(rd
, adj_s
);
1655 test_d
= diff(si
, test_t
, _mc_arg
, local_ax_count
, m
);
1657 if (test_d
< here
|| (!finite(here
) && finite(test_d
))) {
1660 modified_bd
[rd
] += adj_s
;
1667 if (!(here
< old_here
) && !(!finite(old_here
) && finite(here
))) {
1673 * We're about to work with images
1674 * twice as large, so rescale the
1679 default_initial_alignment
.rescale(2);
1682 * Work with images twice as large
1686 si
= scale_clusters
[lod
];
1689 here
= diff(si
, offset
, _mc_arg
, local_ax_count
, m
);
1696 * Announce that we've dropped a perturbation level.
1699 ui::get()->alignment_perturbation_level(perturb
, lod
);
1702 ui::get()->set_match(here
);
1706 offset
.rescale(pow(2, lod
));
1707 default_initial_alignment
.rescale(pow(2, lod
));
1711 * Post-alignment exposure adjustment
1714 if (_exp_register
== 1) {
1715 ui::get()->exposure_2();
1716 set_exposure_ratio(m
, scale_clusters
[0], offset
, local_ax_count
, 1);
1723 ui::get()->postmatching();
1724 here
= diff(scale_clusters
[0], offset
, _mc
, local_ax_count
, m
);
1725 ui::get()->set_match(here
);
1728 * Free the level-of-detail structures
1731 final_clusters(scale_clusters
, scale_factor
, steps
);
1734 * Ensure that the match meets the threshold.
1737 if ((1 - here
) * 100 > match_threshold
) {
1739 * Update alignment variables
1742 default_initial_alignment
= offset
;
1743 old_final_alignment
= offset
;
1744 ui::get()->alignment_match_ok();
1745 } else if (local_gs
== 4) {
1748 * Align with outer starting points.
1752 * XXX: This probably isn't exactly the right thing to do,
1753 * since variables like old_initial_value have been overwritten.
1756 ale_accum nested_result
= _align(m
, -1);
1758 if ((1 - nested_result
) * 100 > match_threshold
) {
1759 return nested_result
;
1760 } else if (nested_result
< here
) {
1761 here
= nested_result
;
1765 if (is_fail_default
)
1766 offset
= default_initial_alignment
;
1768 ui::get()->set_match(here
);
1769 ui::get()->alignment_no_match();
1771 } else if (local_gs
== -1) {
1778 if (is_fail_default
)
1779 offset
= default_initial_alignment
;
1781 ui::get()->alignment_no_match();
1785 * Write the tonal registration multiplier as a comment.
1788 pixel trm
= image_rw::exp(m
).get_multiplier();
1789 tsave_trm(tsave
, trm
[0], trm
[1], trm
[2]);
1792 * Save the transformation information
1795 tsave_next(tsave
, offset
, alignment_class
== 2);
1800 * Update match statistics.
1803 match_sum
+= (1 - here
) * 100;
1808 * Close the image file.
1818 * High-pass filter for frequency weights
1820 static void hipass(int rows
, int cols
, fftw_complex
*inout
) {
1821 for (int i
= 0; i
< rows
* vert_freq_cut
; i
++)
1822 for (int j
= 0; j
< cols
; j
++)
1823 for (int k
= 0; k
< 2; k
++)
1824 inout
[i
* cols
+ j
][k
] = 0;
1825 for (int i
= 0; i
< rows
; i
++)
1826 for (int j
= 0; j
< cols
* horiz_freq_cut
; j
++)
1827 for (int k
= 0; k
< 2; k
++)
1828 inout
[i
* cols
+ j
][k
] = 0;
1829 for (int i
= 0; i
< rows
; i
++)
1830 for (int j
= 0; j
< cols
; j
++)
1831 for (int k
= 0; k
< 2; k
++)
1832 if (i
/ (double) rows
+ j
/ (double) cols
< 2 * avg_freq_cut
)
1833 inout
[i
* cols
+ j
][k
] = 0;
1839 * Reset alignment weights
1841 static void reset_weights() {
1843 alignment_weights_const
= NULL
;
1845 if (alignment_weights
!= NULL
)
1846 delete alignment_weights
;
1848 alignment_weights
= NULL
;
1852 * Initialize alignment weights
1854 static void init_weights() {
1855 if (alignment_weights
!= NULL
)
1858 int rows
= reference_image
->height();
1859 int cols
= reference_image
->width();
1860 int colors
= reference_image
->depth();
1862 alignment_weights
= new image_ale_real(rows
, cols
,
1863 colors
, "alignment_weights");
1865 assert (alignment_weights
);
1867 for (int i
= 0; i
< rows
; i
++)
1868 for (int j
= 0; j
< cols
; j
++)
1869 alignment_weights
->set_pixel(i
, j
, pixel(1, 1, 1));
1873 * Update alignment weights with weight map
1875 static void map_update() {
1877 if (weight_map
== NULL
)
1882 point map_offset
= reference_image
->offset() - weight_map
->offset();
1884 int rows
= reference_image
->height();
1885 int cols
= reference_image
->width();
1887 for (int i
= 0; i
< rows
; i
++)
1888 for (int j
= 0; j
< cols
; j
++) {
1889 point map_weight_position
= map_offset
+ point(i
, j
);
1890 if (map_weight_position
[0] >= 0
1891 && map_weight_position
[1] >= 0
1892 && map_weight_position
[0] <= weight_map
->height() - 1
1893 && map_weight_position
[1] <= weight_map
->width() - 1)
1894 alignment_weights
->pix(i
, j
) *= weight_map
->get_bl(map_weight_position
);
1899 * Update alignment weights with an internal weight map, reflecting a
1900 * summation of certainty values. Use existing memory structures if
1901 * possible. This function updates alignment_weights_const; hence, it
1902 * should not be called prior to any functions that modify the
1903 * alignment_weights structure.
1905 static void imap_update() {
1906 if (alignment_weights
== NULL
) {
1907 alignment_weights_const
= reference_defined
;
1909 int rows
= reference_image
->height();
1910 int cols
= reference_image
->width();
1912 for (int i
= 0; i
< rows
; i
++)
1913 for (int j
= 0; j
< cols
; j
++)
1914 alignment_weights
->pix(i
, j
) *= reference_defined
->get_pixel(i
, j
);
1916 alignment_weights_const
= alignment_weights
;
1921 * Update alignment weights with algorithmic weights
1923 static void wmx_update() {
1926 static exposure
*exp_def
= new exposure_default();
1927 static exposure
*exp_bool
= new exposure_boolean();
1929 if (wmx_file
== NULL
|| wmx_exec
== NULL
|| wmx_defs
== NULL
)
1932 unsigned int rows
= reference_image
->height();
1933 unsigned int cols
= reference_image
->width();
1935 image_rw::write_image(wmx_file
, reference_image
);
1936 image_rw::write_image(wmx_defs
, reference_defined
, exp_bool
);
1939 int exit_status
= 1;
1941 execlp(wmx_exec
, wmx_exec
, wmx_file
, wmx_defs
, NULL
);
1942 ui::get()->exec_failure(wmx_exec
, wmx_file
, wmx_defs
);
1948 ui::get()->fork_failure("d2::align");
1950 image
*wmx_weights
= image_rw::read_image(wmx_file
, exp_def
);
1952 if (wmx_weights
->height() != rows
|| wmx_weights
->width() != cols
)
1953 ui::get()->error("algorithmic weighting must not change image size");
1955 if (alignment_weights
== NULL
)
1956 alignment_weights
= wmx_weights
;
1958 for (unsigned int i
= 0; i
< rows
; i
++)
1959 for (unsigned int j
= 0; j
< cols
; j
++)
1960 alignment_weights
->pix(i
, j
) *= wmx_weights
->pix(i
, j
);
1965 * Update alignment weights with frequency weights
1967 static void fw_update() {
1969 if (horiz_freq_cut
== 0
1970 && vert_freq_cut
== 0
1971 && avg_freq_cut
== 0)
1975 * Required for correct operation of --fwshow
1978 assert (alignment_weights
== NULL
);
1980 int rows
= reference_image
->height();
1981 int cols
= reference_image
->width();
1982 int colors
= reference_image
->depth();
1984 alignment_weights
= new image_ale_real(rows
, cols
,
1985 colors
, "alignment_weights");
1987 fftw_complex
*inout
= (fftw_complex
*) fftw_malloc(sizeof(fftw_complex
) * rows
* cols
);
1991 fftw_plan pf
= fftw_plan_dft_2d(rows
, cols
,
1993 FFTW_FORWARD
, FFTW_ESTIMATE
);
1995 fftw_plan pb
= fftw_plan_dft_2d(rows
, cols
,
1997 FFTW_BACKWARD
, FFTW_ESTIMATE
);
1999 for (int k
= 0; k
< colors
; k
++) {
2000 for (int i
= 0; i
< rows
* cols
; i
++) {
2001 inout
[i
][0] = reference_image
->get_pixel(i
/ cols
, i
% cols
)[k
];
2006 hipass(rows
, cols
, inout
);
2009 for (int i
= 0; i
< rows
* cols
; i
++) {
2011 alignment_weights
->pix(i
/ cols
, i
% cols
)[k
] = fabs(inout
[i
][0] / (rows
* cols
));
2013 alignment_weights
->pix(i
/ cols
, i
% cols
)[k
] =
2014 sqrt(pow(inout
[i
][0] / (rows
* cols
), 2)
2015 + pow(inout
[i
][1] / (rows
* cols
), 2));
2020 fftw_destroy_plan(pf
);
2021 fftw_destroy_plan(pb
);
2024 if (fw_output
!= NULL
)
2025 image_rw::write_image(fw_output
, alignment_weights
);
2030 * Update alignment to frame N.
2032 static void update_to(int n
) {
2033 assert (n
<= latest
+ 1);
2036 const image
*i
= image_rw::open(n
);
2038 transformation result
= alignment_class
== 2
2039 ? transformation::gpt_identity(i
, scale_factor
)
2040 : transformation::eu_identity(i
, scale_factor
);
2041 result
= tload_first(tload
, alignment_class
== 2, result
, &is_default
);
2042 tsave_first(tsave
, result
, alignment_class
== 2);
2046 kept_t
= (transformation
*) malloc(image_rw::count()
2047 * sizeof(transformation
));
2048 kept_ok
= (int *) malloc(image_rw::count()
2053 if (!kept_t
|| !kept_ok
)
2054 ui::get()->memory_error("alignment");
2064 default_initial_alignment
= result
;
2068 for (int i
= latest
+ 1; i
<= n
; i
++) {
2069 assert (reference
!= NULL
);
2071 ui::get()->set_arender_current();
2072 reference
->sync(i
- 1);
2073 ui::get()->clear_arender_current();
2074 reference_image
= reference
->get_image();
2075 reference_defined
= reference
->get_defined();
2082 if (certainty_weights
)
2083 imap_update(); /* Must be called after all other _updates */
2085 assert (reference_image
!= NULL
);
2086 assert (reference_defined
!= NULL
);
2095 * Set the control point count
2097 static void set_cp_count(unsigned int n
) {
2098 assert (cp_array
== NULL
);
2101 cp_array
= (const point
**) malloc(n
* sizeof(const point
*));
2105 * Set control points.
2107 static void set_cp(unsigned int i
, const point
*p
) {
2114 static void exp_register() {
2119 * Register exposure only based on metadata
2121 static void exp_meta_only() {
2126 * Don't register exposure
2128 static void exp_noregister() {
2133 * Set alignment class to translation only. Only adjust the x and y
2134 * position of images. Do not rotate input images or perform
2135 * projective transformations.
2137 static void class_translation() {
2138 alignment_class
= 0;
2142 * Set alignment class to Euclidean transformations only. Adjust the x
2143 * and y position of images and the orientation of the image about the
2146 static void class_euclidean() {
2147 alignment_class
= 1;
2151 * Set alignment class to perform general projective transformations.
2152 * See the file gpt.h for more information about general projective
2155 static void class_projective() {
2156 alignment_class
= 2;
2160 * Set the default initial alignment to the identity transformation.
2162 static void initial_default_identity() {
2163 default_initial_alignment_type
= 0;
2167 * Set the default initial alignment to the most recently matched
2168 * frame's final transformation.
2170 static void initial_default_follow() {
2171 default_initial_alignment_type
= 1;
2175 * Perturb output coordinates.
2177 static void perturb_output() {
2182 * Perturb source coordinates.
2184 static void perturb_source() {
2189 * Frames under threshold align optimally
2191 static void fail_optimal() {
2192 is_fail_default
= 0;
2196 * Frames under threshold keep their default alignments.
2198 static void fail_default() {
2199 is_fail_default
= 1;
2203 * Align images with an error contribution from each color channel.
2206 channel_alignment_type
= 0;
2210 * Align images with an error contribution only from the green channel.
2211 * Other color channels do not affect alignment.
2213 static void green() {
2214 channel_alignment_type
= 1;
2218 * Align images using a summation of channels. May be useful when
2219 * dealing with images that have high frequency color ripples due to
2223 channel_alignment_type
= 2;
2227 * Error metric exponent
2230 static void set_metric_exponent(float me
) {
2231 metric_exponent
= me
;
2238 static void set_match_threshold(float mt
) {
2239 match_threshold
= mt
;
2243 * Perturbation lower and upper bounds.
2246 static void set_perturb_lower(ale_pos pl
, int plp
) {
2248 perturb_lower_percent
= plp
;
2251 static void set_perturb_upper(ale_pos pu
, int pup
) {
2253 perturb_upper_percent
= pup
;
2257 * Maximum rotational perturbation.
2260 static void set_rot_max(int rm
) {
2263 * Obtain the largest power of two not larger than rm.
2266 rot_max
= pow(2, floor(log(rm
) / log(2)));
2270 * Barrel distortion adjustment multiplier
2273 static void set_bda_mult(ale_pos m
) {
2278 * Barrel distortion maximum rate of change
2281 static void set_bda_rate(ale_pos m
) {
2289 static void set_lod_max(int lm
) {
2294 * Set the scale factor
2296 static void set_scale(ale_pos s
) {
2301 * Set reference rendering to align against
2303 static void set_reference(render
*r
) {
2308 * Set the interpolant
2310 static void set_interpolant(filter::scaled_filter
*f
) {
2315 * Set alignment weights image
2317 static void set_weight_map(const image
*i
) {
2322 * Set frequency cuts
2324 static void set_frequency_cut(double h
, double v
, double a
) {
2331 * Set algorithmic alignment weighting
2333 static void set_wmx(const char *e
, const char *f
, const char *d
) {
2340 * Show frequency weights
2342 static void set_fl_show(const char *filename
) {
2343 fw_output
= filename
;
2347 * Set transformation file loader.
2349 static void set_tload(tload_t
*tl
) {
2354 * Set transformation file saver.
2356 static void set_tsave(tsave_t
*ts
) {
2361 * Get match statistics for frame N.
2363 static int match(int n
) {
2377 * Message that old alignment data should be kept.
2379 static void keep() {
2380 assert (latest
== -1);
2385 * Get alignment for frame N.
2387 static transformation
of(int n
) {
2400 * Use Monte Carlo alignment sampling with argument N.
2402 static void mc(ale_pos n
) {
2407 * Set the certainty-weighted flag.
2409 static void certainty_weighted(int flag
) {
2410 certainty_weights
= flag
;
2414 * Set the global search type.
2416 static void gs(const char *type
) {
2417 if (!strcmp(type
, "local")) {
2419 } else if (!strcmp(type
, "inner")) {
2421 } else if (!strcmp(type
, "outer")) {
2423 } else if (!strcmp(type
, "all")) {
2425 } else if (!strcmp(type
, "central")) {
2427 } else if (!strcmp(type
, "points")) {
2431 ui::get()->error("bad global search type");
2436 * Set the minimum overlap for global searching
2438 static void gs_mo(unsigned int value
) {
2443 * Don't use Monte Carlo alignment sampling.
2445 static void no_mc() {
2450 * Set alignment exclusion regions
2452 static void set_exclusion(exclusion
*_ax_parameters
, int _ax_count
) {
2453 ax_count
= _ax_count
;
2454 ax_parameters
= _ax_parameters
;
2458 * Get match summary statistics.
2460 static ale_accum
match_summary() {
2461 return match_sum
/ match_count
;