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 type.
164 * 0. Identity transformation.
166 * 1. Most recently accepted frame's final transformation.
169 static int default_initial_alignment_type
;
172 * Projective group behavior
174 * 0. Perturb in output coordinates.
176 * 1. Perturb in source coordinates
179 static int perturb_type
;
184 * This structure contains variables necessary for handling a
185 * multi-alignment element. The change between the non-default old
186 * initial alignment and old final alignment is used to adjust the
187 * non-default current initial alignment. If either the old or new
188 * initial alignment is a default alignment, the old --follow semantics
193 int is_default
, old_is_default
;
196 transformation old_initial_alignment
;
197 transformation old_final_alignment
;
198 transformation default_initial_alignment
;
199 const image
*input_frame
;
209 * Alignment for failed frames -- default or optimal?
211 * A frame that does not meet the match threshold can be assigned the
212 * best alignment found, or can be assigned its alignment default.
215 static int is_fail_default
;
220 * 0. Align images with an error contribution from each color channel.
222 * 1. Align images with an error contribution only from the green channel.
223 * Other color channels do not affect alignment.
225 * 2. Align images using a summation of channels. May be useful when dealing
226 * with images that have high frequency color ripples due to color aliasing.
229 static int channel_alignment_type
;
232 * Error metric exponent
235 static float metric_exponent
;
241 static float match_threshold
;
244 * Perturbation lower and upper bounds.
247 static ale_pos perturb_lower
;
248 static int perturb_lower_percent
;
249 static ale_pos perturb_upper
;
250 static int perturb_upper_percent
;
253 * Maximum level-of-detail scale factor is 2^lod_max/perturb.
259 * Maximum rotational perturbation
262 static ale_pos rot_max
;
265 * Barrel distortion alignment multiplier
268 static ale_pos bda_mult
;
271 * Barrel distortion maximum adjustment rate
274 static ale_pos bda_rate
;
277 * Alignment match sum
280 static ale_accum match_sum
;
283 * Alignment match count.
286 static int match_count
;
289 * Monte Carlo parameter
291 * 0. Don't use monte carlo alignment sampling.
293 * (0,1]. Select, on average, a number of pixels which is the
294 * specified fraction of the number of pixels in the accumulated image.
298 static int _mcd_limit
;
301 * Certainty weight flag
303 * 0. Don't use certainty weights for alignment.
305 * 1. Use certainty weights for alignment.
308 static int certainty_weights
;
311 * Global search parameter
313 * 0. Local: Local search only.
314 * 1. Inner: Alignment reference image inner region
315 * 2. Outer: Alignment reference image outer region
316 * 3. All: Alignment reference image inner and outer regions.
317 * 4. Central: Inner if possible; else, best of inner and outer.
318 * 5. Points: Align by control points.
324 * Multi-alignment cardinality.
327 static unsigned int _ma_card
;
330 * Multi-alignment contiguity.
333 static double _ma_cont
;
336 * Minimum overlap for global searches
339 static unsigned int _gs_mo
;
345 static exclusion
*ax_parameters
;
349 * Type for scale cluster.
352 struct scale_cluster
{
354 const image
*defined
;
355 const image
*aweight
;
356 exclusion
*ax_parameters
;
363 * Check for exclusion region coverage in the reference
366 static int ref_excluded(int i
, int j
, point offset
, exclusion
*params
, int param_count
) {
367 for (int idx
= 0; idx
< param_count
; idx
++)
368 if (params
[idx
].type
== exclusion::RENDER
369 && i
+ offset
[0] >= params
[idx
].x
[0]
370 && i
+ offset
[0] <= params
[idx
].x
[1]
371 && j
+ offset
[1] >= params
[idx
].x
[2]
372 && j
+ offset
[1] <= params
[idx
].x
[3])
379 * Check for exclusion region coverage in the input
382 static int input_excluded(ale_pos ti
, ale_pos tj
, exclusion
*params
, int param_count
) {
383 for (int idx
= 0; idx
< param_count
; idx
++)
384 if (params
[idx
].type
== exclusion::FRAME
385 && ti
>= params
[idx
].x
[0]
386 && ti
<= params
[idx
].x
[1]
387 && tj
>= params
[idx
].x
[2]
388 && tj
<= params
[idx
].x
[3])
395 * Overlap function. Determines the number of pixels in areas where
396 * the arrays overlap. Uses the reference array's notion of pixel
399 static unsigned int overlap(struct scale_cluster c
, transformation t
, int ax_count
) {
400 assert (reference_image
);
402 unsigned int result
= 0;
404 point offset
= c
.accum
->offset();
406 for (unsigned int i
= 0; i
< c
.accum
->height(); i
++)
407 for (unsigned int j
= 0; j
< c
.accum
->width(); j
++) {
409 if (ref_excluded(i
, j
, offset
, c
.ax_parameters
, ax_count
))
418 q
= (c
.input_scale
< 1.0 && interpolant
== NULL
)
419 ? t
.scaled_inverse_transform(
420 point(i
+ offset
[0], j
+ offset
[1]))
421 : t
.unscaled_inverse_transform(
422 point(i
+ offset
[0], j
+ offset
[1]));
428 * Check that the transformed coordinates are within
429 * the boundaries of array c.input, and check that the
430 * weight value in the accumulated array is nonzero,
431 * unless we know it is nonzero by virtue of the fact
432 * that it falls within the region of the original
433 * frame (e.g. when we're not increasing image
434 * extents). Also check for frame exclusion.
437 if (input_excluded(ti
, tj
, c
.ax_parameters
, ax_count
))
441 && ti
<= c
.input
->height() - 1
443 && tj
<= c
.input
->width() - 1
444 && c
.defined
->get_pixel(i
, j
)[0] != 0)
452 * Not-quite-symmetric difference function. Determines the difference in areas
453 * where the arrays overlap. Uses the reference array's notion of pixel positions.
455 * For the purposes of determining the difference, this function divides each
456 * pixel value by the corresponding image's average pixel magnitude, unless we
459 * a) Extending the boundaries of the image, or
461 * b) following the previous frame's transform
463 * If we are doing monte-carlo pixel sampling for alignment, we
464 * typically sample a subset of available pixels; otherwise, we sample
474 ale_accum centroid
[2], centroid_divisor
;
476 typedef unsigned int hist_bin
;
482 hist_bin
*histogram_integral
;
486 void add_hist(int r
, int d
, int count
) {
490 int r_shift
= 0, d_shift
= 0;
492 if (r
- hist_min_r
>= hist_dim
) {
493 r_shift
= (r
- hist_min_r
) - hist_dim
+ 1;
494 hist_min_r
+= r_shift
;
497 if (d
- hist_min_d
>= hist_dim
) {
498 d_shift
= (d
- hist_min_d
) - hist_dim
+ 1;
499 hist_min_d
+= d_shift
;
502 assert (r_shift
>= 0);
503 assert (d_shift
>= 0);
505 if (r_shift
|| d_shift
) {
506 for (int rr
= 0; rr
< hist_dim
; rr
++)
507 for (int dd
= 0; dd
< hist_dim
; dd
++) {
509 hist_bin value
= histogram
[rr
* hist_dim
+ dd
];
511 histogram
[rr
* hist_dim
+ dd
] = 0;
513 int rrr
= rr
- r_shift
;
514 int ddd
= dd
- d_shift
;
521 histogram
[rrr
* hist_dim
+ ddd
] += value
;
533 histogram
[r
* hist_dim
+ d
] += count
;
536 void add_hist(ale_accum result
, ale_accum divisor
) {
537 ale_accum rbin
= log(result
) / log(2);
538 ale_accum dbin
= log(divisor
) / log(2);
540 if (!(rbin
> INT_MIN
))
542 if (!(dbin
> INT_MIN
))
545 add_hist((int) floor(rbin
), (int) floor(dbin
), 1);
552 hist_min_r
= INT_MIN
;
553 hist_min_d
= INT_MIN
;
556 histogram
= (hist_bin
*) calloc(hist_dim
* hist_dim
, sizeof(hist_bin
));
558 min
= point::posinf();
559 max
= point::neginf();
563 centroid_divisor
= 0;
571 hist_min_r
= INT_MIN
;
572 hist_min_d
= INT_MIN
;
574 histogram
= (hist_bin
*) calloc(hist_dim
* hist_dim
, sizeof(hist_bin
));
581 int check_removal(diff_stat_t
*with
) {
582 ale_accum bresult
, bdivisor
, wresult
, wdivisor
;
583 hist_bin
*bhist
, *whist
;
585 ui::get()->d2_align_sim_start();
587 bhist
= (hist_bin
*)malloc(sizeof(hist_bin
) * hist_dim
* hist_dim
);
588 whist
= (hist_bin
*)malloc(sizeof(hist_bin
) * with
->hist_dim
* with
->hist_dim
);
592 wresult
= with
->result
;
593 wdivisor
= with
->divisor
;
595 for (int i
= 0; i
< hist_dim
* hist_dim
; i
++)
596 bhist
[i
] = histogram
[i
];
598 for (int i
= 0; i
< with
->hist_dim
* with
->hist_dim
; i
++)
599 whist
[i
] = with
->histogram
[i
];
601 for (int r
= 0; r
< _mcd_limit
; r
++) {
602 int max_gradient_bin
= -1;
603 int max_gradient_hist
= -1;
604 ale_accum max_gradient
= 0;
606 for (int i
= 0; i
< hist_dim
* hist_dim
; i
++) {
610 ale_accum br
= pow(2, hist_min_r
+ i
/ hist_dim
);
611 ale_accum bd
= pow(2, hist_min_d
+ i
% hist_dim
);
612 ale_accum b_test_gradient
=
613 (bresult
- br
) / (bdivisor
- bd
) - bresult
/ bdivisor
;
615 if (b_test_gradient
> max_gradient
) {
616 max_gradient_bin
= i
;
617 max_gradient_hist
= 0;
618 max_gradient
= b_test_gradient
;
622 for (int i
= 0; i
< with
->hist_dim
* with
->hist_dim
; i
++) {
626 ale_accum wr
= pow(2, with
->hist_min_r
+ i
/ with
->hist_dim
);
627 ale_accum wd
= pow(2, with
->hist_min_d
+ i
% with
->hist_dim
);
628 ale_accum w_test_gradient
=
629 wresult
/ wdivisor
- (wresult
- wr
) / (wdivisor
- wd
);
631 if (w_test_gradient
> max_gradient
) {
632 max_gradient_bin
= i
;
633 max_gradient_hist
= 1;
634 max_gradient
= w_test_gradient
;
638 if (max_gradient_hist
== 0) {
639 bhist
[max_gradient_bin
]--;
640 bresult
-= pow(2, hist_min_r
+ max_gradient_bin
/ hist_dim
);
641 bdivisor
-= pow(2, hist_min_d
+ max_gradient_bin
% hist_dim
);
642 } else if (max_gradient_hist
== 1) {
643 whist
[max_gradient_bin
]--;
644 wresult
-= pow(2, with
->hist_min_r
+ max_gradient_bin
/ with
->hist_dim
);
645 wdivisor
-= pow(2, with
->hist_min_d
+ max_gradient_bin
% with
->hist_dim
);
652 ui::get()->d2_align_sim_stop();
654 if (bresult
/ bdivisor
< wresult
/ wdivisor
)
660 int reliable(diff_stat_t
*with
, ale_pos mc
) {
661 return check_removal(with
);
664 void add(const diff_stat_t
*ds
) {
665 result
+= ds
->result
;
666 divisor
+= ds
->divisor
;
668 for (int r
= 0; r
< ds
->hist_dim
; r
++)
669 for (int d
= 0; d
< ds
->hist_dim
; d
++)
670 add_hist(r
+ ds
->hist_min_r
, d
+ ds
->hist_min_d
,
671 ds
->histogram
[r
* hist_dim
+ d
]);
673 for (int d
= 0; d
< 2; d
++) {
674 if (min
[d
] > ds
->min
[d
])
676 if (max
[d
] < ds
->max
[d
])
678 centroid
[d
] += ds
->centroid
[d
];
681 centroid_divisor
+= ds
->centroid_divisor
;
684 ale_accum
get_result() {
688 ale_accum
get_divisor() {
692 point
get_centroid() {
693 point result
= point(centroid
[0] / centroid_divisor
, centroid
[1] / centroid_divisor
);
695 assert (finite(centroid
[0])
696 && finite(centroid
[1])
697 && (result
.defined() || centroid_divisor
== 0));
702 ale_accum
get_error() {
703 return pow(result
/ divisor
, 1/metric_exponent
);
706 void sample(int f
, scale_cluster c
, int i
, int j
, ale_pos ti
, ale_pos tj
) {
707 pixel pa
= c
.accum
->get_pixel(i
, j
);
710 ale_accum this_result
= 0;
711 ale_accum this_divisor
= 0;
714 if (interpolant
!= NULL
)
715 interpolant
->filtered(i
, j
, &pb
, &weight
, 1, f
);
718 c
.input
->get_bl(point(ti
, tj
), result
);
727 if (certainty_weights
== 0)
728 weight
= pixel(1, 1, 1);
730 if (c
.aweight
!= NULL
)
731 weight
*= c
.aweight
->get_pixel(i
, j
);
734 * Update sampling area statistics
746 centroid
[0] += (weight
[0] + weight
[1] + weight
[2]) * i
;
747 centroid
[1] += (weight
[0] + weight
[1] + weight
[2]) * j
;
748 centroid_divisor
+= (weight
[0] + weight
[1] + weight
[2]);
751 * Determine alignment type.
754 if (channel_alignment_type
== 0) {
756 * Align based on all channels.
760 for (int k
= 0; k
< 3; k
++) {
761 ale_real achan
= pa
[k
];
762 ale_real bchan
= pb
[k
];
764 this_result
+= weight
[k
] * pow(fabs(achan
- bchan
), metric_exponent
);
765 this_divisor
+= weight
[k
] * pow(achan
> bchan
? achan
: bchan
, metric_exponent
);
767 } else if (channel_alignment_type
== 1) {
769 * Align based on the green channel.
772 ale_real achan
= pa
[1];
773 ale_real bchan
= pb
[1];
775 this_result
= weight
[1] * pow(fabs(achan
- bchan
), metric_exponent
);
776 this_divisor
= weight
[1] * pow(achan
> bchan
? achan
: bchan
, metric_exponent
);
777 } else if (channel_alignment_type
== 2) {
779 * Align based on the sum of all channels.
786 for (int k
= 0; k
< 3; k
++) {
789 wsum
+= weight
[k
] / 3;
792 this_result
= wsum
* pow(fabs(asum
- bsum
), metric_exponent
);
793 this_divisor
= wsum
* pow(asum
> bsum
? asum
: bsum
, metric_exponent
);
796 result
+= this_result
;
797 divisor
+= this_divisor
;
799 add_hist(this_result
, this_divisor
);
803 fprintf(stderr
, "\n");
804 fprintf(stderr
, "hist_min_r = %d\n", hist_min_r
);
805 fprintf(stderr
, "hist_min_d = %d\n", hist_min_d
);
806 fprintf(stderr
, "hist_dim = %d\n", hist_dim
);
807 fprintf(stderr
, "hist_total = %d\n", hist_total
);
808 fprintf(stderr
, "\n");
810 hist_bin recalc_total
= 0;
812 for (int r
= 0; r
< hist_dim
; r
++) {
813 for (int d
= 0; d
< hist_dim
; d
++) {
814 recalc_total
+= histogram
[r
* hist_dim
+ d
];
815 fprintf(stderr
, "\t%d", histogram
[r
* hist_dim
+ d
]);
817 fprintf(stderr
, "\n");
820 fprintf(stderr
, "\n");
821 fprintf(stderr
, "recalc_total = %d\n", recalc_total
);
825 struct subdomain_args
{
826 struct scale_cluster c
;
831 diff_stat_t
* diff_stat
;
832 int i_min
, i_max
, j_min
, j_max
;
836 static void *diff_subdomain(void *args
) {
838 subdomain_args
*sargs
= (subdomain_args
*) args
;
840 struct scale_cluster c
= sargs
->c
;
841 transformation t
= sargs
->t
;
842 ale_pos _mc_arg
= sargs
->_mc_arg
;
843 int ax_count
= sargs
->ax_count
;
845 int i_min
= sargs
->i_min
;
846 int i_max
= sargs
->i_max
;
847 int j_min
= sargs
->j_min
;
848 int j_max
= sargs
->j_max
;
849 int subdomain
= sargs
->subdomain
;
851 assert (reference_image
);
853 point offset
= c
.accum
->offset();
858 * We always use the same code for exhaustive and Monte Carlo
859 * pixel sampling, setting _mc_arg = 1 when all pixels are to
863 if (_mc_arg
<= 0 || _mc_arg
>= 1)
868 int index_max
= (i_max
- i_min
) * (j_max
- j_min
);
871 * We use a random process for which the expected
872 * number of sampled pixels is +/- .000003 from mc_arg
873 * in the range [.005,.995] for an image with 100,000
874 * pixels. (The actual number may still deviate from
875 * the expected number by more than this amount,
876 * however.) The method is as follows:
878 * We have mc_arg == USE/ALL, or (expected # pixels to
879 * use)/(# total pixels). We derive from this
882 * SKIP/USE == (SKIP/ALL)/(USE/ALL) == (1 - (USE/ALL))/(USE/ALL)
884 * Once we have SKIP/USE, we know the expected number
885 * of pixels to skip in each iteration. We use a random
886 * selection process that provides SKIP/USE close to
887 * this calculated value.
889 * If we can draw uniformly to select the number of
890 * pixels to skip, we do. In this case, the maximum
891 * number of pixels to skip is twice the expected
894 * If we cannot draw uniformly, we still assign equal
895 * probability to each of the integer values in the
896 * interval [0, 2 * (SKIP/USE)], but assign an unequal
897 * amount to the integer value ceil(2 * SKIP/USE) + 1.
900 ale_pos u
= (1 - _mc_arg
) / _mc_arg
;
902 ale_pos mc_max
= (floor(2*u
) * (1 + floor(2*u
)) + 2*u
)
903 / (2 + 2 * floor(2*u
) - 2*u
);
906 * Reseed the random number generator; we want the
907 * same set of pixels to be used when comparing two
908 * alignment options. If we wanted to avoid bias from
909 * repeatedly utilizing the same seed, we could seed
910 * with the number of the frame most recently aligned:
914 * However, in cursory tests, it seems okay to just use
915 * the default seed of 1, and so we do this, since it
916 * is simpler; both of these approaches to reseeding
917 * achieve better results than not reseeding. (1 is
918 * the default seed according to the GNU Manual Page
921 * For subdomain calculations, we vary the seed by subdomain.
926 rng
.seed(1 + subdomain
);
928 for(index
= -1 + (int) ceil((mc_max
+1)
929 * ( (1 + ((ale_pos
) (rng
.get())) )
930 / (1 + ((ale_pos
) RAND_MAX
)) ));
932 index
+= (int) ceil((mc_max
+1)
933 * ( (1 + ((ale_pos
) (rng
.get())) )
934 / (1 + ((ale_pos
) RAND_MAX
)) ))){
936 i
= index
/ (j_max
- j_min
) + i_min
;
937 j
= index
% (j_max
- j_min
) + j_min
;
940 * Check for exclusion in render coordinates.
943 if (ref_excluded(i
, j
, offset
, c
.ax_parameters
, ax_count
))
947 * Check transformation support.
950 if (!t
.supported((int) (i
+ offset
[0]), (int) (j
+ offset
[1])))
959 q
= (c
.input_scale
< 1.0 && interpolant
== NULL
)
960 ? t
.scaled_inverse_transform(
961 point(i
+ offset
[0], j
+ offset
[1]))
962 : t
.unscaled_inverse_transform(
963 point(i
+ offset
[0], j
+ offset
[1]));
969 * Check that the transformed coordinates are within
970 * the boundaries of array c.input and that they
971 * are not subject to exclusion.
973 * Also, check that the weight value in the accumulated array
974 * is nonzero, unless we know it is nonzero by virtue of the
975 * fact that it falls within the region of the original frame
976 * (e.g. when we're not increasing image extents).
979 if (input_excluded(ti
, tj
, c
.ax_parameters
, ax_count
))
983 && ti
<= c
.input
->height() - 1
985 && tj
<= c
.input
->width() - 1
986 && c
.defined
->get_pixel(i
, j
)[0] != 0)
988 sargs
->diff_stat
->sample(f
, c
, i
, j
, ti
, tj
);
995 static ale_accum
diff(struct scale_cluster c
, transformation t
,
996 ale_pos _mc_arg
, int ax_count
, int f
, diff_stat_t
*diff_stat_in
= NULL
) {
998 diff_stat_t
*diff_stat
= diff_stat_in
;
1000 if (diff_stat
== NULL
)
1001 diff_stat
= new diff_stat_t();
1005 ui::get()->d2_align_sample_start();
1007 if (interpolant
!= NULL
)
1008 interpolant
->set_parameters(t
, c
.input
, c
.accum
->offset());
1012 N
= thread::count();
1014 pthread_t
*threads
= (pthread_t
*) malloc(sizeof(pthread_t
) * N
);
1015 pthread_attr_t
*thread_attr
= (pthread_attr_t
*) malloc(sizeof(pthread_attr_t
) * N
);
1021 subdomain_args
*args
= new subdomain_args
[N
];
1023 for (int ti
= 0; ti
< N
; ti
++) {
1026 args
[ti
]._mc_arg
= _mc_arg
;
1027 args
[ti
].ax_count
= ax_count
;
1029 args
[ti
].diff_stat
= new diff_stat_t();
1030 args
[ti
].i_min
= (c
.accum
->height() * ti
) / N
;
1031 args
[ti
].i_max
= (c
.accum
->height() * (ti
+ 1)) / N
;
1033 args
[ti
].j_max
= c
.accum
->width();
1034 args
[ti
].subdomain
= ti
;
1037 pthread_attr_init(&thread_attr
[ti
]);
1038 pthread_attr_setdetachstate(&thread_attr
[ti
], PTHREAD_CREATE_JOINABLE
);
1039 pthread_create(&threads
[ti
], &thread_attr
[ti
], diff_subdomain
, &args
[ti
]);
1041 diff_subdomain(&args
[ti
]);
1045 for (int ti
= 0; ti
< N
; ti
++) {
1047 pthread_join(threads
[ti
], NULL
);
1049 diff_stat
->add(args
[ti
].diff_stat
);
1051 delete args
[ti
].diff_stat
;
1056 ui::get()->d2_align_sample_stop();
1058 ale_accum result
= diff_stat
->get_error();
1060 if (diff_stat_in
== NULL
)
1068 * Adjust exposure for an aligned frame B against reference A.
1070 * Expects full-LOD images.
1072 * This function is a bit of a mess, as it reflects rather ad-hoc rules
1073 * regarding what seems to work w.r.t. certainty. Using certainty in the
1074 * first pass seems to result in worse alignment, while not using certainty
1075 * in the second pass results in incorrect determination of exposure.
1077 * [Note that this may have been due to a bug in certainty determination
1078 * within this function.]
1080 static void set_exposure_ratio(unsigned int m
, struct scale_cluster c
,
1081 transformation t
, int ax_count
, int pass_number
) {
1083 if (_exp_register
== 2) {
1085 * Use metadata only.
1087 ale_real gain_multiplier
= image_rw::exp(m
).get_gain_multiplier();
1088 pixel multiplier
= pixel(gain_multiplier
, gain_multiplier
, gain_multiplier
);
1090 image_rw::exp(m
).set_multiplier(multiplier
);
1091 ui::get()->exp_multiplier(multiplier
[0],
1098 pixel_accum asum
, bsum
;
1100 point offset
= c
.accum
->offset();
1102 for (unsigned int i
= 0; i
< c
.accum
->height(); i
++)
1103 for (unsigned int j
= 0; j
< c
.accum
->width(); j
++) {
1105 if (ref_excluded(i
, j
, offset
, c
.ax_parameters
, ax_count
))
1114 q
= (c
.input_scale
< 1.0 && interpolant
== NULL
)
1115 ? t
.scaled_inverse_transform(
1116 point(i
+ offset
[0], j
+ offset
[1]))
1117 : t
.unscaled_inverse_transform(
1118 point(i
+ offset
[0], j
+ offset
[1]));
1121 * Check that the transformed coordinates are within
1122 * the boundaries of array c.input, that they are not
1123 * subject to exclusion, and that the weight value in
1124 * the accumulated array is nonzero.
1127 if (input_excluded(q
[0], q
[1], c
.ax_parameters
, ax_count
))
1131 && q
[0] <= c
.input
->height() - 1
1133 && q
[1] <= c
.input
->width() - 1
1134 && c
.defined
->get_pixel(i
, j
).minabs_norm() != 0) {
1135 pixel a
= c
.accum
->get_pixel(i
, j
);
1138 c
.input
->get_bl(q
, b
);
1141 pixel weight
= (c
.aweight
1142 ? c
.aweight
->get_pixel(i
, j
)
1144 * ((!certainty_weights
&& pass_number
)
1145 ? c
.defined
->get_pixel(i
, j
)
1151 pixel weight
= pixel(1, 1, 1);
1155 bsum
+= b
[0] * weight
;
1159 // std::cerr << (asum / bsum) << " ";
1161 pixel_accum new_multiplier
;
1163 new_multiplier
= asum
/ bsum
* image_rw::exp(m
).get_multiplier();
1165 if (finite(new_multiplier
[0])
1166 && finite(new_multiplier
[1])
1167 && finite(new_multiplier
[2])) {
1168 image_rw::exp(m
).set_multiplier(new_multiplier
);
1169 ui::get()->exp_multiplier(new_multiplier
[0],
1176 * Copy all ax parameters.
1178 static exclusion
*copy_ax_parameters(int local_ax_count
, exclusion
*source
) {
1180 exclusion
*dest
= (exclusion
*) malloc(local_ax_count
* sizeof(exclusion
));
1185 ui::get()->memory_error("exclusion regions");
1187 for (int idx
= 0; idx
< local_ax_count
; idx
++)
1188 dest
[idx
] = source
[idx
];
1194 * Copy ax parameters according to frame.
1196 static exclusion
*filter_ax_parameters(int frame
, int *local_ax_count
) {
1198 exclusion
*dest
= (exclusion
*) malloc(ax_count
* sizeof(exclusion
));
1203 ui::get()->memory_error("exclusion regions");
1205 *local_ax_count
= 0;
1207 for (int idx
= 0; idx
< ax_count
; idx
++) {
1208 if (ax_parameters
[idx
].x
[4] > frame
1209 || ax_parameters
[idx
].x
[5] < frame
)
1212 dest
[*local_ax_count
] = ax_parameters
[idx
];
1214 (*local_ax_count
)++;
1220 static void scale_ax_parameters(int local_ax_count
, exclusion
*ax_parameters
,
1221 ale_pos ref_scale
, ale_pos input_scale
) {
1222 for (int i
= 0; i
< local_ax_count
; i
++) {
1223 ale_pos scale
= (ax_parameters
[i
].type
== exclusion::RENDER
)
1227 for (int n
= 0; n
< 6; n
++) {
1228 ax_parameters
[i
].x
[n
] = (int) floor(ax_parameters
[i
].x
[n
]
1235 * Prepare the next level of detail for ordinary images.
1237 static const image
*prepare_lod(const image
*current
) {
1238 if (current
== NULL
)
1241 return current
->scale_by_half("prepare_lod");
1245 * Prepare the next level of detail for weighted images.
1247 static const image
*prepare_lod(const image
*current
, const image
*weights
) {
1248 if (current
== NULL
)
1251 return current
->scale_by_half(weights
, "prepare_lod");
1255 * Prepare the next level of detail for definition maps.
1257 static const image
*prepare_lod_def(const image
*current
) {
1260 return current
->defined_scale_by_half("prepare_lod_def");
1264 * Initialize the scale cluster data structure.
1266 static struct scale_cluster
*init_clusters(int frame
, ale_real scale_factor
,
1267 const image
*input_frame
, unsigned int steps
,
1268 int *local_ax_count
) {
1271 * Allocate memory for the array.
1274 struct scale_cluster
*scale_clusters
=
1275 (struct scale_cluster
*) malloc(steps
* sizeof(struct scale_cluster
));
1277 assert (scale_clusters
);
1279 if (!scale_clusters
)
1280 ui::get()->memory_error("alignment");
1283 * Prepare images and exclusion regions for the highest level
1287 scale_clusters
[0].accum
= reference_image
;
1289 ui::get()->constructing_lod_clusters(0.0);
1290 scale_clusters
[0].input_scale
= scale_factor
;
1291 if (scale_factor
< 1.0 && interpolant
== NULL
)
1292 scale_clusters
[0].input
= input_frame
->scale(scale_factor
, "alignment");
1294 scale_clusters
[0].input
= input_frame
;
1296 scale_clusters
[0].defined
= reference_defined
;
1297 scale_clusters
[0].aweight
= alignment_weights_const
;
1298 scale_clusters
[0].ax_parameters
= filter_ax_parameters(frame
, local_ax_count
);
1300 scale_ax_parameters(*local_ax_count
, scale_clusters
[0].ax_parameters
, scale_factor
,
1301 (scale_factor
< 1.0 && interpolant
== NULL
) ? scale_factor
: 1);
1304 * Prepare reduced-detail images and exclusion
1308 for (unsigned int step
= 1; step
< steps
; step
++) {
1309 ui::get()->constructing_lod_clusters(step
);
1310 scale_clusters
[step
].accum
= prepare_lod(scale_clusters
[step
- 1].accum
, scale_clusters
[step
- 1].aweight
);
1311 scale_clusters
[step
].defined
= prepare_lod_def(scale_clusters
[step
- 1].defined
);
1312 scale_clusters
[step
].aweight
= prepare_lod(scale_clusters
[step
- 1].aweight
);
1313 scale_clusters
[step
].ax_parameters
1314 = copy_ax_parameters(*local_ax_count
, scale_clusters
[step
- 1].ax_parameters
);
1316 double sf
= scale_clusters
[step
- 1].input_scale
/ 2;
1317 scale_clusters
[step
].input_scale
= sf
;
1319 if (sf
>= 1.0 || interpolant
!= NULL
) {
1320 scale_clusters
[step
].input
= scale_clusters
[step
- 1].input
;
1321 scale_ax_parameters(*local_ax_count
, scale_clusters
[step
].ax_parameters
, 0.5, 1);
1322 } else if (sf
> 0.5) {
1323 scale_clusters
[step
].input
= scale_clusters
[step
- 1].input
->scale(sf
, "alignment");
1324 scale_ax_parameters(*local_ax_count
, scale_clusters
[step
].ax_parameters
, 0.5, sf
);
1326 scale_clusters
[step
].input
= scale_clusters
[step
- 1].input
->scale(0.5, "alignment");
1327 scale_ax_parameters(*local_ax_count
, scale_clusters
[step
].ax_parameters
, 0.5, 0.5);
1331 return scale_clusters
;
1335 * Destroy the first element in the scale cluster data structure.
1337 static void final_clusters(struct scale_cluster
*scale_clusters
, ale_real scale_factor
,
1338 unsigned int steps
) {
1340 if (scale_clusters
[0].input_scale
< 1.0)
1341 delete scale_clusters
[0].input
;
1343 free((void *)scale_clusters
[0].ax_parameters
);
1345 for (unsigned int step
= 1; step
< steps
; step
++) {
1346 delete scale_clusters
[step
].accum
;
1347 delete scale_clusters
[step
].defined
;
1348 delete scale_clusters
[step
].aweight
;
1350 if (scale_clusters
[step
].input_scale
< 1.0)
1351 delete scale_clusters
[step
].input
;
1353 free((void *)scale_clusters
[step
].ax_parameters
);
1356 free(scale_clusters
);
1360 * Calculate the centroid of a control point for the set of frames
1361 * having index lower than m. Divide by any scaling of the output.
1363 static point
unscaled_centroid(unsigned int m
, unsigned int p
) {
1366 point
point_sum(0, 0);
1367 ale_accum divisor
= 0;
1369 for(unsigned int j
= 0; j
< m
; j
++) {
1370 point pp
= cp_array
[p
][j
];
1373 point_sum
+= kept_t
[j
].transform_unscaled(pp
)
1374 / kept_t
[j
].scale();
1380 return point::undefined();
1382 return point_sum
/ divisor
;
1386 * Calculate centroid of this frame, and of all previous frames,
1387 * from points common to both sets.
1389 static void centroids(unsigned int m
, point
*current
, point
*previous
) {
1391 * Calculate the translation
1393 point
other_centroid(0, 0);
1394 point
this_centroid(0, 0);
1395 ale_pos divisor
= 0;
1397 for (unsigned int i
= 0; i
< cp_count
; i
++) {
1398 point other_c
= unscaled_centroid(m
, i
);
1399 point this_c
= cp_array
[i
][m
];
1401 if (!other_c
.defined() || !this_c
.defined())
1404 other_centroid
+= other_c
;
1405 this_centroid
+= this_c
;
1411 *current
= point::undefined();
1412 *previous
= point::undefined();
1416 *current
= this_centroid
/ divisor
;
1417 *previous
= other_centroid
/ divisor
;
1421 * Calculate the RMS error of control points for frame m, with
1422 * transformation t, against control points for earlier frames.
1424 static ale_accum
cp_rms_error(unsigned int m
, transformation t
) {
1428 ale_accum divisor
= 0;
1430 for (unsigned int i
= 0; i
< cp_count
; i
++)
1431 for (unsigned int j
= 0; j
< m
; j
++) {
1432 const point
*p
= cp_array
[i
];
1433 point p_ref
= kept_t
[j
].transform_unscaled(p
[j
]);
1434 point p_cur
= t
.transform_unscaled(p
[m
]);
1436 if (!p_ref
.defined() || !p_cur
.defined())
1439 err
+= p_ref
.lengthtosq(p_cur
);
1443 return sqrt(err
/ divisor
);
1447 * Align frame m against the reference.
1449 * XXX: the transformation class currently combines ordinary
1450 * transformations with scaling. This is somewhat convenient for
1451 * some things, but can also be confusing. This method, _align(), is
1452 * one case where special care must be taken to ensure that the scale
1453 * is always set correctly (by using the 'rescale' method).
1455 static ale_accum
_align(int m
, int local_gs
, element_t
*element
) {
1457 const image
*input_frame
= element
->input_frame
;
1460 * Local upper/lower data, possibly dependent on image
1464 ale_pos local_lower
, local_upper
;
1467 * Select the minimum dimension as the reference.
1470 ale_pos reference_size
= input_frame
->height();
1471 if (input_frame
->width() < reference_size
)
1472 reference_size
= input_frame
->width();
1474 if (perturb_lower_percent
)
1475 local_lower
= perturb_lower
1480 local_lower
= perturb_lower
;
1482 if (perturb_upper_percent
)
1483 local_upper
= perturb_upper
1488 local_upper
= perturb_upper
;
1490 local_upper
= pow(2, floor(log(local_upper
) / log(2)));
1493 * Logarithms aren't exact, so we divide repeatedly to discover
1494 * how many steps will occur, and pass this information to the
1499 double step_variable
= local_upper
;
1500 while (step_variable
>= local_lower
) {
1505 ui::get()->set_steps(step_count
);
1507 ale_pos perturb
= local_upper
;
1508 transformation offset
;
1510 diff_stat_t
*here_diff_stat
= new diff_stat_t();
1514 kept_t
[latest
] = latest_t
;
1515 kept_ok
[latest
] = latest_ok
;
1519 * Maximum level-of-detail. Use a level of detail at most
1520 * 2^lod_diff finer than the adjustment resolution. lod_diff
1521 * is a synonym for lod_max.
1524 const int lod_diff
= lod_max
;
1527 * Determine how many levels of detail should be prepared.
1530 unsigned int steps
= (perturb
> pow(2, lod_max
))
1531 ? (unsigned int) (log(perturb
) / log(2)) - lod_max
+ 1 : 1;
1535 * Prepare multiple levels of detail.
1539 struct scale_cluster
*scale_clusters
= init_clusters(m
,
1540 scale_factor
, input_frame
, steps
,
1544 * Initialize variables used in the main loop.
1550 * Initialize the default initial transform
1553 if (default_initial_alignment_type
== 0) {
1556 * Follow the transformation of the original frame,
1557 * setting new image dimensions.
1560 // element->default_initial_alignment = orig_t;
1561 element
->default_initial_alignment
.set_current_element(orig_t
.get_element(0));
1562 element
->default_initial_alignment
.set_dimensions(input_frame
);
1564 } else if (default_initial_alignment_type
== 1)
1567 * Follow previous transformation, setting new image
1571 element
->default_initial_alignment
.set_dimensions(input_frame
);
1576 element
->old_is_default
= element
->is_default
;
1579 * Scale default initial transform for lod
1582 element
->default_initial_alignment
.rescale(1 / pow(2, lod
));
1585 * Load any file-specified transformation
1588 offset
= tload_next(tload
, alignment_class
== 2, element
->default_initial_alignment
,
1589 &element
->is_default
, element
->is_primary
);
1591 transformation new_offset
= offset
;
1593 if (!element
->old_is_default
&& !element
->is_default
&&
1594 default_initial_alignment_type
== 1) {
1597 * Implement new delta --follow semantics.
1599 * If we have a transformation T such that
1601 * prev_final == T(prev_init)
1605 * current_init_follow == T(current_init)
1607 * We can calculate T as follows:
1609 * T == prev_final(prev_init^-1)
1611 * Where ^-1 is the inverse operator.
1615 * Ensure that the lod for the old initial and final
1616 * alignments are equal to the lod for the new initial
1620 element
->old_final_alignment
.rescale (1 / pow(2, lod
));
1621 element
->old_initial_alignment
.rescale(1 / pow(2, lod
- element
->old_lod
));
1623 if (alignment_class
== 0) {
1625 * Translational transformations
1628 ale_pos t0
= -element
->old_initial_alignment
.eu_get(0)
1629 + element
->old_final_alignment
.eu_get(0);
1630 ale_pos t1
= -element
->old_initial_alignment
.eu_get(1)
1631 + element
->old_final_alignment
.eu_get(1);
1633 new_offset
.eu_modify(0, t0
);
1634 new_offset
.eu_modify(1, t1
);
1636 } else if (alignment_class
== 1) {
1638 * Euclidean transformations
1641 ale_pos t2
= -element
->old_initial_alignment
.eu_get(2)
1642 + element
->old_final_alignment
.eu_get(2);
1644 new_offset
.eu_modify(2, t2
);
1646 point
p( offset
.scaled_height()/2 + offset
.eu_get(0) - element
->old_initial_alignment
.eu_get(0),
1647 offset
.scaled_width()/2 + offset
.eu_get(1) - element
->old_initial_alignment
.eu_get(1) );
1649 p
= element
->old_final_alignment
.transform_scaled(p
);
1651 new_offset
.eu_modify(0, p
[0] - offset
.scaled_height()/2 - offset
.eu_get(0));
1652 new_offset
.eu_modify(1, p
[1] - offset
.scaled_width()/2 - offset
.eu_get(1));
1654 } else if (alignment_class
== 2) {
1656 * Projective transformations
1661 p
[0] = element
->old_final_alignment
.transform_scaled(element
->old_initial_alignment
1662 . scaled_inverse_transform(offset
.transform_scaled(point( 0 , 0 ))));
1663 p
[1] = element
->old_final_alignment
.transform_scaled(element
->old_initial_alignment
1664 . scaled_inverse_transform(offset
.transform_scaled(point(offset
.scaled_height(), 0 ))));
1665 p
[2] = element
->old_final_alignment
.transform_scaled(element
->old_initial_alignment
1666 . scaled_inverse_transform(offset
.transform_scaled(point(offset
.scaled_height(), offset
.scaled_width()))));
1667 p
[3] = element
->old_final_alignment
.transform_scaled(element
->old_initial_alignment
1668 . scaled_inverse_transform(offset
.transform_scaled(point( 0 , offset
.scaled_width()))));
1670 new_offset
.gpt_set(p
);
1674 element
->old_initial_alignment
= offset
;
1675 element
->old_lod
= lod
;
1676 offset
= new_offset
;
1678 struct scale_cluster si
= scale_clusters
[lod
];
1679 ale_pos _mc_arg
= (_mc
> 0) ? (_mc
* pow(2, 2 * lod
))
1680 /* : ((double)_mcd_min / (si.accum->height() * si.accum->width())); */
1683 ui::get()->alignment_monte_carlo_parameter(_mc_arg
);
1686 * Projective adjustment value
1689 ale_pos adj_p
= (perturb
>= pow(2, lod_diff
))
1690 ? pow(2, lod_diff
) : (double) perturb
;
1693 * Pre-alignment exposure adjustment
1696 if (_exp_register
) {
1697 ui::get()->exposure_1();
1698 transformation o
= offset
;
1699 for (int k
= lod
; k
> 0; k
--)
1701 set_exposure_ratio(m
, scale_clusters
[0], o
, local_ax_count
, 0);
1705 * Current difference (error) value
1708 ui::get()->prematching();
1709 here
= diff(si
, offset
, _mc_arg
, local_ax_count
, m
, here_diff_stat
);
1710 ui::get()->set_match(here
);
1713 * Current and modified barrel distortion parameters
1716 ale_pos current_bd
[BARREL_DEGREE
];
1717 ale_pos modified_bd
[BARREL_DEGREE
];
1718 offset
.bd_get(current_bd
);
1719 offset
.bd_get(modified_bd
);
1722 * Translational global search step
1725 if (perturb
>= local_lower
&& local_gs
!= 0 && local_gs
!= 5) {
1727 ui::get()->aligning(perturb
, lod
);
1729 transformation lowest_t
= offset
;
1730 ale_accum lowest_v
= here
;
1734 transformation offset_p
= offset
;
1736 if (!offset_p
.is_projective())
1737 offset_p
.eu_to_gpt();
1739 min
= max
= offset_p
.gpt_get(0);
1740 for (int p_index
= 1; p_index
< 4; p_index
++) {
1741 point p
= offset_p
.gpt_get(p_index
);
1752 point inner_min_t
= -min
;
1753 point inner_max_t
= -max
+ point(si
.accum
->height(), si
.accum
->width());
1754 point outer_min_t
= -max
+ point(adj_p
- 1, adj_p
- 1);
1755 point outer_max_t
= point(si
.accum
->height(), si
.accum
->width()) - point(adj_p
, adj_p
);
1757 if (local_gs
== 1 || local_gs
== 3 || local_gs
== 4) {
1763 for (ale_pos i
= inner_min_t
[0]; i
<= inner_max_t
[0]; i
+= adj_p
)
1764 for (ale_pos j
= inner_min_t
[1]; j
<= inner_max_t
[1]; j
+= adj_p
) {
1765 transformation t
= offset
;
1766 t
.translate(point(i
, j
));
1767 ale_accum v
= diff(si
, t
, _mc_arg
, local_ax_count
, m
);
1768 unsigned int ovl
= overlap(si
, t
, local_ax_count
);
1770 if ((v
< lowest_v
&& ovl
>= _gs_mo
)
1771 || (!finite(lowest_v
) && finite(v
))) {
1778 if (local_gs
== 2 || local_gs
== 3 || local_gs
== -1) {
1784 for (ale_pos i
= outer_min_t
[0]; i
<= outer_max_t
[0]; i
+= adj_p
)
1785 for (ale_pos j
= outer_min_t
[1]; j
< inner_min_t
[1]; j
+= adj_p
) {
1786 transformation t
= offset
;
1787 t
.translate(point(i
, j
));
1788 ale_accum v
= diff(si
, t
, _mc_arg
, local_ax_count
, m
);
1789 unsigned int ovl
= overlap(si
, t
, local_ax_count
);
1791 if ((v
< lowest_v
&& ovl
>= _gs_mo
)
1792 || (!finite(lowest_v
) && finite(v
))) {
1797 for (ale_pos i
= outer_min_t
[0]; i
<= outer_max_t
[0]; i
+= adj_p
)
1798 for (ale_pos j
= outer_max_t
[1]; j
> inner_max_t
[1]; j
-= adj_p
) {
1799 transformation t
= offset
;
1800 t
.translate(point(i
, j
));
1801 ale_accum v
= diff(si
, t
, _mc_arg
, local_ax_count
, m
);
1802 unsigned int ovl
= overlap(si
, t
, local_ax_count
);
1804 if ((v
< lowest_v
&& ovl
>= _gs_mo
)
1805 || (!finite(lowest_v
) && finite(v
))) {
1810 for (ale_pos i
= outer_min_t
[0]; i
< inner_min_t
[0]; i
+= adj_p
)
1811 for (ale_pos j
= outer_min_t
[1]; j
<= outer_max_t
[1]; j
+= adj_p
) {
1812 transformation t
= offset
;
1813 t
.translate(point(i
, j
));
1814 ale_accum v
= diff(si
, t
, _mc_arg
, local_ax_count
, m
);
1815 unsigned int ovl
= overlap(si
, t
, local_ax_count
);
1817 if ((v
< lowest_v
&& ovl
>= _gs_mo
)
1818 || (!finite(lowest_v
) && finite(v
))) {
1823 for (ale_pos i
= outer_max_t
[0]; i
> inner_max_t
[0]; i
-= adj_p
)
1824 for (ale_pos j
= outer_min_t
[1]; j
<= outer_max_t
[1]; j
+= adj_p
) {
1825 transformation t
= offset
;
1826 t
.translate(point(i
, j
));
1827 ale_accum v
= diff(si
, t
, _mc_arg
, local_ax_count
, m
);
1828 unsigned int ovl
= overlap(si
, t
, local_ax_count
);
1830 if ((v
< lowest_v
&& ovl
>= _gs_mo
)
1831 || (!finite(lowest_v
) && finite(v
))) {
1841 ui::get()->set_match(here
);
1845 * Control point alignment
1848 if (local_gs
== 5) {
1850 transformation o
= offset
;
1851 for (int k
= lod
; k
> 0; k
--)
1855 * Determine centroid data
1858 point current
, previous
;
1859 centroids(m
, ¤t
, &previous
);
1861 if (current
.defined() && previous
.defined()) {
1863 o
.set_dimensions(input_frame
);
1864 o
.translate((previous
- current
) * o
.scale());
1869 * Determine rotation for alignment classes other than translation.
1872 ale_accum lowest_error
= cp_rms_error(m
, o
);
1874 ale_pos rot_lower
= 2 * local_lower
1875 / sqrt(pow(scale_clusters
[0].input
->height(), 2)
1876 + pow(scale_clusters
[0].input
->width(), 2))
1880 if (alignment_class
> 0)
1881 for (ale_pos rot
= 30; rot
> rot_lower
; rot
/= 2)
1882 for (ale_pos srot
= -rot
; srot
<= rot
; srot
+= rot
* 2) {
1883 int is_improved
= 1;
1884 while (is_improved
) {
1886 transformation test_t
= o
;
1887 test_t
.rotate(current
* o
.scale(), srot
);
1888 ale_pos test_v
= cp_rms_error(m
, test_t
);
1890 if (test_v
< lowest_error
) {
1891 lowest_error
= test_v
;
1900 * Determine projective parameters through a local
1904 if (alignment_class
== 2) {
1905 ale_accum adj_p
= lowest_error
;
1907 if (adj_p
< local_lower
)
1908 adj_p
= local_lower
;
1910 while (adj_p
>= local_lower
) {
1911 transformation test_t
= o
;
1912 int is_improved
= 1;
1916 while (is_improved
) {
1919 for (int i
= 0; i
< 4; i
++)
1920 for (int j
= 0; j
< 2; j
++)
1921 for (adj_s
= -adj_p
; adj_s
<= adj_p
; adj_s
+= 2 * adj_p
) {
1925 if (perturb_type
== 0)
1926 test_t
.gpt_modify(j
, i
, adj_s
);
1927 else if (perturb_type
== 1)
1928 test_t
.gr_modify(j
, i
, adj_s
);
1932 test_v
= cp_rms_error(m
, test_t
);
1934 if (test_v
< lowest_error
) {
1935 lowest_error
= test_v
;
1947 set_exposure_ratio(m
, scale_clusters
[0], o
, local_ax_count
, 0);
1949 for (int k
= lod
; k
> 0; k
--)
1956 * Perturbation adjustment loop.
1959 ui::get()->aligning(perturb
, lod
);
1961 while (perturb
>= local_lower
) {
1966 * Orientational adjustment value in degrees.
1968 * Since rotational perturbation is now specified as an
1969 * arclength, we have to convert.
1972 ale_pos adj_o
= 2 * perturb
1973 / sqrt(pow(scale_clusters
[0].input
->height(), 2)
1974 + pow(scale_clusters
[0].input
->width(), 2))
1979 * Barrel distortion adjustment value
1982 ale_pos adj_b
= perturb
* bda_mult
;
1984 transformation test_t
;
1985 transformation old_offset
= offset
;
1987 ale_accum old_here
= here
;
1988 diff_stat_t
*old_here_diff_stat
= here_diff_stat
;
1989 here_diff_stat
= new diff_stat_t();
1990 int found_better
= 0;
1991 int found_reliable_better
= 0;
1992 int found_reliable_worse
= 0;
1993 int found_unreliable_worse
= 0;
1995 if (alignment_class
< 2 && alignment_class
>= 0) {
1998 * Translational or euclidean transformation
2001 for (int i
= 0; i
< 2; i
++)
2002 for (adj_s
= -adj_p
; adj_s
<= adj_p
; adj_s
+= 2 * adj_p
) {
2006 test_t
.eu_modify(i
, adj_s
);
2008 test_d
= diff(si
, test_t
, _mc_arg
, local_ax_count
, m
, here_diff_stat
);
2010 if (test_d
< here
|| (!finite(here
) && finite(test_d
))) {
2014 || here_diff_stat
->reliable(old_here_diff_stat
, _mc_arg
)) {
2015 found_reliable_better
= 1;
2022 if (_mc
<= 0 && test_d
> here
) {
2024 || old_here_diff_stat
->reliable(here_diff_stat
, _mc_arg
))
2025 found_reliable_worse
= 1;
2027 found_unreliable_worse
= 1;
2031 if (alignment_class
== 1 && adj_o
< rot_max
)
2032 for (adj_s
= -adj_o
; adj_s
<= adj_o
; adj_s
+= 2 * adj_o
) {
2034 point sample_centroid
= old_here_diff_stat
->get_centroid() + si
.accum
->offset();
2037 if (sample_centroid
.defined()) {
2038 test_t
.eu_rotate_about_scaled(sample_centroid
, adj_s
);
2040 test_t
.eu_modify(2, adj_s
);
2043 test_d
= diff(si
, test_t
, _mc_arg
, local_ax_count
, m
, here_diff_stat
);
2045 if (test_d
< here
|| (!finite(here
) && finite(test_d
))) {
2049 || here_diff_stat
->reliable(old_here_diff_stat
, _mc_arg
)) {
2050 found_reliable_better
= 1;
2057 if (_mc
<= 0 && test_d
> here
) {
2059 || old_here_diff_stat
->reliable(here_diff_stat
, _mc_arg
))
2060 found_reliable_worse
= 1;
2062 found_unreliable_worse
= 1;
2066 } else if (alignment_class
== 2) {
2069 * Projective transformation
2072 for (int i
= 0; i
< 4; i
++)
2073 for (int j
= 0; j
< 2; j
++)
2074 for (adj_s
= -adj_p
; adj_s
<= adj_p
; adj_s
+= 2 * adj_p
) {
2078 if (perturb_type
== 0)
2079 test_t
.gpt_modify(j
, i
, adj_s
);
2080 else if (perturb_type
== 1)
2081 test_t
.gr_modify(j
, i
, adj_s
);
2085 test_d
= diff(si
, test_t
, _mc_arg
, local_ax_count
, m
, here_diff_stat
);
2088 fprintf(stderr
, "old\n");
2089 old_here_diff_stat
->print_hist();
2090 fprintf(stderr
, "new\n");
2091 here_diff_stat
->print_hist();
2094 if (test_d
< here
|| (!finite(here
) && finite(test_d
))) {
2095 // fprintf(stderr, "found better\n");
2099 || here_diff_stat
->reliable(old_here_diff_stat
, _mc_arg
)) {
2100 // fprintf(stderr, "found reliable better\n");
2101 found_reliable_better
= 1;
2108 if (_mc
<= 0 && test_d
> here
) {
2110 || old_here_diff_stat
->reliable(here_diff_stat
, _mc_arg
))
2111 found_reliable_worse
= 1;
2113 found_unreliable_worse
= 1;
2123 if (bda_mult
!= 0) {
2125 static unsigned int d_rotation
= 0;
2127 for (unsigned int d
= 0; d
< offset
.bd_count(); d
++)
2128 for (adj_s
= -adj_b
; adj_s
<= adj_b
; adj_s
+= 2 * adj_b
) {
2130 unsigned int rd
= (d
+ d_rotation
) % offset
.bd_count();
2131 d_rotation
= (d_rotation
+ 1) % offset
.bd_count();
2133 if (bda_rate
> 0 && fabs(modified_bd
[rd
] + adj_s
- current_bd
[rd
]) > bda_rate
)
2138 test_t
.bd_modify(rd
, adj_s
);
2140 test_d
= diff(si
, test_t
, _mc_arg
, local_ax_count
, m
, here_diff_stat
);
2142 if (test_d
< here
|| (!finite(here
) && finite(test_d
))) {
2146 || here_diff_stat
->reliable(old_here_diff_stat
, _mc_arg
)) {
2147 found_reliable_better
= 1;
2150 modified_bd
[rd
] += adj_s
;
2155 if (_mc
<= 0 && test_d
> here
) {
2157 || old_here_diff_stat
->reliable(here_diff_stat
, _mc_arg
))
2158 found_reliable_worse
= 1;
2160 found_unreliable_worse
= 1;
2167 if (_mc_arg
< 1 && _mc
<= 0
2168 && (!found_reliable_worse
|| found_better
)
2169 /* && found_unreliable_worse */
2170 && !found_reliable_better
) {
2172 ui::get()->alignment_monte_carlo_parameter(_mc_arg
);
2177 && found_reliable_better
) {
2178 diff_stat_t
*here_diff_stat_half
= new diff_stat_t();
2179 diff_stat_t
*old_here_diff_stat_half
= new diff_stat_t();
2181 diff(si
, offset
, _mc_arg
/ 2, local_ax_count
, m
, here_diff_stat_half
);
2182 diff(si
, old_offset
, _mc_arg
/ 2, local_ax_count
, m
, old_here_diff_stat_half
);
2184 if (here_diff_stat_half
->reliable(old_here_diff_stat_half
, _mc_arg
/ 2)) {
2186 ui::get()->alignment_monte_carlo_parameter(_mc_arg
);
2187 delete here_diff_stat
;
2188 delete old_here_diff_stat
;
2189 here_diff_stat
= here_diff_stat_half
;
2190 old_here_diff_stat
= old_here_diff_stat_half
;
2192 delete here_diff_stat_half
;
2193 delete old_here_diff_stat_half
;
2197 if (!(here
< old_here
) && !(!finite(old_here
) && finite(here
))) {
2206 * We're about to work with images
2207 * twice as large, so rescale the
2212 element
->default_initial_alignment
.rescale(2);
2215 * Work with images twice as large
2219 si
= scale_clusters
[lod
];
2224 here
= diff(si
, offset
, _mc_arg
, local_ax_count
, m
, here_diff_stat
);
2225 delete old_here_diff_stat
;
2228 delete here_diff_stat
;
2229 here_diff_stat
= old_here_diff_stat
;
2237 ui::get()->alignment_monte_carlo_parameter(_mc_arg
);
2238 ui::get()->alignment_perturbation_level(perturb
, lod
);
2241 delete old_here_diff_stat
;
2244 ui::get()->set_match(here
);
2248 offset
.rescale(pow(2, lod
));
2249 element
->default_initial_alignment
.rescale(pow(2, lod
));
2253 * Post-alignment exposure adjustment
2256 if (_exp_register
== 1) {
2257 ui::get()->exposure_2();
2258 set_exposure_ratio(m
, scale_clusters
[0], offset
, local_ax_count
, 1);
2265 ui::get()->postmatching();
2266 diff_stat_t
*new_diff_stat
= new diff_stat_t();
2267 offset
.use_full_support();
2268 here
= diff(scale_clusters
[0], offset
, _mc_arg
, local_ax_count
, m
, new_diff_stat
);
2269 offset
.use_restricted_support();
2270 delete new_diff_stat
;
2271 ui::get()->set_match(here
);
2274 * Free the level-of-detail structures
2277 final_clusters(scale_clusters
, scale_factor
, steps
);
2280 * Ensure that the match meets the threshold.
2283 if ((1 - here
) * 100 > match_threshold
) {
2285 * Update alignment variables
2288 element
->default_initial_alignment
= offset
;
2289 element
->old_final_alignment
= offset
;
2290 ui::get()->alignment_match_ok();
2291 } else if (local_gs
== 4) {
2294 * Align with outer starting points.
2298 * XXX: This probably isn't exactly the right thing to do,
2299 * since variables like old_initial_value have been overwritten.
2302 ale_accum nested_result
= _align(m
, -1, element
);
2304 if ((1 - nested_result
) * 100 > match_threshold
) {
2305 return nested_result
;
2306 } else if (nested_result
< here
) {
2307 here
= nested_result
;
2311 if (is_fail_default
)
2312 offset
= element
->default_initial_alignment
;
2314 ui::get()->set_match(here
);
2315 ui::get()->alignment_no_match();
2317 } else if (local_gs
== -1) {
2324 if (is_fail_default
)
2325 offset
= element
->default_initial_alignment
;
2327 ui::get()->alignment_no_match();
2331 * Write the tonal registration multiplier as a comment.
2334 pixel trm
= image_rw::exp(m
).get_multiplier();
2335 tsave_trm(tsave
, trm
[0], trm
[1], trm
[2]);
2338 * Save the transformation information
2341 tsave_next(tsave
, offset
, alignment_class
== 2, element
->is_primary
);
2346 * Update match statistics.
2349 match_sum
+= (1 - here
) * 100;
2358 * High-pass filter for frequency weights
2360 static void hipass(int rows
, int cols
, fftw_complex
*inout
) {
2361 for (int i
= 0; i
< rows
* vert_freq_cut
; i
++)
2362 for (int j
= 0; j
< cols
; j
++)
2363 for (int k
= 0; k
< 2; k
++)
2364 inout
[i
* cols
+ j
][k
] = 0;
2365 for (int i
= 0; i
< rows
; i
++)
2366 for (int j
= 0; j
< cols
* horiz_freq_cut
; j
++)
2367 for (int k
= 0; k
< 2; k
++)
2368 inout
[i
* cols
+ j
][k
] = 0;
2369 for (int i
= 0; i
< rows
; i
++)
2370 for (int j
= 0; j
< cols
; j
++)
2371 for (int k
= 0; k
< 2; k
++)
2372 if (i
/ (double) rows
+ j
/ (double) cols
< 2 * avg_freq_cut
)
2373 inout
[i
* cols
+ j
][k
] = 0;
2379 * Reset alignment weights
2381 static void reset_weights() {
2383 alignment_weights_const
= NULL
;
2385 if (alignment_weights
!= NULL
)
2386 delete alignment_weights
;
2388 alignment_weights
= NULL
;
2392 * Initialize alignment weights
2394 static void init_weights() {
2395 if (alignment_weights
!= NULL
)
2398 int rows
= reference_image
->height();
2399 int cols
= reference_image
->width();
2400 int colors
= reference_image
->depth();
2402 alignment_weights
= new image_ale_real(rows
, cols
,
2403 colors
, "alignment_weights");
2405 assert (alignment_weights
);
2407 for (int i
= 0; i
< rows
; i
++)
2408 for (int j
= 0; j
< cols
; j
++)
2409 alignment_weights
->set_pixel(i
, j
, pixel(1, 1, 1));
2413 * Update alignment weights with weight map
2415 static void map_update() {
2417 if (weight_map
== NULL
)
2422 point map_offset
= reference_image
->offset() - weight_map
->offset();
2424 int rows
= reference_image
->height();
2425 int cols
= reference_image
->width();
2427 for (int i
= 0; i
< rows
; i
++)
2428 for (int j
= 0; j
< cols
; j
++) {
2429 point map_weight_position
= map_offset
+ point(i
, j
);
2430 if (map_weight_position
[0] >= 0
2431 && map_weight_position
[1] >= 0
2432 && map_weight_position
[0] <= weight_map
->height() - 1
2433 && map_weight_position
[1] <= weight_map
->width() - 1)
2434 alignment_weights
->pix(i
, j
) *= weight_map
->get_bl(map_weight_position
);
2439 * Update alignment weights with an internal weight map, reflecting a
2440 * summation of certainty values. Use existing memory structures if
2441 * possible. This function updates alignment_weights_const; hence, it
2442 * should not be called prior to any functions that modify the
2443 * alignment_weights structure.
2445 static void imap_update() {
2446 if (alignment_weights
== NULL
) {
2447 alignment_weights_const
= reference_defined
;
2449 int rows
= reference_image
->height();
2450 int cols
= reference_image
->width();
2452 for (int i
= 0; i
< rows
; i
++)
2453 for (int j
= 0; j
< cols
; j
++)
2454 alignment_weights
->pix(i
, j
) *= reference_defined
->get_pixel(i
, j
);
2456 alignment_weights_const
= alignment_weights
;
2461 * Update alignment weights with algorithmic weights
2463 static void wmx_update() {
2466 static exposure
*exp_def
= new exposure_default();
2467 static exposure
*exp_bool
= new exposure_boolean();
2469 if (wmx_file
== NULL
|| wmx_exec
== NULL
|| wmx_defs
== NULL
)
2472 unsigned int rows
= reference_image
->height();
2473 unsigned int cols
= reference_image
->width();
2475 image_rw::write_image(wmx_file
, reference_image
);
2476 image_rw::write_image(wmx_defs
, reference_defined
, exp_bool
);
2479 int exit_status
= 1;
2481 execlp(wmx_exec
, wmx_exec
, wmx_file
, wmx_defs
, NULL
);
2482 ui::get()->exec_failure(wmx_exec
, wmx_file
, wmx_defs
);
2488 ui::get()->fork_failure("d2::align");
2490 image
*wmx_weights
= image_rw::read_image(wmx_file
, exp_def
);
2492 if (wmx_weights
->height() != rows
|| wmx_weights
->width() != cols
)
2493 ui::get()->error("algorithmic weighting must not change image size");
2495 if (alignment_weights
== NULL
)
2496 alignment_weights
= wmx_weights
;
2498 for (unsigned int i
= 0; i
< rows
; i
++)
2499 for (unsigned int j
= 0; j
< cols
; j
++)
2500 alignment_weights
->pix(i
, j
) *= wmx_weights
->pix(i
, j
);
2505 * Update alignment weights with frequency weights
2507 static void fw_update() {
2509 if (horiz_freq_cut
== 0
2510 && vert_freq_cut
== 0
2511 && avg_freq_cut
== 0)
2515 * Required for correct operation of --fwshow
2518 assert (alignment_weights
== NULL
);
2520 int rows
= reference_image
->height();
2521 int cols
= reference_image
->width();
2522 int colors
= reference_image
->depth();
2524 alignment_weights
= new image_ale_real(rows
, cols
,
2525 colors
, "alignment_weights");
2527 fftw_complex
*inout
= (fftw_complex
*) fftw_malloc(sizeof(fftw_complex
) * rows
* cols
);
2531 fftw_plan pf
= fftw_plan_dft_2d(rows
, cols
,
2533 FFTW_FORWARD
, FFTW_ESTIMATE
);
2535 fftw_plan pb
= fftw_plan_dft_2d(rows
, cols
,
2537 FFTW_BACKWARD
, FFTW_ESTIMATE
);
2539 for (int k
= 0; k
< colors
; k
++) {
2540 for (int i
= 0; i
< rows
* cols
; i
++) {
2541 inout
[i
][0] = reference_image
->get_pixel(i
/ cols
, i
% cols
)[k
];
2546 hipass(rows
, cols
, inout
);
2549 for (int i
= 0; i
< rows
* cols
; i
++) {
2551 alignment_weights
->pix(i
/ cols
, i
% cols
)[k
] = fabs(inout
[i
][0] / (rows
* cols
));
2553 alignment_weights
->pix(i
/ cols
, i
% cols
)[k
] =
2554 sqrt(pow(inout
[i
][0] / (rows
* cols
), 2)
2555 + pow(inout
[i
][1] / (rows
* cols
), 2));
2560 fftw_destroy_plan(pf
);
2561 fftw_destroy_plan(pb
);
2564 if (fw_output
!= NULL
)
2565 image_rw::write_image(fw_output
, alignment_weights
);
2570 * Update alignment to frame N.
2572 static void update_to(int n
) {
2574 assert (n
<= latest
+ 1);
2577 static std::vector
<element_t
> elements
;
2584 * Handle the initial frame
2587 ui::get()->loading_file();
2588 elements
[0].input_frame
= image_rw::open(n
);
2590 const image
*i
= elements
[0].input_frame
;
2592 transformation result
= alignment_class
== 2
2593 ? transformation::gpt_identity(i
, scale_factor
)
2594 : transformation::eu_identity(i
, scale_factor
);
2595 result
= tload_first(tload
, alignment_class
== 2, result
, &is_default
);
2596 tsave_first(tsave
, result
, alignment_class
== 2);
2599 kept_t
= new transformation
[image_rw::count()];
2600 kept_ok
= (int *) malloc(image_rw::count()
2605 if (!kept_t
|| !kept_ok
)
2606 ui::get()->memory_error("alignment");
2616 elements
[0].default_initial_alignment
= result
;
2622 for (int i
= latest
+ 1; i
<= n
; i
++)
2623 for (unsigned int j
= 0; j
< _ma_card
; j
++) {
2625 if (j
>= elements
.size()) {
2626 elements
.resize(j
+ 1);
2627 elements
[j
] = elements
[0];
2628 elements
[j
].default_initial_alignment
=
2629 elements
[j
- 1].default_initial_alignment
;
2630 elements
[j
].default_initial_alignment
.push_element();
2634 * Handle supplemental frames.
2637 assert (reference
!= NULL
);
2639 ui::get()->set_arender_current();
2640 reference
->sync(i
- 1);
2641 ui::get()->clear_arender_current();
2642 reference_image
= reference
->get_image();
2643 reference_defined
= reference
->get_defined();
2650 if (certainty_weights
)
2651 imap_update(); /* Must be called after all other _updates */
2653 assert (reference_image
!= NULL
);
2654 assert (reference_defined
!= NULL
);
2656 ui::get()->loading_file();
2657 elements
[j
].input_frame
= image_rw::open(i
);
2658 elements
[j
].is_primary
= (j
== 0);
2660 _align(i
, _gs
, &elements
[j
]);
2665 if (elements
.size() > _ma_card
)
2666 elements
.resize(_ma_card
);
2672 * Set the control point count
2674 static void set_cp_count(unsigned int n
) {
2675 assert (cp_array
== NULL
);
2678 cp_array
= (const point
**) malloc(n
* sizeof(const point
*));
2682 * Set control points.
2684 static void set_cp(unsigned int i
, const point
*p
) {
2691 static void exp_register() {
2696 * Register exposure only based on metadata
2698 static void exp_meta_only() {
2703 * Don't register exposure
2705 static void exp_noregister() {
2710 * Set alignment class to translation only. Only adjust the x and y
2711 * position of images. Do not rotate input images or perform
2712 * projective transformations.
2714 static void class_translation() {
2715 alignment_class
= 0;
2719 * Set alignment class to Euclidean transformations only. Adjust the x
2720 * and y position of images and the orientation of the image about the
2723 static void class_euclidean() {
2724 alignment_class
= 1;
2728 * Set alignment class to perform general projective transformations.
2729 * See the file gpt.h for more information about general projective
2732 static void class_projective() {
2733 alignment_class
= 2;
2737 * Set the default initial alignment to the identity transformation.
2739 static void initial_default_identity() {
2740 default_initial_alignment_type
= 0;
2744 * Set the default initial alignment to the most recently matched
2745 * frame's final transformation.
2747 static void initial_default_follow() {
2748 default_initial_alignment_type
= 1;
2752 * Perturb output coordinates.
2754 static void perturb_output() {
2759 * Perturb source coordinates.
2761 static void perturb_source() {
2766 * Frames under threshold align optimally
2768 static void fail_optimal() {
2769 is_fail_default
= 0;
2773 * Frames under threshold keep their default alignments.
2775 static void fail_default() {
2776 is_fail_default
= 1;
2780 * Align images with an error contribution from each color channel.
2783 channel_alignment_type
= 0;
2787 * Align images with an error contribution only from the green channel.
2788 * Other color channels do not affect alignment.
2790 static void green() {
2791 channel_alignment_type
= 1;
2795 * Align images using a summation of channels. May be useful when
2796 * dealing with images that have high frequency color ripples due to
2800 channel_alignment_type
= 2;
2804 * Error metric exponent
2807 static void set_metric_exponent(float me
) {
2808 metric_exponent
= me
;
2815 static void set_match_threshold(float mt
) {
2816 match_threshold
= mt
;
2820 * Perturbation lower and upper bounds.
2823 static void set_perturb_lower(ale_pos pl
, int plp
) {
2825 perturb_lower_percent
= plp
;
2828 static void set_perturb_upper(ale_pos pu
, int pup
) {
2830 perturb_upper_percent
= pup
;
2834 * Maximum rotational perturbation.
2837 static void set_rot_max(int rm
) {
2840 * Obtain the largest power of two not larger than rm.
2843 rot_max
= pow(2, floor(log(rm
) / log(2)));
2847 * Barrel distortion adjustment multiplier
2850 static void set_bda_mult(ale_pos m
) {
2855 * Barrel distortion maximum rate of change
2858 static void set_bda_rate(ale_pos m
) {
2866 static void set_lod_max(int lm
) {
2871 * Set the scale factor
2873 static void set_scale(ale_pos s
) {
2878 * Set reference rendering to align against
2880 static void set_reference(render
*r
) {
2885 * Set the interpolant
2887 static void set_interpolant(filter::scaled_filter
*f
) {
2892 * Set alignment weights image
2894 static void set_weight_map(const image
*i
) {
2899 * Set frequency cuts
2901 static void set_frequency_cut(double h
, double v
, double a
) {
2908 * Set algorithmic alignment weighting
2910 static void set_wmx(const char *e
, const char *f
, const char *d
) {
2917 * Show frequency weights
2919 static void set_fl_show(const char *filename
) {
2920 fw_output
= filename
;
2924 * Set transformation file loader.
2926 static void set_tload(tload_t
*tl
) {
2931 * Set transformation file saver.
2933 static void set_tsave(tsave_t
*ts
) {
2938 * Get match statistics for frame N.
2940 static int match(int n
) {
2954 * Message that old alignment data should be kept.
2956 static void keep() {
2957 assert (latest
== -1);
2962 * Get alignment for frame N.
2964 static transformation
of(int n
) {
2977 * Use Monte Carlo alignment sampling with argument N.
2979 static void mc(ale_pos n
) {
2983 static void mcd_limit(int n
) {
2988 * Set the certainty-weighted flag.
2990 static void certainty_weighted(int flag
) {
2991 certainty_weights
= flag
;
2995 * Set the global search type.
2997 static void gs(const char *type
) {
2998 if (!strcmp(type
, "local")) {
3000 } else if (!strcmp(type
, "inner")) {
3002 } else if (!strcmp(type
, "outer")) {
3004 } else if (!strcmp(type
, "all")) {
3006 } else if (!strcmp(type
, "central")) {
3008 } else if (!strcmp(type
, "points")) {
3012 ui::get()->error("bad global search type");
3017 * Multi-alignment contiguity
3019 static void ma_cont(double value
) {
3024 * Multi-alignment cardinality
3026 static void ma_card(unsigned int value
) {
3027 assert (value
>= 1);
3032 * Set the minimum overlap for global searching
3034 static void gs_mo(unsigned int value
) {
3039 * Don't use Monte Carlo alignment sampling.
3041 static void no_mc() {
3046 * Set alignment exclusion regions
3048 static void set_exclusion(exclusion
*_ax_parameters
, int _ax_count
) {
3049 ax_count
= _ax_count
;
3050 ax_parameters
= _ax_parameters
;
3054 * Get match summary statistics.
3056 static ale_accum
match_summary() {
3057 return match_sum
/ match_count
;