1 // Copyright 2002, 2003, 2004, 2005, 2006 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
25 * ANSI C and POSIX include files.
42 #include "unsupported.h"
43 #include "implication.h"
65 #include "../ale_pos.h"
66 #include "../ale_real.h"
81 * Thread include files
84 #include "../thread.h"
87 * Device configuration files
90 #include "../device/xvp610_320x240.h"
91 #include "../device/xvp610_640x480.h"
92 #include "../device/ov7620_raw_linear.h"
93 #include "../device/canon_300d_raw_linear.h"
94 #include "../device/canon_300d_raw_linear_85mm_1_8.h"
95 #include "../device/canon_300d_raw_linear_50mm_1_8.h"
96 #include "../device/canon_300d_raw_linear_50mm_1_4.h"
97 #include "../device/canon_300d_raw_linear_50mm_1_4_1_4.h"
98 #include "../device/nikon_d50.h"
109 * Flag for global options.
112 static int global_options
;
121 * Counts instances of a given option.
123 static unsigned int arg_count(int argc
, const char *argv
[], const char *arg
) {
124 unsigned int count
= 0;
125 for (int i
= 0; i
< argc
; i
++) {
126 if (!strcmp(argv
[i
], arg
))
128 else if (!strcmp(argv
[i
], "--"))
135 * Argument prefix counter.
137 * Counts instances of a given option prefix.
139 static unsigned int arg_prefix_count(int argc
, const char *argv
[], const char *pfix
) {
140 unsigned int count
= 0;
141 for (int i
= 0; i
< argc
; i
++) {
142 if (!strncmp(argv
[i
], pfix
, strlen(pfix
)))
144 else if (!strcmp(argv
[i
], "--"))
151 * Reallocation function
153 static void *local_realloc(void *ptr
, size_t size
) {
154 void *new_ptr
= realloc(ptr
, size
);
157 ui::get()->memory_error_location("main()");
163 * Not enough arguments function.
165 static void not_enough(const char *opt_name
) {
166 ui::get()->cli_not_enough(opt_name
);
170 * Bad argument function
172 static void bad_arg(const char *opt_name
) {
173 ui::get()->cli_bad_arg(opt_name
);
177 * String comparison class.
180 class compare_strings
{
182 int operator()(const char *A
, const char *B
) const {
183 return strcmp(A
, B
) < 0;
188 * Environment structures.
190 * XXX: It's arguable that these should be public members of the
191 * 'input' class in order to allow passing environment values to other
192 * classes, but, since we're currently using them only to prepare state
193 * for an internal 'input' function, they can stay private for now. A
194 * more nuanced approach will likely be required later.
198 static std::stack
<environment
*> environment_stack
;
199 static std::set
<environment
*> environment_set
;
201 std::map
<const char *, const char *, compare_strings
> environment_map
;
204 * Internal set operations do not protect any data.
207 void internal_set(const char *name
, const char *value
) {
208 environment_map
[name
] = value
;
211 void internal_unset(const char *name
) {
212 environment_map
.erase(name
);
215 const char *internal_convert_pointer(const void *pointer
) {
216 int chars
= sizeof(void *) * 2 + 3;
217 char *c
= (char *) malloc(sizeof(char) * chars
);
222 ui::get()->memory_error_location("environment::set_ptr");
224 int count
= snprintf(c
, chars
, "%p", pointer
);
226 assert (count
>= 0 && count
< chars
);
231 void internal_set_ptr(const char *name
, const void *pointer
) {
232 internal_set(name
, internal_convert_pointer(pointer
));
236 * Check for restricted names.
239 int name_ok(const char *name
) {
240 if (!strcmp(name
, "---chain") || !strcmp(name
, "---this"))
246 void name_check(const char *name
) {
247 if (!name_ok(name
)) {
248 fprintf(stderr
, "Bad set operation.");
257 * Get the environment map.
260 std::map
<const char *, const char *, compare_strings
> &get_map() {
261 return environment_map
;
265 * Public set operations restrict valid names.
268 void set(const char *name
, const char *value
) {
270 internal_set(name
, value
);
273 void unset(const char *name
) {
275 internal_unset(name
);
278 void set_ptr(const char *name
, const void *pointer
) {
280 internal_set_ptr(name
, pointer
);
283 const char *get(const char *name
) {
284 if (environment_map
.count(name
) == 0)
287 return environment_map
[name
];
291 * Make an environment substructure. Note that since deep
292 * structures are currently referenced rather than copied when
293 * the stack is pushed, there is no current need for any
294 * chaining mechanism.
296 void make_substructure(const char *name
) {
297 environment
*s
= new environment
;
299 environment_set
.insert(s
);
302 static int is_env(const char *name
) {
304 sscanf(name
, "%p", &ptr_value
);
307 * Check for bad pointers.
310 if (!environment_set
.count((environment
*) ptr_value
)) {
317 const char *get_option_name(const char *name
) {
318 if (strncmp(name
, "0 ", strlen("0 ")))
321 name
+= strlen("0 ");
323 if (!isdigit(name
[0]))
326 while (isdigit(name
[0]))
329 if (!isspace(name
[0]))
332 while (isspace(name
[0]))
335 if (!isalnum(name
[0]))
341 int is_option(const char *name
) {
342 return (get_option_name(name
) != NULL
);
345 int is_arg(const char *name
, unsigned int arg
) {
346 assert (is_option(name
));
348 int length
= strlen(name
) + 3 * sizeof(unsigned int);
350 char *desired_string
= (char *) malloc(sizeof(char) * length
);
352 snprintf(desired_string
, length
, "%u %s", arg
, name
+ strlen("0 "));
354 int result
= environment_map
.count(desired_string
);
356 free(desired_string
);
361 void remove_arg(const char *name
, unsigned int arg
) {
362 assert (is_option(name
));
363 assert (is_arg(name
, arg
));
365 int length
= strlen(name
) + 3 * sizeof(unsigned int);
367 char *desired_string
= (char *) malloc(sizeof(char) * length
);
369 snprintf(desired_string
, length
, "%u %s", arg
, name
+ strlen("0 "));
371 environment_map
.erase(desired_string
);
374 const char *get_string_arg(const char *name
, unsigned int arg
) {
375 assert (is_option(name
));
377 int length
= strlen(name
) + 3 * sizeof(unsigned int);
379 char *desired_string
= (char *) malloc(sizeof(char) * length
);
381 snprintf(desired_string
, length
, "%u %s", arg
, name
+ strlen("0 "));
383 const char *result
= environment_map
[desired_string
];
387 free(desired_string
);
392 long int get_long_arg(const char *name
, unsigned int arg
) {
393 assert (is_option(name
));
395 const char *string
= get_string_arg(name
, arg
);
398 long int result
= strtol(string
, &endptr
, 0);
400 if (endptr
[0] != '\0') {
401 fprintf(stderr
, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name
));
408 int get_int_arg(const char *name
, unsigned int arg
) {
409 return (int) get_long_arg(name
, arg
);
412 unsigned int get_unsigned_arg(const char *name
, unsigned int arg
) {
413 long int result
= get_long_arg(name
, arg
);
416 fprintf(stderr
, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name
));
420 return (unsigned int) result
;
423 double get_double_arg(const char *name
, unsigned int arg
) {
424 assert (is_option(name
));
426 const char *string
= get_string_arg(name
, arg
);
429 double result
= strtod(string
, &endptr
);
431 if (endptr
[0] != '\0') {
432 fprintf(stderr
, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name
));
439 static environment
*get_env(const char *name
) {
444 sscanf(name
, "%p", &ptr_value
);
447 * Check for bad pointers.
450 if (!environment_set
.count((environment
*) ptr_value
)) {
452 fprintf(stderr
, "Bad environment pointer.\n");
456 return (environment
*) ptr_value
;
462 void prepend(const char *list
, const char *element
) {
463 environment
*d
= get_env(get(list
));
464 make_substructure(list
);
465 get_env(get(list
))->set("a", element
);
466 get_env(get(list
))->set_ptr("d", d
);
469 void prepend_ptr(const char *list
, void *ptr
) {
470 prepend(list
, internal_convert_pointer(ptr
));
474 * Clone the environment.
476 environment
*clone() {
477 environment
*e
= new environment();
479 for (std::map
<const char *, const char *, compare_strings
>::iterator i
= environment_map
.begin();
480 i
!= environment_map
.end(); i
++) {
482 if (!name_ok(i
->first
))
485 if (is_env(i
->second
)) {
486 e
->set_ptr(i
->first
, get_env(i
->second
)->clone());
488 e
->set(i
->first
, i
->second
);
495 static environment
*top() {
496 if (environment_stack
.empty()) {
497 environment_stack
.push(new environment
);
498 environment_set
.insert(environment_stack
.top());
500 return environment_stack
.top();
504 environment
*e
= new environment
;
506 e
->environment_map
= environment_stack
.top()->environment_map
;
508 e
->internal_set_ptr("---chain", environment_stack
.top());
509 e
->internal_set_ptr("---this", e
);
510 e
->make_substructure("---dup");
512 environment_stack
.push(e
);
513 environment_set
.insert(e
);
516 static void dup_second() {
517 environment_stack
.top()->prepend_ptr("---dup",
518 environment::get_env(environment_stack
.top()->get("---chain")));
521 static void push_and_dup_output() {
527 assert(!environment_stack
.empty());
530 * Execution environments should never be referenced by
531 * structures further up the call chain, so they can
532 * safely be deleted. (XXX: In particular, while
533 * lexical scoping may require copying of execution
534 * environments from lower on the call chain, there is
535 * no obvious reason that a reference should be used in
536 * this case; a shallow copy should be used instead.)
539 environment_set
.erase(environment_stack
.top());
540 delete environment_stack
.top();
542 environment_stack
.pop();
546 * Set with duplication.
549 void set_with_dup(const char *name
, const char *value
) {
555 environment
*dup_item
= get_env(get("---dup"));
559 while (dup_item
->get("a")) {
560 get_env(dup_item
->get("a"))->set_with_dup(name
, value
);
561 assert(dup_item
->get("d"));
562 dup_item
= get_env(dup_item
->get("d"));
569 * Read tokens from a stream.
576 virtual const char *get() = 0;
579 * Peek at the next token.
582 virtual const char *peek() = 0;
585 * Divert the stream until the next occurrence of TOKEN.
587 virtual token_reader
*divert(const char *open_token
, const char *close_token
) = 0;
589 virtual int expects_exactly_one_option(void) {
593 virtual ~token_reader() {
597 class argument_parsing_token_reader
: public token_reader
{
599 const char *separators
;
601 argument_parsing_token_reader(const char *s
) {
606 int expects_exactly_one_option(void) {
610 virtual const char *get() {
611 int length
= strcspn(index
, separators
);
616 const char *result
= strndup(index
, length
);
619 if (strspn(index
, separators
) >= 1)
627 virtual const char *peek() {
628 int length
= strcspn(index
, separators
);
633 const char *result
= strndup(index
, length
);
638 virtual token_reader
*divert(const char *open_token
, const char *close_token
) {
644 class cstring_token_reader
: public token_reader
{
645 const char *separators
;
649 cstring_token_reader(const char *s
, int ephemeral
) {
650 assert(ephemeral
== 1);
652 separators
= "\n \t";
658 cstring_token_reader(const char *s
) {
659 separators
= "\n \t";
666 string
+= strspn(string
, separators
);
668 size_t length_to_next
= strcspn(string
, separators
);
670 if (length_to_next
== 0)
673 const char *result
= strndup(string
, length_to_next
);
675 string
+= length_to_next
;
681 string
+= strspn(string
, separators
);
683 size_t length_to_next
= strcspn(string
, separators
);
685 if (length_to_next
== 0)
688 return strndup(string
, length_to_next
);
691 cstring_token_reader
*divert(const char *open_token
, const char *close_token
) {
693 * This function might be broken.
699 int next
= strcspn(string
, separators
);
702 while (*(string
+ search
) != '\0' &&
703 (depth
|| strcmp(close_token
, (string
+ search
)))) {
704 if (!strcmp(close_token
, (string
+ search
)))
706 if (!strcmp(open_token
, (string
+ search
)))
709 next
= strcspn((string
+ next
), separators
);
712 if (*(string
+ search
) == '\0') {
713 fprintf(stderr
, "Parse error: End of scope not found.");
717 cstring_token_reader
*result
= new cstring_token_reader(strndup(string
, search
), 1);
722 * Eat the closing token.
730 ~cstring_token_reader() {
732 free((void *) string
);
736 class cli_token_reader
: public token_reader
{
743 cli_token_reader(int c
, const char *v
[]) {
751 if (arg_index
< argc
)
752 return argv
[arg_index
++];
760 if (arg_index
< argc
)
761 return argv
[arg_index
];
767 cli_token_reader
*divert(const char *open_token
, const char *close_token
) {
771 while (arg_index
+ search
< argc
772 && (depth
|| strcmp(argv
[arg_index
+ search
], close_token
))) {
773 if (!strcmp(close_token
, argv
[arg_index
+ search
]))
775 if (!strcmp(open_token
, argv
[arg_index
+ search
]))
780 if (arg_index
+ search
== argc
) {
781 fprintf(stderr
, "Parse error: end of scope not found.\n");
785 cli_token_reader
*result
= new cli_token_reader(search
, argv
+ arg_index
);
790 * Eat the closing token.
800 struct simple_option
{
802 const char *map_name
;
803 const char *map_value
;
808 static const char *supported_nonglobal_option_table
[];
809 static const char *focus_prefixes
[];
810 static simple_option simple_option_table
[];
812 static int option_name_match(const char *unadorned
, const char *token
, int require_ornamentation
= 1) {
815 if (!strcmp(unadorned
, token
) && !require_ornamentation
)
818 while (token
[0] == '-' && strip_max
) {
821 if (!strcmp(unadorned
, token
))
828 static int is_scope_operator(const char *string
) {
829 if (!strcmp("{", string
)
830 || !strcmp("}", string
)
831 || !strcmp("[", string
)
832 || !strcmp("]", string
)
833 || !strcmp("<", string
)
834 || !strcmp(">", string
))
840 static const char *option_name_gen(const char *unadorned
, const char *map_name
, int arg_num
, int multi
) {
841 static unsigned int multi_counter
= 0;
844 unadorned
= map_name
;
847 int length
= (strlen(unadorned
) + sizeof(unsigned int) * 3 + sizeof(int) * 3 + 2) + 1;
849 char *result
= (char *) malloc(sizeof(char) * length
);
854 snprintf(result
, length
, "%u 0 %s", arg_num
, unadorned
);
858 * XXX: This assumes that generating calls for
859 * options other than 0 exist in the same
860 * multiplicity group as the most recently
861 * generated 0-option multiplicity.
867 snprintf(result
, length
, "%u %u %s", arg_num
, multi_counter
, unadorned
);
873 static environment
*genv
;
875 static const char *get_next(token_reader
*tr
, const char *option_name
) {
876 const char *argument
= tr
->get();
878 if (argument
== NULL
) {
879 fprintf(stderr
, "\n\nError: not enough arguments for `%s'.\n\n", option_name
);
886 static int table_contains(const char **haystack
, const char *needle
, int prefix_length
= 0) {
891 while (*haystack
!= NULL
) {
892 if (prefix_length
== 0 && !strcmp(*haystack
, needle
))
894 if (prefix_length
> 0 && !strncmp(*haystack
, needle
, prefix_length
))
902 static int option_is_identical(environment
*a
, environment
*b
, const char *option_name
) {
903 if (!a
->is_option(option_name
) || !b
->is_option(option_name
))
906 int option_number
= 0;
908 while (a
->is_arg(option_name
, option_number
) || b
->is_arg(option_name
, option_number
)) {
909 if (!a
->is_arg(option_name
, option_number
)
910 || !b
->is_arg(option_name
, option_number
))
913 const char *a_str
= a
->get_string_arg(option_name
, option_number
);
914 const char *b_str
= b
->get_string_arg(option_name
, option_number
);
916 if (strcmp(a_str
, b_str
))
925 static void remove_option(environment
*a
, const char *option_name
) {
926 assert(a
->is_option(option_name
));
928 int option_number
= 0;
930 while (a
->is_arg(option_name
, option_number
)) {
931 a
->remove_arg(option_name
, option_number
);
936 static void remove_nonglobals(environment
*a
) {
939 std::stack
<const char *> removal_stack
;
941 for (std::map
<const char *, const char *, compare_strings
>::iterator i
= a
->get_map().begin();
942 i
!= a
->get_map().end(); i
++) {
944 if (!a
->is_option(i
->first
))
947 if (!table_contains(supported_nonglobal_option_table
, a
->get_option_name(i
->first
)))
950 removal_stack
.push(i
->first
);
953 while (!removal_stack
.empty()) {
954 remove_option(a
, removal_stack
.top());
959 static void option_intersect(environment
*a
, environment
*b
) {
963 std::stack
<const char *> removal_stack
;
965 for (std::map
<const char *, const char *, compare_strings
>::iterator i
= a
->get_map().begin();
966 i
!= a
->get_map().end(); i
++) {
968 if (!a
->is_option(i
->first
))
971 if (option_is_identical(a
, b
, i
->first
))
974 removal_stack
.push(i
->first
);
977 while (!removal_stack
.empty()) {
978 remove_option(a
, removal_stack
.top());
983 static void option_difference(environment
*a
, environment
*b
) {
987 std::stack
<const char *> removal_stack
;
989 for (std::map
<const char *, const char *, compare_strings
>::iterator i
= a
->get_map().begin();
990 i
!= a
->get_map().end(); i
++) {
992 if (!a
->is_option(i
->first
))
995 if (!option_is_identical(a
, b
, i
->first
))
998 removal_stack
.push(i
->first
);
1001 while (!removal_stack
.empty()) {
1002 remove_option(a
, removal_stack
.top());
1003 removal_stack
.pop();
1007 static void evaluate_stream(token_reader
*tr
,
1008 std::vector
<std::pair
<const char *, environment
*> > *files
) {
1010 int end_of_options
= 0;
1012 while ((token
= tr
->get())) {
1018 if (!strcmp(token
, "{") && !end_of_options
) {
1019 environment::push_and_dup_output();
1020 token_reader
*tr_nest
= tr
->divert("{", "}");
1021 evaluate_stream(tr_nest
, files
);
1024 } else if (!strcmp(token
, "[") && !end_of_options
) {
1026 environment::push();
1027 token_reader
*tr_nest
= tr
->divert("[", "]");
1028 evaluate_stream(tr_nest
, files
);
1031 } else if (!strcmp(token
, "<") && !end_of_options
) {
1032 environment
*dup_list
= environment::get_env(environment::top()->get("---dup"));
1033 assert (dup_list
!= NULL
);
1034 dup_list
= dup_list
->clone();
1036 environment::dup_second();
1037 token_reader
*tr_nest
= tr
->divert("<", ">");
1038 evaluate_stream(tr_nest
, files
);
1041 environment::top()->set_ptr("---dup", dup_list
);
1045 * Check for non-whitespace argument separators
1048 else if (!end_of_options
&& token
&& token
[0] == '-' && strchr(token
, '=')) {
1049 environment::push_and_dup_output();
1050 token_reader
*tr_nest
= new argument_parsing_token_reader(token
);
1051 evaluate_stream(tr_nest
, files
);
1057 * Trap the end-of-option indicator.
1060 else if (!strcmp(token
, "--")) {
1066 * Check for options and filenames
1074 if (strncmp("-", token
, strlen("-")) || end_of_options
) {
1079 files
->push_back(std::pair
<const char *, environment
*>(strdup(token
),
1080 environment::top()->clone()));
1082 if (tr
->expects_exactly_one_option() && tr
->get()) {
1083 fprintf(stderr
, "\n\nError: Too many arguments for `%s'.\n\n", token
);
1091 * Handle focus option.
1094 if (option_name_match("focus", token
)) {
1096 environment
*target
;
1097 target
= environment::top();
1099 target
->set_with_dup(option_name_gen("focus", NULL
, 0, 0), "1");
1101 const char *option
= get_next(tr
, "focus");
1103 target
->set_with_dup(option_name_gen("focus", NULL
, 1, 0), option
);
1105 if (!strcmp(option
, "d")) {
1106 target
->set_with_dup(option_name_gen("focus", NULL
, 2, 0),
1107 get_next(tr
, "focus"));
1108 } else if (!strcmp(option
, "p")) {
1109 target
->set_with_dup(option_name_gen("focus", NULL
, 2, 0),
1110 get_next(tr
, "focus"));
1111 target
->set_with_dup(option_name_gen("focus", NULL
, 3, 0),
1112 get_next(tr
, "focus"));
1118 while (table_contains(focus_prefixes
, tr
->peek(), 3)) {
1119 target
->set_with_dup(option_name_gen("focus", NULL
, 4 + arg
, 0),
1120 get_next(tr
, "focus"));
1128 * Handle simple options.
1131 int found_option
= 0;
1132 for (int i
= 0; simple_option_table
[i
].name
; i
++) {
1133 if (!option_name_match(simple_option_table
[i
].name
, token
))
1137 * Handle the match case.
1143 * Determine which environment should be modified
1146 environment
*target
;
1147 target
= environment::top();
1150 * Store information required for
1151 * handling the local case later.
1154 const char *map_value
= "1";
1156 if (simple_option_table
[i
].map_value
) {
1157 map_value
= simple_option_table
[i
].map_value
;
1158 } else if (simple_option_table
[i
].map_name
) {
1159 map_value
= simple_option_table
[i
].name
;
1162 target
->set_with_dup(option_name_gen(simple_option_table
[i
].name
,
1163 simple_option_table
[i
].map_name
,
1165 simple_option_table
[i
].multi
),
1168 for (int j
= 0; j
< simple_option_table
[i
].arg_count
; j
++) {
1169 const char *option
= tr
->get();
1171 if (option
== NULL
) {
1172 fprintf(stderr
, "\n\nError: not enough options for `%s'.\n\n", token
);
1177 * Reject scope operators as options,
1181 if (is_scope_operator(option
)) {
1182 fprintf(stderr
, "\n\nError: illegal argument to `%s'.\n\n", token
);
1186 target
->set_with_dup(option_name_gen(simple_option_table
[i
].name
,
1187 simple_option_table
[i
].map_name
,
1189 simple_option_table
[i
].multi
),
1195 * Trap illegal options.
1199 ui::get()->illegal_option(token
);
1202 if (tr
->expects_exactly_one_option() && tr
->get()) {
1203 fprintf(stderr
, "\n\nError: Too many arguments for `%s'.\n\n", token
);
1213 * Does one of two things:
1215 * (1) Output version information if called with '--version'
1217 * (2) Read options and file arguments, and if the arguments are correct,
1218 * write output. If an error is detected, print the usage statement.
1222 static void handle(int argc
, const char *argv
[], const char *package
, const char *short_version
, const char *version
) {
1225 * Initialize help object
1228 help
hi(package
, argv
[0], short_version
);
1231 * Output version information if --version appears
1232 * on the command line.
1235 if (arg_count(argc
, argv
, "--version")) {
1237 * Output the version
1240 fprintf(stdout
, "%s", version
);
1246 * Handle help options
1249 if (arg_prefix_count(argc
, argv
, "--h"))
1250 for (int i
= 1; i
< argc
; i
++) {
1251 int all
= !strcmp(argv
[i
], "--hA");
1252 int is_help_option
= !strncmp(argv
[i
], "--h", strlen("--h"));
1255 if (!strcmp(argv
[i
], "--hu") || all
)
1256 hi
.usage(), found_help
= 1;
1257 if (!strcmp(argv
[i
], "--hq") || all
)
1258 hi
.defaults(), found_help
= 1;
1259 if (!strcmp(argv
[i
], "--hf") || all
)
1260 hi
.file(), found_help
= 1;
1261 if (!strcmp(argv
[i
], "--he") || all
)
1262 hi
.exclusion(), found_help
= 1;
1263 if (!strcmp(argv
[i
], "--ha") || all
)
1264 hi
.alignment(), found_help
= 1;
1265 if (!strcmp(argv
[i
], "--hr") || all
)
1266 hi
.rendering(), found_help
= 1;
1267 if (!strcmp(argv
[i
], "--hx") || all
)
1268 hi
.exposure(), found_help
= 1;
1269 if (!strcmp(argv
[i
], "--ht") || all
)
1270 hi
.tdf(), found_help
= 1;
1271 if (!strcmp(argv
[i
], "--hl") || all
)
1272 hi
.filtering(), found_help
= 1;
1273 if (!strcmp(argv
[i
], "--hd") || all
)
1274 hi
.device(), found_help
= 1;
1275 if (!strcmp(argv
[i
], "--hi") || all
)
1276 hi
.interface(), found_help
= 1;
1277 if (!strcmp(argv
[i
], "--hv") || all
)
1278 hi
.visp(), found_help
= 1;
1279 if (!strcmp(argv
[i
], "--hc") || all
)
1280 hi
.cp(), found_help
= 1;
1281 if (!strcmp(argv
[i
], "--h3") || all
)
1282 hi
.d3(), found_help
= 1;
1283 if (!strcmp(argv
[i
], "--hs") || all
)
1284 hi
.scope(), found_help
= 1;
1285 if (!strcmp(argv
[i
], "--hp") || all
)
1286 hi
.process(), found_help
= 1;
1287 if (!strcmp(argv
[i
], "--hz") || all
)
1288 hi
.undocumented(), found_help
= 1;
1290 if (is_help_option
&& !found_help
)
1294 * Check for the end-of-options marker, a non-option argument,
1295 * or the end of arguments. In all of these cases, we exit.
1298 if (!strcmp(argv
[i
], "--")
1299 || strncmp(argv
[i
], "--", strlen("--"))
1305 * Undocumented projective transformation utility
1308 if (arg_count(argc
, argv
, "--ptcalc") > 0) {
1309 fprintf(stderr
, "\n\n*** Warning: this feature is not documented ***\n\n");
1310 printf("Enter: w h tlx tly blx bly brx bry trx try x y\n\n");
1312 double w
, h
, tlx
, tly
, blx
, bly
, brx
, bry
, trx
, tr_y
, x
, y
;
1316 if (scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
1317 &w
, &h
, &tlx
, &tly
, &blx
, &bly
, &brx
, &bry
, &trx
, &tr_y
, &x
, &y
) != 12) {
1319 fprintf(stderr
, "Error reading input.\n");
1323 d2::image
*i
= new d2::image_ale_real((int)h
, (int)w
, 3);
1324 d2::transformation t
= d2::transformation::gpt_identity(i
, 1);
1326 d2::point(tly
, tlx
),
1327 d2::point(bly
, blx
),
1328 d2::point(bry
, brx
),
1329 d2::point(tr_y
, trx
)
1333 d2::point
a(y
, x
), b
;
1335 b
= t
.transform_scaled(a
);
1337 printf("TRANSFORM t(a): (%f, %f)\n", (double) b
[1], (double) b
[0]);
1339 b
= t
.scaled_inverse_transform(a
);
1341 printf("INVERSE t^-1(a): (%f, %f)\n", (double) b
[1], (double) b
[0]);
1347 * Thread initialization.
1353 * Flags and variables
1356 double scale_factor
= 1;
1357 double vise_scale_factor
= 1;
1359 double usm_multiplier
= 0.0;
1362 struct d2::tload_t
*tload
= NULL
;
1363 struct d2::tsave_t
*tsave
= NULL
;
1364 struct d3::tload_t
*d3_tload
= NULL
;
1365 struct d3::tsave_t
*d3_tsave
= NULL
;
1366 int ip_iterations
= 0;
1367 int ip_use_median
= 0;
1369 enum { psf_linear
, psf_nonlinear
, psf_N
};
1370 const char *psf
[psf_N
] = {NULL
, NULL
};
1371 const char *device
= NULL
;
1373 double psf_match_args
[6];
1375 int exposure_register
= 1;
1376 const char *wm_filename
= NULL
;
1377 int wm_offsetx
= 0, wm_offsety
= 0;
1378 double cx_parameter
= 1;
1379 double *d3px_parameters
= NULL
;
1381 d2::exclusion
*ex_parameters
= NULL
;
1385 const char *achain_type
= "triangle:2";
1386 const char *afilter_type
= "internal";
1387 d2::render
**ochain
= NULL
;
1388 const char **ochain_names
= NULL
;
1389 const char **ochain_types
= NULL
;
1390 const char *d3chain_type
= NULL
;
1392 const char **visp
= NULL
;
1394 const char **d3_output
= NULL
;
1395 const char **d3_depth
= NULL
;
1396 unsigned int d3_count
= 0;
1397 double user_view_angle
= 0;
1398 int user_bayer
= IMAGE_BAYER_DEFAULT
;
1399 d2::pixel exp_mult
= d2::pixel(1, 1, 1);
1400 std::map
<const char *, d3::pt
> d3_output_pt
;
1401 std::map
<const char *, d3::pt
> d3_depth_pt
;
1404 * dchain is ochain[0].
1407 ochain
= (d2::render
**) local_realloc(ochain
,
1408 (oc_count
+ 1) * sizeof(d2::render
*));
1409 ochain_names
= (const char **) local_realloc((void *)ochain_names
,
1410 (oc_count
+ 1) * sizeof(const char *));
1411 ochain_types
= (const char **) local_realloc((void *)ochain_types
,
1412 (oc_count
+ 1) * sizeof(const char *));
1414 ochain_types
[0] = "sinc*lanc:8";
1419 * Handle default settings
1422 if (arg_prefix_count(argc
, argv
, "--q") > 1)
1423 ui::get()->error("more than one default setting option --q* was specified");
1425 const char *defaults
[] = {
1426 "--dchain fine:triangle:2,triangle:2 "
1427 "--achain triangle:2 "
1429 "--3d-chain fine:triangle:2,triangle:2 ",
1431 "--dchain sinc*lanc:6 "
1432 "--achain sinc*lanc:6 "
1434 "--3d-chain sinc*lanc:6 ",
1436 "--dchain fine:triangle:2,fine:gauss:0.75,triangle:2 "
1437 "--achain triangle:2 "
1439 "--3d-chain fine:triangle:2,fine:gauss:0.75,triangle:2 ",
1441 "--dchain triangle:2 "
1442 "--achain triangle:2 "
1444 "--3d-chain fine:triangle:2,fine:gauss:0.75,triangle:2 ",
1448 if (arg_count(argc
, argv
, "--q0")) {
1450 } else if (arg_count(argc
, argv
, "--qn")) {
1452 } else if (arg_count(argc
, argv
, "--q1")) {
1454 } else if (arg_count(argc
, argv
, "--q2")) {
1456 } else if (arg_count(argc
, argv
, "--qr")) {
1465 token_reader
*default_reader
= new cstring_token_reader(defaults
[default_index
]);
1467 evaluate_stream(default_reader
, NULL
);
1470 * Set basic program information in the environment.
1473 environment::top()->set_with_dup("---package", package
);
1474 environment::top()->set_with_dup("---short-version", short_version
);
1475 environment::top()->set_with_dup("---version", version
);
1476 environment::top()->set_with_dup("---invocation", argv
[0]);
1479 * Initialize the top-level token-reader and generate
1480 * an environment variable for it.
1483 token_reader
*tr
= new cli_token_reader(argc
- 1, argv
+ 1);
1484 environment::top()->set_ptr("---token-reader", tr
);
1487 * Evaluate the command-line arguments to generate environment
1491 std::vector
<std::pair
<const char *, environment
*> > files
;
1493 evaluate_stream(tr
, &files
);
1496 * If there are fewer than two files, then output usage information.
1499 if (files
.size() < 2) {
1505 * Extract the global environment and check non-globals
1506 * against a list of supported non-global options.
1509 genv
= files
[0].second
->clone();
1511 remove_nonglobals(genv
);
1513 for (unsigned int i
= 0; i
< files
.size(); i
++) {
1514 option_intersect(genv
, files
[i
].second
);
1517 for (unsigned int i
= 0; i
< files
.size(); i
++) {
1518 option_difference(files
[i
].second
, genv
);
1520 for (std::map
<const char *, const char *>::iterator j
= files
[i
].second
->get_map().begin();
1521 j
!= files
[i
].second
->get_map().end(); j
++) {
1523 environment
*env
= files
[i
].second
;
1525 if (!env
->is_option(j
->first
))
1528 const char *option_name
= env
->get_option_name(j
->first
);
1530 if (!table_contains(supported_nonglobal_option_table
, option_name
)) {
1531 fprintf(stderr
, "\n\nError: option `%s' must be applied globally.", option_name
);
1532 fprintf(stderr
, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
1540 * Iterate through the global environment,
1541 * looking for options.
1544 for (std::map
<const char *, const char *>::iterator i
= genv
->get_map().begin();
1545 i
!= genv
->get_map().end(); i
++) {
1547 environment
*env
= genv
;
1549 if (!env
->is_option(i
->first
))
1552 const char *option_name
= env
->get_option_name(i
->first
);
1554 if (!strcmp(option_name
, "default")) {
1556 * Do nothing. Defaults have already been set.
1558 } else if (!strcmp(option_name
, "bpc")) {
1559 if (!strcmp(env
->get_string_arg(i
->first
, 0), "8bpc"))
1560 d2::image_rw::depth8();
1561 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "16bpc"))
1562 d2::image_rw::depth16();
1565 } else if (!strcmp(option_name
, "format")) {
1566 if (!strcmp(env
->get_string_arg(i
->first
, 0), "plain"))
1567 d2::image_rw::ppm_plain();
1568 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "raw"))
1569 d2::image_rw::ppm_raw();
1570 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "auto"))
1571 d2::image_rw::ppm_auto();
1574 } else if (!strcmp(option_name
, "align")) {
1575 if (!strcmp(env
->get_string_arg(i
->first
, 0), "align-all"))
1577 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "align-green"))
1579 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "align-sum"))
1583 } else if (!strcmp(option_name
, "transformation")) {
1584 if (!strcmp(env
->get_string_arg(i
->first
, 0), "translation"))
1585 d2::align::class_translation();
1586 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "euclidean"))
1587 d2::align::class_euclidean();
1588 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "projective"))
1589 d2::align::class_projective();
1592 } else if (!strcmp(option_name
, "transformation-default")) {
1593 if (!strcmp(env
->get_string_arg(i
->first
, 0), "identity"))
1594 d2::align::initial_default_identity();
1595 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "follow"))
1596 d2::align::initial_default_follow();
1599 } else if (!strcmp(option_name
, "perturb")) {
1600 if (!strcmp(env
->get_string_arg(i
->first
, 0), "perturb-output"))
1601 d2::align::perturb_output();
1602 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "perturb-source"))
1603 d2::align::perturb_source();
1606 } else if (!strcmp(option_name
, "fail")) {
1607 if (!strcmp(env
->get_string_arg(i
->first
, 0), "fail-optimal"))
1608 d2::align::fail_optimal();
1609 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "fail-default"))
1610 d2::align::fail_default();
1613 } else if (!strcmp(option_name
, "profile")) {
1615 } else if (!strcmp(option_name
, "extend")) {
1616 if (env
->get_int_arg(i
->first
, 0))
1620 } else if (!strcmp(option_name
, "oc")) {
1621 if (env
->get_int_arg(i
->first
, 0))
1625 } else if (!strcmp(option_name
, "focus")) {
1629 double inf
= one
/ zero
;
1631 assert (isinf(inf
) && inf
> 0);
1637 unsigned int type
= 0;
1638 double distance
= 0;
1639 double px
= 0, py
= 0;
1641 if (!strcmp(env
->get_string_arg(i
->first
, 1), "d")) {
1645 distance
= env
->get_double_arg(i
->first
, 2);
1647 } else if (!strcmp(env
->get_string_arg(i
->first
, 1), "p")) {
1651 px
= env
->get_double_arg(i
->first
, 2);
1652 py
= env
->get_double_arg(i
->first
, 3);
1655 bad_arg(option_name
);
1662 unsigned int ci
= 0;
1673 unsigned int sc
= 3;
1674 unsigned int fs
= 0;
1675 unsigned int sr
= 0;
1677 for (int arg_num
= 4; env
->is_arg(i
->first
, arg_num
); arg_num
++) {
1678 const char *option
= env
->get_string_arg(i
->first
, arg_num
);
1679 if (!strncmp(option
, "ci=", 3)) {
1680 if(sscanf(option
+ 3, "%u", &ci
) != 1)
1682 } else if (!strncmp(option
, "fr=", 3)) {
1683 if(sscanf(option
+ 3, "%lf", &fr
) != 1)
1685 } else if (!strncmp(option
, "ht=", 3)) {
1686 if(sscanf(option
+ 3, "%lf", &ht
) != 1)
1688 } else if (!strncmp(option
, "vt=", 3)) {
1689 if(sscanf(option
+ 3, "%lf", &vt
) != 1)
1691 } else if (!strncmp(option
, "sy=", 3)) {
1692 if(sscanf(option
+ 3, "%lf", &sy
) != 1)
1694 } else if (!strncmp(option
, "ey=", 3)) {
1695 if(sscanf(option
+ 3, "%lf", &ey
) != 1)
1697 } else if (!strncmp(option
, "sx=", 3)) {
1698 if(sscanf(option
+ 3, "%lf", &sx
) != 1)
1700 } else if (!strncmp(option
, "ex=", 3)) {
1701 if(sscanf(option
+ 3, "%lf", &ex
) != 1)
1703 } else if (!strncmp(option
, "sd=", 3)) {
1704 if(sscanf(option
+ 3, "%lf", &sd
) != 1)
1706 } else if (!strncmp(option
, "ed=", 3)) {
1707 if(sscanf(option
+ 3, "%lf", &ed
) != 1)
1709 } else if (!strncmp(option
, "ap=", 3)) {
1710 if(sscanf(option
+ 3, "%lf", &ap
) != 1)
1712 } else if (!strncmp(option
, "sc=", 3)) {
1713 if(sscanf(option
+ 3, "%u", &sc
) != 1)
1715 } else if (!strncmp(option
, "sr=", 3)) {
1716 if (!strcmp(option
, "sr=aperture")) {
1718 } else if (!strcmp(option
, "sr=pixel")) {
1723 } else if (!strncmp(option
, "fs=", 3)) {
1724 if (!strcmp(option
, "fs=mean")) {
1726 } else if (!strcmp(option
, "fs=median")) {
1734 d3::focus::add_region(type
, distance
, px
, py
, ci
, fr
, ht
, vt
, sd
, ed
, sx
, ex
, sy
, ey
, ap
, sc
, fs
, sr
);
1736 } else if (!strcmp(option_name
, "3ddp") || !strcmp(option_name
, "3dvp")) {
1740 * Unsupported configurations
1744 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1748 unsupported::fornow("3D modeling with unsharp mask");
1752 * Initialize if necessary
1754 * Note: because their existence is checked as an
1755 * indicator of the presence of 3D arguments, we
1756 * initialize these structures here.
1759 if (d3_output
== NULL
) {
1761 d3_output
= (const char **) calloc(d3_count
, sizeof(char *));
1762 d3_depth
= (const char **) calloc(d3_count
, sizeof(char *));
1765 unsigned int width
, height
;
1770 width
= env
->get_unsigned_arg(i
->first
, 1);
1771 height
= env
->get_unsigned_arg(i
->first
, 2);
1772 view_angle
= env
->get_double_arg(i
->first
, 3);
1773 x
= env
->get_double_arg(i
->first
, 4);
1774 y
= env
->get_double_arg(i
->first
, 5);
1775 z
= env
->get_double_arg(i
->first
, 6);
1776 P
= env
->get_double_arg(i
->first
, 7);
1777 Y
= env
->get_double_arg(i
->first
, 8);
1778 R
= env
->get_double_arg(i
->first
, 9);
1780 view_angle
*= M_PI
/ 180;
1785 d2::transformation t
=
1786 d2::transformation::eu_identity();
1787 t
.set_domain(height
, width
);
1788 d3::pt
_pt(t
, d3::et(y
, x
, z
, Y
, P
, R
), view_angle
);
1790 if (!strcmp(option_name
, "3dvp")) {
1791 d3_output_pt
[env
->get_string_arg(i
->first
, 10)] = _pt
;
1792 } else if (!strcmp(option_name
, "3ddp")) {
1793 d3_depth_pt
[env
->get_string_arg(i
->first
, 10)] = _pt
;
1797 } else if (!strcmp(option_name
, "3dv")) {
1800 unsigned int frame_no
;
1803 * Unsupported configurations
1807 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1811 unsupported::fornow("3D modeling with unsharp mask");
1815 * Initialize if necessary
1818 if (d3_output
== NULL
) {
1820 d3_output
= (const char **) calloc(d3_count
, sizeof(char *));
1821 d3_depth
= (const char **) calloc(d3_count
, sizeof(char *));
1824 frame_no
= env
->get_int_arg(i
->first
, 1);
1826 if (frame_no
>= d3_count
)
1827 ui::get()->error("--3dv argument 0 is too large");
1829 if (d3_output
[frame_no
] != NULL
) {
1830 unsupported::fornow ("Writing a single 3D view to more than one output file");
1833 d3_output
[frame_no
] = env
->get_string_arg(i
->first
, 2);
1835 } else if (!strcmp(option_name
, "3dd")) {
1838 unsigned int frame_no
;
1841 * Unsupported configurations
1845 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1849 unsupported::fornow("3D modeling with unsharp mask");
1853 * Initialize if necessary
1856 if (d3_output
== NULL
) {
1858 d3_output
= (const char **) calloc(d3_count
, sizeof(char *));
1859 d3_depth
= (const char **) calloc(d3_count
, sizeof(char *));
1862 frame_no
= env
->get_int_arg(i
->first
, 1);
1864 if (frame_no
>= d3_count
)
1865 ui::get()->error("--3dd argument 0 is too large");
1867 if (d3_depth
[frame_no
] != NULL
) {
1868 unsupported::fornow ("Writing a single frame's depth info to more than one output file");
1871 d3_depth
[frame_no
] = env
->get_string_arg(i
->first
, 2);
1873 } else if (!strcmp(option_name
, "view-angle")) {
1874 user_view_angle
= env
->get_double_arg(i
->first
, 1) * M_PI
/ 180;
1875 } else if (!strcmp(option_name
, "cpf-load")) {
1876 d3::cpf::init_loadfile(env
->get_string_arg(i
->first
, 1));
1877 } else if (!strcmp(option_name
, "ui")) {
1878 if (!strcmp(env
->get_string_arg(i
->first
, 1), "stream"))
1880 else if (!strcmp(env
->get_string_arg(i
->first
, 1), "tty"))
1882 else if (!strcmp(env
->get_string_arg(i
->first
, 1), "log"))
1884 else if (!strcmp(env
->get_string_arg(i
->first
, 1), "quiet"))
1887 fprintf(stderr
, "Error: Unknown user interface type '%s'\n",
1888 env
->get_string_arg(i
->first
, 1));
1891 } else if (!strcmp(option_name
, "3d-fmr")) {
1892 d3::scene::fmr(env
->get_double_arg(i
->first
, 1));
1893 } else if (!strcmp(option_name
, "3d-dmr")) {
1894 d3::scene::dmr(env
->get_double_arg(i
->first
, 1));
1895 } else if (!strcmp(option_name
, "et")) {
1896 d3::scene::et(env
->get_double_arg(i
->first
, 1));
1897 } else if (!strcmp(option_name
, "st")) {
1898 d3::cpf::st(env
->get_double_arg(i
->first
, 1));
1899 } else if (!strcmp(option_name
, "di-lower")) {
1900 d3::scene::di_lower(env
->get_double_arg(i
->first
, 1));
1901 } else if (!strcmp(option_name
, "rc")) {
1902 d3::scene::rc(env
->get_double_arg(i
->first
, 1));
1903 } else if (!strcmp(option_name
, "do-try")) {
1904 d3::scene::do_try(env
->get_double_arg(i
->first
, 1));
1905 } else if (!strcmp(option_name
, "di-upper")) {
1906 d3::scene::di_upper(env
->get_double_arg(i
->first
, 1));
1907 } else if (!strcmp(option_name
, "fc")) {
1908 d3::scene::fc(env
->get_double_arg(i
->first
, 1));
1909 } else if (!strcmp(option_name
, "ecm")) {
1910 unsupported::discontinued("--ecm <x>");
1911 } else if (!strcmp(option_name
, "acm")) {
1912 unsupported::discontinued("--acm <x>");
1913 } else if (!strcmp(option_name
, "def-nn")) {
1914 d2::image_rw::def_nn(env
->get_double_arg(i
->first
, 1));
1916 if (env
->get_double_arg(i
->first
, 1) > 2) {
1917 fprintf(stderr
, "\n\n*** Warning: --def-nn implementation is currently "
1918 "inefficient for large radii. ***\n\n");
1921 } else if (!strcmp(option_name
, "fx")) {
1922 d3::scene::fx(env
->get_double_arg(i
->first
, 1));
1923 } else if (!strcmp(option_name
, "tcem")) {
1924 d3::scene::tcem(env
->get_double_arg(i
->first
, 1));
1925 } else if (!strcmp(option_name
, "oui")) {
1926 d3::scene::oui(env
->get_unsigned_arg(i
->first
, 1));
1927 } else if (!strcmp(option_name
, "pa")) {
1928 d3::scene::pa(env
->get_unsigned_arg(i
->first
, 1));
1929 } else if (!strcmp(option_name
, "pc")) {
1930 d3::scene::pc(env
->get_string_arg(i
->first
, 1));
1931 } else if (!strcmp(option_name
, "cw")) {
1932 d2::align::certainty_weighted(env
->get_unsigned_arg(i
->first
, 0));
1933 } else if (!strcmp(option_name
, "wm")) {
1934 if (wm_filename
!= NULL
)
1935 ui::get()->error("only one weight map can be specified");
1937 wm_filename
= env
->get_string_arg(i
->first
, 1);
1938 wm_offsetx
= env
->get_int_arg(i
->first
, 2);
1939 wm_offsety
= env
->get_int_arg(i
->first
, 3);
1941 } else if (!strcmp(option_name
, "fl")) {
1943 d2::align::set_frequency_cut(env
->get_double_arg(i
->first
, 1),
1944 env
->get_double_arg(i
->first
, 2),
1945 env
->get_double_arg(i
->first
, 3));
1948 ui::get()->error_hint("--fl is not supported", "rebuild ALE with FFTW support");
1950 } else if (!strcmp(option_name
, "wmx")) {
1952 d2::align::set_wmx(env
->get_string_arg(i
->first
, 1),
1953 env
->get_string_arg(i
->first
, 2),
1954 env
->get_string_arg(i
->first
, 3));
1956 ui::get()->error_hint("--wmx is not supported", "rebuild ALE with support for --wmx");
1958 } else if (!strcmp(option_name
, "flshow")) {
1959 d2::align::set_fl_show(env
->get_string_arg(i
->first
, 1));
1960 } else if (!strcmp(option_name
, "3dpx")) {
1962 d3px_parameters
= (double *) local_realloc(d3px_parameters
, (d3px_count
+ 1) * 6 * sizeof(double));
1964 for (int param
= 0; param
< 6; param
++)
1965 d3px_parameters
[6 * d3px_count
+ param
] = env
->get_double_arg(i
->first
, param
+ 1);
1968 * Swap x and y, since their internal meanings differ from their external meanings.
1971 for (int param
= 0; param
< 2; param
++) {
1972 double temp
= d3px_parameters
[6 * d3px_count
+ 2 + param
];
1973 d3px_parameters
[6 * d3px_count
+ 2 + param
] = d3px_parameters
[6 * d3px_count
+ 0 + param
];
1974 d3px_parameters
[6 * d3px_count
+ 0 + param
] = temp
;
1979 * Increment counters
1984 } else if (!strcmp(option_name
, "ex") || !strcmp(option_name
, "fex")) {
1986 ex_parameters
= (d2::exclusion
*) local_realloc(ex_parameters
,
1987 (ex_count
+ 1) * sizeof(d2::exclusion
));
1989 ex_parameters
[ex_count
].type
= (!strcmp(option_name
, "ex"))
1990 ? d2::exclusion::RENDER
1991 : d2::exclusion::FRAME
;
1994 * Get parameters, swapping x and y coordinates
1997 ex_parameters
[ex_count
].x
[0] = env
->get_int_arg(i
->first
, 1 + 2);
1998 ex_parameters
[ex_count
].x
[1] = env
->get_int_arg(i
->first
, 1 + 3);
1999 ex_parameters
[ex_count
].x
[2] = env
->get_int_arg(i
->first
, 1 + 0);
2000 ex_parameters
[ex_count
].x
[3] = env
->get_int_arg(i
->first
, 1 + 1);
2001 ex_parameters
[ex_count
].x
[4] = env
->get_int_arg(i
->first
, 1 + 4);
2002 ex_parameters
[ex_count
].x
[5] = env
->get_int_arg(i
->first
, 1 + 5);
2005 * Increment counters
2010 } else if (!strcmp(option_name
, "crop") || !strcmp(option_name
, "fcrop")) {
2012 ex_parameters
= (d2::exclusion
*) local_realloc(ex_parameters
,
2013 (ex_count
+ 4) * sizeof(d2::exclusion
));
2015 for (int r
= 0; r
< 4; r
++)
2016 ex_parameters
[ex_count
+ r
].type
= (!strcmp(option_name
, "crop"))
2017 ? d2::exclusion::RENDER
2018 : d2::exclusion::FRAME
;
2023 for (int param
= 0; param
< 6; param
++)
2024 crop_args
[param
] = env
->get_int_arg(i
->first
, param
+ 1);
2027 * Construct exclusion regions from the crop area,
2028 * swapping x and y, since their internal meanings
2029 * differ from their external meanings.
2033 * Exclusion region 1: low x
2036 ex_parameters
[ex_count
+ 0].x
[0] = INT_MIN
;
2037 ex_parameters
[ex_count
+ 0].x
[1] = crop_args
[2] - 1;
2038 ex_parameters
[ex_count
+ 0].x
[2] = INT_MIN
;
2039 ex_parameters
[ex_count
+ 0].x
[3] = INT_MAX
;
2040 ex_parameters
[ex_count
+ 0].x
[4] = crop_args
[4];
2041 ex_parameters
[ex_count
+ 0].x
[5] = crop_args
[5];
2044 * Exclusion region 2: low y
2047 ex_parameters
[ex_count
+ 1].x
[0] = INT_MIN
;
2048 ex_parameters
[ex_count
+ 1].x
[1] = INT_MAX
;
2049 ex_parameters
[ex_count
+ 1].x
[2] = INT_MIN
;
2050 ex_parameters
[ex_count
+ 1].x
[3] = crop_args
[0] - 1;
2051 ex_parameters
[ex_count
+ 1].x
[4] = crop_args
[4];
2052 ex_parameters
[ex_count
+ 1].x
[5] = crop_args
[5];
2055 * Exclusion region 3: high y
2058 ex_parameters
[ex_count
+ 2].x
[0] = INT_MIN
;
2059 ex_parameters
[ex_count
+ 2].x
[1] = INT_MAX
;
2060 ex_parameters
[ex_count
+ 2].x
[2] = crop_args
[1] + 1;
2061 ex_parameters
[ex_count
+ 2].x
[3] = INT_MAX
;
2062 ex_parameters
[ex_count
+ 2].x
[4] = crop_args
[4];
2063 ex_parameters
[ex_count
+ 2].x
[5] = crop_args
[5];
2066 * Exclusion region 4: high x
2069 ex_parameters
[ex_count
+ 3].x
[0] = crop_args
[3] + 1;
2070 ex_parameters
[ex_count
+ 3].x
[1] = INT_MAX
;
2071 ex_parameters
[ex_count
+ 3].x
[2] = INT_MIN
;
2072 ex_parameters
[ex_count
+ 3].x
[3] = INT_MAX
;
2073 ex_parameters
[ex_count
+ 3].x
[4] = crop_args
[4];
2074 ex_parameters
[ex_count
+ 3].x
[5] = crop_args
[5];
2077 * Increment counters
2082 } else if (!strcmp(option_name
, "exshow")) {
2084 } else if (!strcmp(option_name
, "wt")) {
2085 d2::render::set_wt(env
->get_double_arg(i
->first
, 1));
2086 } else if (!strcmp(option_name
, "3d-chain")) {
2087 d3chain_type
= env
->get_string_arg(i
->first
, 1);
2088 } else if (!strcmp(option_name
, "dchain")) {
2089 ochain_types
[0] = env
->get_string_arg(i
->first
, 1);
2090 } else if (!strcmp(option_name
, "achain")) {
2091 achain_type
= env
->get_string_arg(i
->first
, 1);
2092 } else if (!strcmp(option_name
, "afilter")) {
2093 afilter_type
= env
->get_string_arg(i
->first
, 1);
2094 } else if (!strcmp(option_name
, "ochain")) {
2096 ochain
= (d2::render
**) local_realloc(ochain
,
2097 (oc_count
+ 1) * sizeof(d2::render
*));
2098 ochain_names
= (const char **) local_realloc((void *)ochain_names
,
2099 (oc_count
+ 1) * sizeof(const char *));
2100 ochain_types
= (const char **) local_realloc((void *)ochain_types
,
2101 (oc_count
+ 1) * sizeof(const char *));
2103 ochain_types
[oc_count
] = env
->get_string_arg(i
->first
, 1);
2104 ochain_names
[oc_count
] = env
->get_string_arg(i
->first
, 2);
2108 } else if (!strcmp(option_name
, "visp")) {
2110 visp
= (const char **) local_realloc((void *)visp
, 4 *
2111 (vise_count
+ 1) * sizeof(const char *));
2113 for (int param
= 0; param
< 4; param
++)
2114 visp
[vise_count
* 4 + param
] = env
->get_string_arg(i
->first
, param
+ 1);
2118 } else if (!strcmp(option_name
, "cx")) {
2119 cx_parameter
= env
->get_int_arg(i
->first
, 0) ? env
->get_double_arg(i
->first
, 1) : 0;
2120 } else if (!strcmp(option_name
, "ip")) {
2121 unsupported::discontinued("--ip <r> <i>", "--lpsf box=<r> --ips <i>");
2122 } else if (!strcmp(option_name
, "cache")) {
2123 double cache
= env
->get_double_arg(i
->first
, 1);
2125 d2::image_rw::set_cache(cache
);
2127 } else if (!strcmp(option_name
, "bayer")) {
2130 * External order is clockwise from top-left. Internal
2131 * order is counter-clockwise from top-left.
2134 const char *option
= env
->get_string_arg(i
->first
, 1);
2136 if (!strcmp(option
, "rgbg")) {
2137 user_bayer
= IMAGE_BAYER_RGBG
;
2138 } else if (!strcmp(option
, "bgrg")) {
2139 user_bayer
= IMAGE_BAYER_BGRG
;
2140 } else if (!strcmp(option
, "gbgr")) {
2141 user_bayer
= IMAGE_BAYER_GRGB
;
2142 } else if (!strcmp(option
, "grgb")) {
2143 user_bayer
= IMAGE_BAYER_GBGR
;
2144 } else if (!strcmp(option
, "none")) {
2145 user_bayer
= IMAGE_BAYER_NONE
;
2150 } else if (!strcmp(option_name
, "lpsf")) {
2151 psf
[psf_linear
] = env
->get_string_arg(i
->first
, 1);
2152 } else if (!strcmp(option_name
, "nlpsf")) {
2153 psf
[psf_nonlinear
] = env
->get_string_arg(i
->first
, 1);
2154 } else if (!strcmp(option_name
, "psf-match")) {
2158 for (int index
= 0; index
< 6; index
++) {
2159 psf_match_args
[index
] = env
->get_double_arg(i
->first
, index
+ 1);
2162 } else if (!strcmp(option_name
, "device")) {
2163 device
= env
->get_string_arg(i
->first
, 1);
2165 } else if (!strcmp(option_name
, "usm")) {
2167 if (d3_output
!= NULL
)
2168 unsupported::fornow("3D modeling with unsharp mask");
2170 usm_multiplier
= env
->get_double_arg(i
->first
, 1);
2173 } else if (!strcmp(option_name
, "ipr")) {
2175 ip_iterations
= env
->get_int_arg(i
->first
, 1);
2177 ui::get()->warn("--ipr is deprecated. Use --ips instead");
2179 } else if (!strcmp(option_name
, "cpp-err")) {
2180 if (!strcmp(env
->get_string_arg(i
->first
, 0), "median"))
2181 d3::cpf::err_median();
2182 else if (!strcmp(env
->get_string_arg(i
->first
, 0), "mean"))
2183 d3::cpf::err_mean();
2184 } else if (!strcmp(option_name
, "vp-adjust")) {
2185 if (env
->get_int_arg(i
->first
, 0))
2186 d3::align::vp_adjust();
2188 d3::align::vp_noadjust();
2189 } else if (!strcmp(option_name
, "vo-adjust")) {
2190 if (env
->get_int_arg(i
->first
, 0))
2191 d3::align::vo_adjust();
2193 d3::align::vo_noadjust();
2194 } else if (!strcmp(option_name
, "ip-statistic")) {
2195 if (!strcmp(env
->get_string_arg(i
->first
, 1), "mean"))
2197 else if (!strcmp(env
->get_string_arg(i
->first
, 1), "median"))
2199 } else if (!strcmp(option_name
, "ips")) {
2200 ip_iterations
= env
->get_int_arg(i
->first
, 1);
2201 } else if (!strcmp(option_name
, "ip-wl")) {
2202 int limited
= env
->get_int_arg(i
->first
, 0);
2204 ipwl
= env
->get_double_arg(i
->first
, 1);
2208 } else if (!strcmp(option_name
, "ipc")) {
2209 unsupported::discontinued("--ipc <c> <i>", "--ips <i> --lpsf <c>", "--ips <i> --device <c>");
2210 } else if (!strcmp(option_name
, "exp-extend")) {
2211 if (env
->get_int_arg(i
->first
, 0))
2212 d2::image_rw::exp_scale();
2214 d2::image_rw::exp_noscale();
2215 } else if (!strcmp(option_name
, "exp-register")) {
2216 if (env
->get_int_arg(i
->first
, 0) == 1) {
2217 exposure_register
= 1;
2218 d2::align::exp_register();
2219 } else if (env
->get_int_arg(i
->first
, 0) == 0) {
2220 exposure_register
= 0;
2221 d2::align::exp_noregister();
2222 } else if (env
->get_int_arg(i
->first
, 0) == 2) {
2223 exposure_register
= 2;
2224 d2::align::exp_meta_only();
2226 } else if (!strcmp(option_name
, "drizzle-only")) {
2227 unsupported::discontinued("--drizzle-only", "--dchain box:1");
2228 } else if (!strcmp(option_name
, "subspace-traverse")) {
2229 unsupported::undocumented("--subspace-traverse");
2230 d3::scene::set_subspace_traverse();
2231 } else if (!strcmp(option_name
, "3d-filter")) {
2232 if (env
->get_int_arg(i
->first
, 0))
2233 d3::scene::filter();
2235 d3::scene::nofilter();
2236 } else if (!strcmp(option_name
, "occ-norm")) {
2237 if (env
->get_int_arg(i
->first
, 0))
2241 } else if (!strcmp(option_name
, "inc")) {
2242 inc
= env
->get_int_arg(i
->first
, 0);
2243 } else if (!strcmp(option_name
, "exp-mult")) {
2244 double exp_c
, exp_r
, exp_b
;
2246 exp_c
= env
->get_double_arg(i
->first
, 1);
2247 exp_r
= env
->get_double_arg(i
->first
, 2);
2248 exp_b
= env
->get_double_arg(i
->first
, 3);
2250 exp_mult
= d2::pixel(1/(exp_r
* exp_c
), 1/exp_c
, 1/(exp_b
* exp_c
));
2252 } else if (!strcmp(option_name
, "visp-scale")) {
2254 vise_scale_factor
= env
->get_double_arg(i
->first
, 1);
2256 if (vise_scale_factor
<= 0.0)
2257 ui::get()->error("VISP scale must be greater than zero");
2259 if (!finite(vise_scale_factor
))
2260 ui::get()->error("VISP scale must be finite");
2262 } else if (!strcmp(option_name
, "scale")) {
2264 scale_factor
= env
->get_double_arg(i
->first
, 1);
2266 if (scale_factor
<= 0)
2267 ui::get()->error("Scale factor must be greater than zero");
2269 if (!finite(scale_factor
))
2270 ui::get()->error("Scale factor must be finite");
2272 } else if (!strcmp(option_name
, "metric")) {
2273 d2::align::set_metric_exponent(env
->get_double_arg(i
->first
, 1));
2274 } else if (!strcmp(option_name
, "threshold")) {
2275 d2::align::set_match_threshold(env
->get_double_arg(i
->first
, 1));
2276 } else if (!strcmp(option_name
, "drizzle-diam")) {
2277 unsupported::discontinued("--drizzle-diam=<x>", "--dchain box:1");
2278 } else if (!strcmp(option_name
, "perturb-lower")) {
2279 const char *option
= env
->get_string_arg(i
->first
, 1);
2280 double perturb_lower
;
2282 sscanf(option
, "%lf%n", &perturb_lower
, &characters
);
2283 if (perturb_lower
<= 0)
2284 ui::get()->error("--perturb-lower= value is non-positive");
2286 if (*(option
+ characters
) == '%')
2287 d2::align::set_perturb_lower(perturb_lower
, 1);
2289 d2::align::set_perturb_lower(perturb_lower
, 0);
2290 } else if (!strcmp(option_name
, "stepsize")) {
2291 ui::get()->warn("--stepsize is deprecated. Use --perturb-lower instead");
2292 d2::align::set_perturb_lower(env
->get_double_arg(i
->first
, 1), 0);
2293 } else if (!strcmp(option_name
, "va-upper")) {
2294 const char *option
= env
->get_string_arg(i
->first
, 1);
2297 sscanf(option
, "%lf%n", &va_upper
, &characters
);
2298 if (*(option
+ characters
) == '%')
2299 ui::get()->error("--va-upper= does not accept '%' arguments\n");
2301 d3::cpf::set_va_upper(va_upper
);
2302 } else if (!strcmp(option_name
, "cpp-upper")) {
2303 const char *option
= env
->get_string_arg(i
->first
, 1);
2304 double perturb_upper
;
2306 sscanf(option
, "%lf%n", &perturb_upper
, &characters
);
2307 if (*(option
+ characters
) == '%')
2308 ui::get()->error("--cpp-upper= does not currently accept '%' arguments\n");
2310 d3::cpf::set_cpp_upper(perturb_upper
);
2311 } else if (!strcmp(option_name
, "cpp-lower")) {
2312 const char *option
= env
->get_string_arg(i
->first
, 1);
2313 double perturb_lower
;
2315 sscanf(option
, "%lf%n", &perturb_lower
, &characters
);
2316 if (*(option
+ characters
) == '%')
2317 ui::get()->error("--cpp-lower= does not currently accept '%' arguments\n");
2319 d3::cpf::set_cpp_lower(perturb_lower
);
2320 } else if (!strcmp(option_name
, "hf-enhance")) {
2321 unsupported::discontinued("--hf-enhance=<x>");
2322 } else if (!strcmp(option_name
, "rot-upper")) {
2323 d2::align::set_rot_max((int) floor(env
->get_double_arg(i
->first
, 1)));
2324 } else if (!strcmp(option_name
, "bda-mult")) {
2325 d2::align::set_bda_mult(env
->get_double_arg(i
->first
, 1));
2326 } else if (!strcmp(option_name
, "bda-rate")) {
2327 d2::align::set_bda_rate(env
->get_double_arg(i
->first
, 1));
2328 } else if (!strcmp(option_name
, "lod-max")) {
2329 d2::align::set_lod_max((int) floor(env
->get_double_arg(i
->first
, 1)));
2330 } else if (!strcmp(option_name
, "cpf-load")) {
2331 d3::cpf::init_loadfile(env
->get_string_arg(i
->first
, 1));
2333 } else if (!strcmp(option_name
, "model-load")) {
2334 d3::scene::load_model(env
->get_string_arg(i
->first
, 1));
2335 } else if (!strcmp(option_name
, "model-save")) {
2336 d3::scene::save_model(env
->get_string_arg(i
->first
, 1));
2338 } else if (!strcmp(option_name
, "trans-load")) {
2339 d2::tload_delete(tload
);
2340 tload
= d2::tload_new(env
->get_string_arg(i
->first
, 1));
2341 d2::align::set_tload(tload
);
2342 } else if (!strcmp(option_name
, "trans-save")) {
2343 tsave_delete(tsave
);
2344 tsave
= d2::tsave_new(env
->get_string_arg(i
->first
, 1));
2345 d2::align::set_tsave(tsave
);
2346 } else if (!strcmp(option_name
, "3d-trans-load")) {
2347 d3::tload_delete(d3_tload
);
2348 d3_tload
= d3::tload_new(env
->get_string_arg(i
->first
, 1));
2349 d3::align::set_tload(d3_tload
);
2350 } else if (!strcmp(option_name
, "3d-trans-save")) {
2351 d3::tsave_delete(d3_tsave
);
2352 d3_tsave
= d3::tsave_new(env
->get_string_arg(i
->first
, 1));
2353 d3::align::set_tsave(d3_tsave
);
2360 * Apply implication logic.
2363 if (extend
== 0 && vise_count
!= 0) {
2364 implication::changed("VISP requires increased image extents.",
2365 "Image extension is now enabled.",
2370 if (psf_match
&& ex_count
)
2371 unsupported::fornow("PSF calibration with exclusion regions.");
2374 if (d3_output
!= NULL
&& ip_iterations
!= 0)
2375 unsupported::fornow("3D modeling with Irani-Peleg rendering");
2378 if (extend
== 0 && d3_output
!= NULL
) {
2379 implication::changed("3D modeling requires increased image extents.",
2380 "Image extension is now enabled.",
2387 if (cx_parameter
!= 0 && !exposure_register
) {
2388 implication::changed("Certainty-based rendering requires exposure registration.",
2389 "Exposure registration is now enabled.",
2391 d2::align::exp_register();
2392 exposure_register
= 1;
2397 * Set alignment class exclusion region static variables
2400 d2::align::set_exclusion(ex_parameters
, ex_count
);
2403 * Initialize renderer class statics.
2406 d2::render::render_init(ex_count
, ex_parameters
, ex_show
, extend
, scale_factor
);
2412 d2::exposure::set_confidence(cx_parameter
);
2415 * Keep transformations for Irani-Peleg, psf-match, and
2419 if (ip_iterations
> 0 || psf_match
|| vise_count
> 0) {
2424 * Initialize device-specific variables
2427 // int input_file_count = argc - i - 1;
2428 int input_file_count
= files
.size() - 1;
2430 d2::psf
*device_response
[psf_N
] = { NULL
, NULL
};
2431 d2::exposure
**input_exposure
= NULL
;
2432 ale_pos view_angle
= 43.7 * M_PI
/ 180;
2433 // ale_pos view_angle = 90 * M_PI / 180;
2434 input_exposure
= (d2::exposure
**)
2435 // malloc((argc - i - 1) * sizeof(d2::exposure *));
2436 malloc(input_file_count
* sizeof(d2::exposure
*));
2438 if (device
!= NULL
) {
2439 if (!strcmp(device
, "xvp610_640x480")) {
2440 device_response
[psf_linear
] = new xvp610_640x480::lpsf();
2441 device_response
[psf_nonlinear
] = new xvp610_640x480::nlpsf();
2442 for (int ii
= 0; ii
< input_file_count
; ii
++)
2443 input_exposure
[ii
] = new xvp610_640x480::exposure();
2444 view_angle
= xvp610_640x480::view_angle();
2445 } else if (!strcmp(device
, "xvp610_320x240")) {
2446 device_response
[psf_linear
] = new xvp610_320x240::lpsf();
2447 device_response
[psf_nonlinear
] = new xvp610_320x240::nlpsf();
2448 for (int ii
= 0; ii
< input_file_count
; ii
++)
2449 input_exposure
[ii
] = new xvp610_320x240::exposure();
2450 view_angle
= xvp610_320x240::view_angle();
2451 } else if (!strcmp(device
, "ov7620")) {
2452 device_response
[psf_linear
] = new ov7620_raw_linear::lpsf();
2453 device_response
[psf_nonlinear
] = NULL
;
2454 for (int ii
= 0; ii
< input_file_count
; ii
++)
2455 input_exposure
[ii
] = new ov7620_raw_linear::exposure();
2456 d2::image_rw::set_default_bayer(IMAGE_BAYER_BGRG
);
2457 } else if (!strcmp(device
, "canon_300d")) {
2458 device_response
[psf_linear
] = new canon_300d_raw_linear::lpsf();
2459 device_response
[psf_nonlinear
] = NULL
;
2460 for (int ii
= 0; ii
< input_file_count
; ii
++)
2461 input_exposure
[ii
] = new canon_300d_raw_linear::exposure();
2462 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG
);
2463 } else if (!strcmp(device
, "nikon_d50")) {
2464 device_response
[psf_linear
] = nikon_d50::lpsf();
2465 device_response
[psf_nonlinear
] = nikon_d50::nlpsf();
2466 for (int ii
= 0; ii
< input_file_count
; ii
++)
2467 input_exposure
[ii
] = new nikon_d50::exposure();
2468 d2::image_rw::set_default_bayer( nikon_d50::bayer() );
2469 } else if (!strcmp(device
, "canon_300d+85mm_1.8")) {
2470 device_response
[psf_linear
] = new canon_300d_raw_linear_85mm_1_8::lpsf();
2471 device_response
[psf_nonlinear
] = NULL
;
2472 for (int ii
= 0; ii
< input_file_count
; ii
++)
2473 input_exposure
[ii
] = new canon_300d_raw_linear_85mm_1_8::exposure();
2474 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG
);
2475 view_angle
= canon_300d_raw_linear_85mm_1_8::view_angle();
2476 } else if (!strcmp(device
, "canon_300d+50mm_1.8")) {
2477 device_response
[psf_linear
] = new canon_300d_raw_linear_50mm_1_8::lpsf();
2478 device_response
[psf_nonlinear
] = NULL
;
2479 for (int ii
= 0; ii
< input_file_count
; ii
++)
2480 input_exposure
[ii
] = new canon_300d_raw_linear_50mm_1_8::exposure();
2481 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG
);
2482 view_angle
= canon_300d_raw_linear_50mm_1_8::view_angle();
2483 } else if (!strcmp(device
, "canon_300d+50mm_1.4")) {
2484 device_response
[psf_linear
] = new canon_300d_raw_linear_50mm_1_4::lpsf();
2485 device_response
[psf_nonlinear
] = NULL
;
2486 for (int ii
= 0; ii
< input_file_count
; ii
++)
2487 input_exposure
[ii
] = new canon_300d_raw_linear_50mm_1_4::exposure();
2488 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG
);
2489 view_angle
= canon_300d_raw_linear_50mm_1_4::view_angle();
2490 } else if (!strcmp(device
, "canon_300d+50mm_1.4@1.4")) {
2491 device_response
[psf_linear
] = new canon_300d_raw_linear_50mm_1_4_1_4::lpsf();
2492 device_response
[psf_nonlinear
] = NULL
;
2493 for (int ii
= 0; ii
< input_file_count
; ii
++)
2494 input_exposure
[ii
] = new canon_300d_raw_linear_50mm_1_4_1_4::exposure();
2495 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG
);
2496 view_angle
= canon_300d_raw_linear_50mm_1_4_1_4::view_angle();
2498 ui::get()->unknown_device(device
);
2501 for (int ii
= 0; ii
< input_file_count
; ii
++)
2502 input_exposure
[ii
] = new d2::exposure_default();
2506 * User-specified variables.
2509 if (user_view_angle
!= 0) {
2510 view_angle
= user_view_angle
;
2513 if (user_bayer
!= IMAGE_BAYER_DEFAULT
) {
2514 d2::image_rw::set_default_bayer(user_bayer
);
2518 * PSF-match exposure.
2521 delete input_exposure
[input_file_count
- 1];
2522 input_exposure
[input_file_count
- 1] = new d2::exposure_default();
2526 * Initialize output exposure
2529 d2::exposure
*output_exposure
= new d2::exposure_default();
2530 output_exposure
->set_multiplier(exp_mult
);
2533 * Configure the response function.
2536 d2::psf
*response
[2] = {NULL
, NULL
};
2538 for (int n
= 0; n
< psf_N
; n
++ ) {
2539 if (psf
[n
] != NULL
) {
2541 response
[n
] = d2::psf_parse::get((n
== psf_linear
), psf
[n
]);
2543 } else if (device_response
[n
] != NULL
) {
2546 * Device-specific response
2549 response
[n
] = device_response
[n
];
2554 * Default point-spread function.
2557 if (n
== psf_linear
) {
2560 * Default lpsf is a box filter
2561 * of diameter 1.0 (radius
2565 response
[n
] = new d2::box(0.5);
2567 } else if (n
== psf_nonlinear
) {
2570 * nlpsf is disabled by default.
2579 * First file argument. Print general file information as well
2580 * as information specific to this argument. Initialize image
2584 // d2::image_rw::init(argc - i - 1, argv + i, argv[argc - 1], input_exposure, output_exposure);
2585 // ochain_names[0] = argv[argc - 1];
2587 const char **input_files
= (const char **) malloc(sizeof(const char *) * input_file_count
);
2588 for (int i
= 0; i
< input_file_count
; i
++) {
2589 input_files
[i
] = files
[i
].first
;
2592 d2::image_rw::init(input_file_count
, input_files
, files
[files
.size() - 1].first
,
2593 input_exposure
, output_exposure
);
2595 ochain_names
[0] = files
[files
.size() - 1].first
;
2598 * Handle control point data for alignment
2600 d2::align::set_cp_count(d3::cpf::count());
2601 for (unsigned int ii
= 0; ii
< d3::cpf::count(); ii
++)
2602 d2::align::set_cp(ii
, d3::cpf::get_2d(ii
));
2605 * PSF-match bayer patterns.
2609 // d2::image_rw::set_specific_bayer(argc - i - 2, IMAGE_BAYER_NONE);
2610 d2::image_rw::set_specific_bayer(input_file_count
- 1, IMAGE_BAYER_NONE
);
2614 * Handle alignment weight map, if necessary
2617 if (wm_filename
!= NULL
) {
2618 d2::image
*weight_map
;
2619 weight_map
= d2::image_rw::read_image(wm_filename
, new d2::exposure_linear());
2620 weight_map
->set_offset(wm_offsety
, wm_offsetx
);
2621 d2::align::set_weight_map(weight_map
);
2625 * Write comment information about original frame and
2626 * target image to the transformation save file, if we
2630 const d2::image
*im
= d2::image_rw::open(0);
2631 // tsave_orig(tsave, argv[i], im->avg_channel_magnitude());
2632 // tsave_target(tsave, argv[argc - 1]);
2633 tsave_orig(tsave
, files
[0].first
, im
->avg_channel_magnitude());
2634 tsave_target(tsave
, files
[files
.size() - 1].first
);
2635 d2::image_rw::close(0);
2638 * Initialize alignment interpolant.
2641 if (afilter_type
!= "internal")
2642 d2::align::set_interpolant(d2::render_parse::get_SSF(afilter_type
));
2645 * Initialize achain and ochain.
2648 achain
= d2::render_parse::get(achain_type
);
2650 for (int chain
= 0; chain
< oc_count
; chain
++)
2651 ochain
[chain
] = d2::render_parse::get(ochain_types
[chain
]);
2654 * Use merged renderings as reference images in
2658 d2::align::set_reference(achain
);
2661 * Tell the alignment class about the scale factor.
2664 d2::align::set_scale(scale_factor
);
2670 d2::vise_core::set_scale(vise_scale_factor
);
2672 for (int opt
= 0; opt
< vise_count
; opt
++) {
2673 d2::vise_core::add(d2::render_parse::get(visp
[opt
* 4 + 0]),
2680 * Initialize non-incremental renderers
2684 if (usm_multiplier
!= 0) {
2687 * Unsharp Mask renderer
2690 ochain
[0] = new d2::usm(ochain
[0], scale_factor
,
2691 usm_multiplier
, inc
, response
[psf_linear
],
2692 response
[psf_nonlinear
], &input_exposure
[0]);
2699 * Point-spread function calibration renderer.
2700 * This renderer does not produce image output.
2701 * It is reserved for use with the point-spread
2702 * function calibration script
2703 * ale-psf-calibrate.
2706 ochain
[0] = new d2::psf_calibrate(ochain
[0],
2707 1, inc
, response
[psf_linear
],
2708 response
[psf_nonlinear
],
2711 } else if (ip_iterations
!= 0) {
2714 * Irani-Peleg renderer
2717 ochain
[0] = new d2::ipc( ochain
[0], ip_iterations
,
2718 inc
, response
[psf_linear
],
2719 response
[psf_nonlinear
],
2720 (exposure_register
== 1), ip_use_median
, ipwl
);
2724 * Iterate through all files.
2727 for (unsigned int j
= 0; j
< d2::image_rw::count(); j
++) {
2730 * Iterate through non-global options
2733 environment
*env
= files
[j
].second
;
2735 for (std::map
<const char *, const char *>::iterator i
= env
->get_map().begin();
2736 i
!= env
->get_map().end(); i
++) {
2738 if (!env
->is_option(i
->first
))
2741 const char *option_name
= env
->get_option_name(i
->first
);
2743 if (!strcmp(option_name
, "mc")) {
2744 int type
= env
->get_int_arg(i
->first
, 0);
2745 d2::align::mc((type
== 2) ? env
->get_double_arg(i
->first
, 1) / 100
2747 } else if (!strcmp(option_name
, "ma-card")) {
2748 int card
= env
->get_int_arg(i
->first
, 1);
2750 ui::get()->error("--ma-card requires a positive integer");
2751 d2::align::ma_card(card
);
2752 } else if (!strcmp(option_name
, "ma-cont")) {
2753 d2::align::ma_cont(env
->get_double_arg(i
->first
, 1));
2754 } else if (!strcmp(option_name
, "gs")) {
2755 d2::align::gs(env
->get_string_arg(i
->first
, 1));
2756 } else if (!strcmp(option_name
, "gs-mo")) {
2757 const char *option
= env
->get_string_arg(i
->first
, 1);
2760 sscanf(option
, "%lf%n", &gs_mo
, &characters
);
2761 if (*(option
+ characters
) == '%')
2762 d2::align::gs_mo(gs_mo
, 1);
2764 d2::align::gs_mo(gs_mo
, 0);
2765 } else if (!strcmp(option_name
, "ev")) {
2766 double ev
= env
->get_double_arg(i
->first
, 1);
2767 double gain_value
= pow(2, -ev
);
2770 d2::exposure::set_gain_reference(gain_value
);
2772 input_exposure
[j
]->set_gain_multiplier(
2773 d2::exposure::get_gain_reference()
2776 } else if (!strcmp(option_name
, "black")) {
2777 double black
= env
->get_double_arg(i
->first
, 1);
2778 input_exposure
[j
]->set_black_level(black
);
2779 } else if (!strcmp(option_name
, "mcd-removal")) {
2780 d2::align::mcd_limit(env
->get_int_arg(i
->first
, 1));
2781 } else if (!strcmp(option_name
, "perturb-upper")) {
2782 const char *option
= env
->get_string_arg(i
->first
, 1);
2783 double perturb_upper
;
2785 sscanf(option
, "%lf%n", &perturb_upper
, &characters
);
2786 if (*(option
+ characters
) == '%')
2787 d2::align::set_perturb_upper(perturb_upper
, 1);
2789 d2::align::set_perturb_upper(perturb_upper
, 0);
2790 } else if (!strcmp(option_name
, "threads")) {
2791 thread::set_count((unsigned int) env
->get_int_arg(i
->first
, 1));
2792 } else if (!strcmp(option_name
, "per-cpu")) {
2793 thread::set_per_cpu((unsigned int) env
->get_int_arg(i
->first
, 1));
2796 * This error should be encountered earlier.
2801 fprintf(stderr
, "\n\nError: option `%s' must be applied globally.", option_name
);
2802 fprintf(stderr
, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
2812 * Handle the original frame.
2815 // ui::get()->original_frame_start(argv[i]);
2816 ui::get()->original_frame_start(files
[0].first
);
2818 for (int opt
= 0; opt
< oc_count
; opt
++) {
2819 ui::get()->set_orender_current(opt
);
2820 ochain
[opt
]->sync(0);
2822 ui::get()->writing_output(opt
);
2823 d2::image_rw::write_image(ochain_names
[opt
],
2824 ochain
[opt
]->get_image(0));
2828 d2::vise_core::frame_queue_add(0);
2830 ui::get()->original_frame_done();
2836 * Handle supplemental frames.
2839 const char *name
= d2::image_rw::name(j
);
2841 ui::get()->supplemental_frame_start(name
);
2844 * Write comment information about the
2845 * supplemental frame to the transformation
2846 * save file, if we have one.
2849 tsave_info (tsave
, name
);
2851 const d2::image
*im
= d2::image_rw::open(j
);
2852 d2::pixel apm
= im
->avg_channel_magnitude();
2853 tsave_apm(tsave
, apm
[0], apm
[1], apm
[2]);
2854 d2::image_rw::close(j
);
2856 for (int opt
= 0; opt
< oc_count
; opt
++) {
2857 ui::get()->set_orender_current(opt
);
2858 ochain
[opt
]->sync(j
);
2860 ui::get()->writing_output(opt
);
2861 d2::image_rw::write_image(ochain_names
[opt
],
2862 ochain
[opt
]->get_image(j
));
2866 d2::vise_core::frame_queue_add(j
);
2868 ui::get()->supplemental_frame_done();
2872 * Do any post-processing and output final image
2874 * XXX: note that non-incremental renderers currently
2875 * return zero for ochain[0]->sync(), since they write
2876 * output internally when inc != 0.
2879 for (int opt
= 0; opt
< oc_count
; opt
++)
2880 if ((ochain
[opt
]->sync() || !inc
) && !psf_match
) {
2881 ui::get()->writing_output(opt
);
2882 d2::image_rw::write_image(ochain_names
[opt
], ochain
[opt
]->get_image());
2886 * Output a summary match statistic.
2889 ui::get()->ale_2d_done((double) d2::align::match_summary());
2892 * Perform any 3D tasks
2895 optimizations::begin_3d_work();
2899 ui::get()->d3_start();
2901 d3::align::init_angle(view_angle
);
2903 ui::get()->d3_init_view_angle(view_angle
/ M_PI
* 180);
2905 d3::align::init_from_d2();
2907 if (d3::cpf::count() > 0) {
2908 ui::get()->d3_control_point_solve();
2909 d3::cpf::solve_3d();
2910 ui::get()->d3_control_point_solve_done();
2913 ui::get()->d3_final_view_angle(d3::align::angle_of(0) / M_PI
* 180);
2915 d3::align::write_alignments();
2917 d3::scene::set_filter_type(d3chain_type
);
2919 d3::scene::init_from_d2();
2921 ui::get()->d3_subdividing_space();
2922 d3::scene::make_space(d3_depth
, d3_output
, &d3_depth_pt
, &d3_output_pt
);
2923 ui::get()->d3_subdividing_space_done();
2925 ui::get()->d3_updating_occupancy();
2926 d3::scene::reduce_cost_to_search_depth(output_exposure
, inc
);
2927 ui::get()->d3_updating_occupancy_done();
2929 d3::scene::d3px(d3px_count
, d3px_parameters
);
2931 for (unsigned int i
= 0; i
< d2::image_rw::count(); i
++) {
2932 assert (i
< d3_count
);
2934 if (d3_depth
[i
] != NULL
) {
2935 ui::get()->d3_writing_output(d3_depth
[i
]);
2936 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
2937 const d2::image
*im
= d3::scene::depth(i
);
2938 d2::image_rw::write_image(d3_depth
[i
], im
, output_exposure
, 1, 1);
2940 ui::get()->d3_writing_output_done();
2943 if (d3_output
[i
] != NULL
) {
2944 ui::get()->d3_writing_output(d3_output
[i
]);
2945 const d2::image
*im
= d3::scene::view(i
);
2946 d2::image_rw::write_image(d3_output
[i
], im
, output_exposure
);
2948 d3::focus::set_camera(view_count
++);
2949 ui::get()->d3_writing_output_done();
2952 for (std::map
<const char *, d3::pt
>::iterator i
= d3_output_pt
.begin();
2953 i
!= d3_output_pt
.end(); i
++) {
2955 ui::get()->d3_writing_output(i
->first
);
2956 const d2::image
*im
= d3::scene::view(i
->second
);
2957 d2::image_rw::write_image(i
->first
, im
, output_exposure
);
2959 d3::focus::set_camera(view_count
++);
2960 ui::get()->d3_writing_output_done();
2963 for (std::map
<const char *, d3::pt
>::iterator i
= d3_depth_pt
.begin();
2964 i
!= d3_depth_pt
.end(); i
++) {
2966 ui::get()->d3_writing_output(i
->first
);
2967 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
2968 const d2::image
*im
= d3::scene::depth(i
->second
);
2969 d2::image_rw::write_image(i
->first
, im
, output_exposure
, 1, 1);
2971 ui::get()->d3_writing_output_done();
2975 for (unsigned int i
= d2::image_rw::count(); i
< d3_count
; i
++) {
2976 if (d3_depth
[i
] != NULL
) {
2977 fprintf(stderr
, "\n\n*** Frame number for --3dd too high. ***\n\n");
2979 if (d3_output
[i
] != NULL
) {
2980 fprintf(stderr
, "\n\n*** Frame number for --3dv too high. ***\n\n");
2986 * Destroy the image file handler
2989 d2::image_rw::destroy();
2992 * Delete the transformation file structures, if any
2996 tsave_delete(tsave
);
2997 tload_delete(tload
);