918 lines
22 KiB
C
918 lines
22 KiB
C
// Copyright 2002, 2003, 2007 David Hilvert <dhilvert@auricle.dyndns.org>,
|
|
// <dhilvert@ugcs.caltech.edu>
|
|
|
|
/* This file is part of the Anti-Lamenessing Engine.
|
|
|
|
The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with the Anti-Lamenessing Engine; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* tfile.h: Read and write transformation data files.
|
|
*/
|
|
|
|
/*
|
|
* This version of ALE reads transformation data file versions 0, 1, 2, and 3,
|
|
* and writes version 2 and 3 transformation data files. Data file versions 1
|
|
* and higher are identified by a version command "V x", where x is the version
|
|
* number, prior to any transformation command. Data file version 0 is
|
|
* identified by having no version command.
|
|
*/
|
|
|
|
#ifndef __tfile_h__
|
|
#define __tfile_h__
|
|
|
|
#include "transformation.h"
|
|
|
|
#define TFILE_VERSION 3
|
|
#define TFILE_VERSION_MAX 3
|
|
|
|
extern int tfile_input_version;
|
|
extern int tfile_output_version;
|
|
|
|
/*
|
|
* Structure to describe a transformation data file to load data from.
|
|
*/
|
|
|
|
struct tload_t {
|
|
const char *filename;
|
|
FILE *file;
|
|
};
|
|
|
|
/*
|
|
* Structure to describe a transformation data file to write data to.
|
|
*/
|
|
|
|
struct tsave_t {
|
|
const char *filename;
|
|
const char *target;
|
|
const char *orig;
|
|
pixel orig_apm;
|
|
FILE *file;
|
|
};
|
|
|
|
/*
|
|
* Create a new tload_t transformation data file structure, used for
|
|
* reading data from transformation data files.
|
|
*/
|
|
|
|
static inline struct tload_t *tload_new(const char *filename) {
|
|
FILE *file = fopen (filename, "r");
|
|
struct tload_t *result = NULL;
|
|
|
|
if (!file) {
|
|
fprintf(stderr, "tload: Error: could not open transformation data file '%s'.", filename);
|
|
exit(1);
|
|
}
|
|
|
|
result = (struct tload_t *)
|
|
malloc(sizeof(struct tload_t));
|
|
result->filename = filename;
|
|
result->file = file;
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Load the first transformation from a transformation data file associated with
|
|
* transformation data file structure T, or return the default transformation
|
|
* if no transformation is available.
|
|
*
|
|
* T is a pointer to the tload_t transformation data file structure.
|
|
*
|
|
* IS_P is nonzero if a projective transformation is expected.
|
|
*
|
|
* DEFAULT_TRANSFORM is the default transformation result.
|
|
*
|
|
* IS_DEFAULT is used to signal a non-default transformation result.
|
|
*/
|
|
|
|
static inline transformation tload_first(struct tload_t *t, int is_p,
|
|
transformation default_transform, int *is_default) {
|
|
|
|
transformation result = default_transform;
|
|
|
|
*is_default = 1;
|
|
|
|
/*
|
|
* If there is no file, return the default.
|
|
*/
|
|
|
|
if (t == NULL)
|
|
return result;
|
|
|
|
/*
|
|
* Search through the initial part of the file to determine
|
|
* its version.
|
|
*/
|
|
|
|
/*
|
|
* Skip comments
|
|
*/
|
|
|
|
int first_character;
|
|
|
|
first_character = fgetc(t->file);
|
|
|
|
while (first_character == ' '
|
|
|| first_character == 0xa
|
|
|| first_character == 0xd
|
|
|| first_character == '\t'
|
|
|| first_character == '#') {
|
|
ungetc(first_character, t->file);
|
|
char line[1024];
|
|
fgets(line, 1024, t->file);
|
|
if (strlen(line) >= 1023) {
|
|
fprintf(stderr,
|
|
"\ntrans-load: Error: line too long in input file\n");
|
|
exit(1);
|
|
}
|
|
|
|
first_character = fgetc(t->file);
|
|
}
|
|
|
|
if (first_character != EOF)
|
|
ungetc(first_character, t->file);
|
|
|
|
/*
|
|
* Check for version 0
|
|
*/
|
|
|
|
if (first_character != 'V')
|
|
|
|
/*
|
|
* Must be version 0.
|
|
*/
|
|
|
|
return result;
|
|
|
|
/*
|
|
* Obtain version from version command string.
|
|
*/
|
|
|
|
char line[1024];
|
|
fgets(line, 1024, t->file);
|
|
if (strlen(line) >= 1023) {
|
|
fprintf(stderr,
|
|
"\ntrans-load: Error: line too long in input file\n");
|
|
exit(1);
|
|
}
|
|
|
|
int count = sscanf(line, "V %d", &tfile_input_version);
|
|
|
|
if (count < 1) {
|
|
fprintf(stderr, "Error in transformation "
|
|
"file version command.\n");
|
|
exit(1);
|
|
} else if (tfile_input_version > TFILE_VERSION_MAX) {
|
|
fprintf(stderr, "Unsupported transformation "
|
|
"file version %d\n",
|
|
tfile_input_version);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Handle versions lower than 3.
|
|
*/
|
|
|
|
if (tfile_input_version < 3)
|
|
|
|
/*
|
|
* Versions lower than 3 use the default transformation
|
|
* for the original frame.
|
|
*/
|
|
|
|
return result;
|
|
|
|
/*
|
|
* Read each line of the file until we find a transformation
|
|
* or EOF.
|
|
*/
|
|
|
|
while (!feof(t->file)) {
|
|
char line[1024];
|
|
|
|
fgets(line, 1024, t->file);
|
|
|
|
if (feof(t->file))
|
|
return result;
|
|
|
|
if (strlen(line) >= 1023) {
|
|
fprintf(stderr,
|
|
"\ntrans-load: Error: line too long in input file\n");
|
|
exit(1);
|
|
}
|
|
|
|
switch (line[0]) {
|
|
case ' ':
|
|
case 0xa:
|
|
case 0xd:
|
|
case '\t':
|
|
case '#':
|
|
/* Comment or whitespace */
|
|
break;
|
|
case 'D':
|
|
case 'd':
|
|
/* Default transformation */
|
|
return result;
|
|
case 'B':
|
|
case 'b':
|
|
if (tfile_input_version < 3) {
|
|
fprintf(stderr, "\ntrans-load: Error: "
|
|
"Barrel distortion not supported "
|
|
"for version %d input files.\n"
|
|
"trans-load: Hint: Use version 3 "
|
|
"file syntax.\n", tfile_input_version);
|
|
exit(1);
|
|
} else {
|
|
unsigned int count;
|
|
unsigned int pos = 0, chars;
|
|
unsigned int bdc;
|
|
double dparameters[BARREL_DEGREE];
|
|
ale_pos parameters[BARREL_DEGREE];
|
|
|
|
count = sscanf(line, "B %u%n", &bdc, &chars);
|
|
pos += chars;
|
|
|
|
if (count < 1) {
|
|
fprintf(stderr, "\ntrans-load: Error: "
|
|
"Malformed 'B' command.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (bdc > result.bd_max()) {
|
|
fprintf(stderr, "\ntrans-load: Error: "
|
|
"Barrel distortion degree %d "
|
|
"is too large. (Maximum is %d.)\n"
|
|
"trans-load: Hint: "
|
|
"Reduce degree or re-compile "
|
|
"with BD_DEGREE=%d\n", bdc, BARREL_DEGREE, bdc);
|
|
exit(1);
|
|
}
|
|
|
|
for (unsigned int d = 0; d < bdc; d++) {
|
|
count = sscanf(line + pos, "%lf%n", &dparameters[d], &chars);
|
|
pos += chars;
|
|
|
|
if (count < 1) {
|
|
fprintf(stderr, "\ntrans-load: Error: "
|
|
"Malformed 'B' command.\n");
|
|
exit(1);
|
|
}
|
|
|
|
parameters[d] = dparameters[d];
|
|
}
|
|
|
|
result.bd_set(bdc, parameters);
|
|
}
|
|
break;
|
|
case 'P':
|
|
case 'p':
|
|
/* Projective transformation data */
|
|
*is_default = 0;
|
|
if (is_p == 0) {
|
|
fprintf(stderr, "\ntrans-load: Error: "
|
|
"Projective data for euclidean "
|
|
"transformation.\n"
|
|
"trans-load: Hint: "
|
|
"Use command-line option --projective.\n");
|
|
exit(1);
|
|
} else {
|
|
double width, height, values[8];
|
|
int count, i;
|
|
point x[4];
|
|
|
|
count = sscanf(line + 1, " %lf%lf%lf%lf%lf%lf%lf%lf%lf%lf", &width, &height,
|
|
&values[0], &values[1], &values[2], &values[3],
|
|
&values[4], &values[5], &values[6], &values[7]);
|
|
|
|
int index = 0;
|
|
for (int i = 0; i < 4; i++)
|
|
for (int j = 1; j >= 0; j--)
|
|
x[i][j] = values[index++];
|
|
|
|
if (count < 10)
|
|
fprintf(stderr, "\ntrans-load: warning:"
|
|
"Missing args for 'P'\n");
|
|
|
|
for (i = 0; i < count - 2; i++) {
|
|
ale_pos factor = (i % 2)
|
|
? ((double) result.scaled_width() / width)
|
|
: ((double) result.scaled_height() / height);
|
|
|
|
x[i / 2][i % 2] *= factor;
|
|
}
|
|
|
|
result.gpt_set(x);
|
|
|
|
return result;
|
|
}
|
|
break;
|
|
case 'E':
|
|
case 'e':
|
|
/* Euclidean transformation data */
|
|
*is_default = 0;
|
|
{
|
|
double width, height;
|
|
double values[3] = {0, 0, 0};
|
|
int count, i;
|
|
ale_pos eu[3];
|
|
|
|
count = sscanf(line + 1, " %lf%lf%lf%lf%lf",
|
|
&width, &height,
|
|
&values[0], &values[1], &values[2]);
|
|
|
|
eu[1] = values[0];
|
|
eu[0] = values[1];
|
|
eu[2] = values[2];
|
|
|
|
if (count < 5)
|
|
fprintf(stderr, "\ntrans-load: warning:"
|
|
"Missing args for 'E'\n");
|
|
|
|
for (i = 0; (i < count - 2) && (i < 2); i++) {
|
|
ale_pos factor = (i % 2)
|
|
? ((double) result.scaled_width() / width)
|
|
: ((double) result.scaled_height() / height);
|
|
|
|
eu[i] *= factor;
|
|
}
|
|
|
|
result.eu_set(eu);
|
|
|
|
return result;
|
|
}
|
|
break;
|
|
default:
|
|
fprintf(stderr,
|
|
"\ntrans-load: Error in tload_first: unrecognized command '%s'\n",
|
|
line);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* EOF reached: return default transformation.
|
|
*/
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Load the next transformation from a transformation data file associated with
|
|
* transformation data file structure T, or return the default transformation
|
|
* if no transformation is available.
|
|
*
|
|
* T is a pointer to the tload_t transformation data file structure.
|
|
*
|
|
* IS_P is nonzero if a projective transformation is expected.
|
|
*
|
|
* DEFAULT_TRANSFORM is the default transformation result.
|
|
*
|
|
* IS_DEFAULT is used to signal a non-default transformation result.
|
|
*
|
|
* IS_PRIMARY is used to differentiate primary and non-primary
|
|
* transformations
|
|
*/
|
|
|
|
static inline transformation tload_next(struct tload_t *t, int is_p,
|
|
transformation default_transform, int *is_default,
|
|
int is_primary) {
|
|
|
|
transformation result = default_transform;
|
|
|
|
*is_default = 1;
|
|
|
|
/*
|
|
* Read each line of the file until we find a transformation.
|
|
*/
|
|
|
|
while (t && !feof(t->file)) {
|
|
|
|
char c = fgetc(t->file);
|
|
if (!feof(t->file) && c != EOF)
|
|
ungetc(c, t->file);
|
|
|
|
if (feof(t->file)
|
|
|| (!is_primary
|
|
&& c != EOF
|
|
&& (c == 'E'
|
|
|| c == 'e'
|
|
|| c == 'P'
|
|
|| c == 'p'
|
|
|| c == 'D'
|
|
|| c == 'd'
|
|
|| c == 'B'
|
|
|| c == 'b'))) {
|
|
return result;
|
|
}
|
|
|
|
char line[1024];
|
|
|
|
fgets(line, 1024, t->file);
|
|
|
|
if (feof(t->file))
|
|
return result;
|
|
|
|
if (strlen(line) >= 1023) {
|
|
fprintf(stderr,
|
|
"\ntrans-load: warning: line too long in input file\n");
|
|
}
|
|
|
|
switch (line[0]) {
|
|
case ' ':
|
|
case 0xa:
|
|
case 0xd:
|
|
case '\t':
|
|
case '#':
|
|
/* Comment or whitespace */
|
|
break;
|
|
case 'D':
|
|
case 'd':
|
|
/* Default transformation */
|
|
return result;
|
|
case 'B':
|
|
case 'b':
|
|
if (tfile_input_version < 3) {
|
|
fprintf(stderr, "\ntrans-load: Error: "
|
|
"Barrel distortion not supported "
|
|
"for version %d input files.\n"
|
|
"trans-load: Hint: Use version 3 "
|
|
"file syntax.\n", tfile_input_version);
|
|
exit(1);
|
|
} else {
|
|
unsigned int count;
|
|
unsigned int pos = 0, chars;
|
|
unsigned int bdc;
|
|
ale_pos parameters[BARREL_DEGREE];
|
|
double dparameters[BARREL_DEGREE];
|
|
|
|
count = sscanf(line, "B %u%n", &bdc, &chars);
|
|
pos += chars;
|
|
|
|
if (count < 1) {
|
|
fprintf(stderr, "\ntrans-load: Error: "
|
|
"Malformed 'B' command.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (bdc > result.bd_max()) {
|
|
fprintf(stderr, "\ntrans-load: Error: "
|
|
"Barrel distortion degree %d "
|
|
"is too large. (Maximum is %d.)\n"
|
|
"trans-load: Hint: "
|
|
"Reduce degree or re-compile "
|
|
"with BD_DEGREE=%d\n", bdc, BARREL_DEGREE, bdc);
|
|
exit(1);
|
|
}
|
|
|
|
for (unsigned int d = 0; d < bdc; d++) {
|
|
count = sscanf(line + pos, "%lf%n", &dparameters[d], &chars);
|
|
pos += chars;
|
|
|
|
if (count < 1) {
|
|
fprintf(stderr, "\ntrans-load: Error: "
|
|
"Malformed 'B' command.\n");
|
|
exit(1);
|
|
}
|
|
|
|
parameters[d] = dparameters[d];
|
|
}
|
|
|
|
result.bd_set(bdc, parameters);
|
|
}
|
|
break;
|
|
case 'Q':
|
|
case 'q':
|
|
if (is_primary)
|
|
break;
|
|
case 'P':
|
|
case 'p':
|
|
/* Projective transformation data */
|
|
if (is_p == 0) {
|
|
fprintf(stderr, "\ntrans-load: Error: "
|
|
"Projective data for euclidean "
|
|
"transformation.\n"
|
|
"trans-load: Hint: "
|
|
"Use command-line option --projective.\n");
|
|
exit(1);
|
|
} else {
|
|
double width, height, values[8];
|
|
int count, i;
|
|
point x[4];
|
|
transformation::multi_coordinate mc1, mc2;
|
|
|
|
count = sscanf(line + 1, " %lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d%d%d", &width, &height,
|
|
&values[0], &values[1], &values[2], &values[3],
|
|
&values[4], &values[5], &values[6], &values[7],
|
|
&mc1.degree, &mc1.x, &mc1.y);
|
|
|
|
if (count == 13) {
|
|
mc2 = default_transform.get_current_coordinate();
|
|
|
|
if (mc1.degree < mc2.degree
|
|
|| mc1.degree == mc2.degree && mc1.y < mc2.y
|
|
|| mc1.degree == mc2.degree && mc1.y == mc2.y && mc1.x < mc2.x)
|
|
break;
|
|
if (mc1.degree != mc2.degree
|
|
|| mc1.x != mc2.x
|
|
|| mc1.y != mc2.y) {
|
|
if (!result.exists(mc1))
|
|
break;
|
|
result.set_current_index(result.get_index(mc1));
|
|
}
|
|
}
|
|
|
|
int index = 0;
|
|
for (int i = 0; i < 4; i++)
|
|
for (int j = 1; j >= 0; j--)
|
|
x[i][j] = values[index++];
|
|
|
|
if (count < 10)
|
|
fprintf(stderr, "\ntrans-load: warning:"
|
|
"Missing args for 'P'\n");
|
|
|
|
for (i = 0; i < count - 2; i++) {
|
|
ale_pos factor = (i % 2)
|
|
? ((double) result.scaled_width() / width)
|
|
: ((double) result.scaled_height() / height);
|
|
|
|
x[i / 2][i % 2] *= factor;
|
|
}
|
|
|
|
if (tfile_input_version < 1) {
|
|
/*
|
|
* Accommodate older versions
|
|
* of tfile.
|
|
*/
|
|
for (i = 0; i < 4; i++) {
|
|
ale_pos y = x[i][0];
|
|
x[i][0] = x[i][1];
|
|
x[i][1] = y;
|
|
}
|
|
result.gpt_v0_set(x);
|
|
} else {
|
|
result.gpt_set(x);
|
|
}
|
|
|
|
*is_default = 0;
|
|
return result;
|
|
}
|
|
break;
|
|
case 'F':
|
|
case 'f':
|
|
if (is_primary)
|
|
break;
|
|
case 'E':
|
|
case 'e':
|
|
/* Euclidean transformation data */
|
|
{
|
|
double width, height;
|
|
double values[3] = {0, 0, 0};
|
|
int count, i;
|
|
ale_pos eu[3];
|
|
transformation::multi_coordinate mc1, mc2;
|
|
|
|
count = sscanf(line + 1, " %lf%lf%lf%lf%lf%d%d%d",
|
|
&width, &height,
|
|
&values[0], &values[1], &values[2],
|
|
&mc1.degree, &mc1.x, &mc1.y);
|
|
|
|
if (count == 8) {
|
|
mc2 = default_transform.get_current_coordinate();
|
|
|
|
if (mc1.degree < mc2.degree
|
|
|| mc1.degree == mc2.degree && mc1.y < mc2.y
|
|
|| mc1.degree == mc2.degree && mc1.y == mc2.y && mc1.x < mc2.x)
|
|
break;
|
|
if (mc1.degree != mc2.degree
|
|
|| mc1.x != mc2.x
|
|
|| mc1.y != mc2.y) {
|
|
if (!result.exists(mc1))
|
|
break;
|
|
result.set_current_index(result.get_index(mc1));
|
|
}
|
|
}
|
|
|
|
|
|
eu[1] = values[0];
|
|
eu[0] = values[1];
|
|
eu[2] = values[2];
|
|
|
|
if (tfile_input_version < 2) {
|
|
ale_pos t = eu[0];
|
|
eu[0] = eu[1];
|
|
eu[1] = t;
|
|
}
|
|
|
|
|
|
if (count < 5)
|
|
fprintf(stderr, "\ntrans-load: warning:"
|
|
"Missing args for 'E'\n");
|
|
|
|
for (i = 0; (i < count - 2) && (i < 2); i++) {
|
|
ale_pos factor = (i % 2)
|
|
? ((double) result.scaled_width() / width)
|
|
: ((double) result.scaled_height() / height);
|
|
|
|
eu[i] *= factor;
|
|
}
|
|
|
|
if (tfile_input_version < 1) {
|
|
result.eu_v0_set(eu);
|
|
} else {
|
|
result.eu_set(eu);
|
|
}
|
|
|
|
*is_default = 0;
|
|
return result;
|
|
}
|
|
break;
|
|
default:
|
|
fprintf(stderr,
|
|
"\ntrans-load: Error in tload_next: unrecognized command '%s'\n",
|
|
line);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Create a new tsave_t transformation data file structure, used for
|
|
* writing data to transformation data files.
|
|
*/
|
|
|
|
static inline struct tsave_t *tsave_new(const char *filename) {
|
|
FILE *file = fopen (filename, "w");
|
|
struct tsave_t *result = NULL;
|
|
|
|
if (!file) {
|
|
fprintf(stderr, "tsave: Error: could not open transformation data file '%s'.", filename);
|
|
exit(1);
|
|
}
|
|
|
|
result = (struct tsave_t *)
|
|
malloc(sizeof(struct tsave_t));
|
|
result->filename = filename;
|
|
result->file = file;
|
|
result->orig = "unknown";
|
|
result->target = "unknown";
|
|
|
|
fprintf(file, "# created by ALE transformation file handler version %d\n",
|
|
TFILE_VERSION);
|
|
|
|
fclose(file);
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Save the first transformation to a transformation data file associated with
|
|
* transformation data file structure T, or do nothing if T is NULL. This
|
|
* function also establishes the output file version.
|
|
*
|
|
* OFFSET is the transformation to be saved.
|
|
*
|
|
* IS_PROJECTIVE indicates whether to write a projective transformation.
|
|
*
|
|
*/
|
|
|
|
static inline void tsave_first(struct tsave_t *t, transformation offset, int is_projective) {
|
|
|
|
if (t == NULL)
|
|
return;
|
|
|
|
t->file = fopen(t->filename, "a");
|
|
|
|
/*
|
|
* Determine the output version to use. We use version 3 output syntax only when
|
|
* necessary. This comprises two cases:
|
|
*
|
|
* (i) an input file is used, and this file uses version 3 syntax.
|
|
* (ii) non-degenerate barrel distortion correction is selected.
|
|
*
|
|
* (i) can be directly examined. When (i) does not hold, (ii) can be
|
|
* inferred from offset.bd_count(), since this value should be constant
|
|
* when (i) does not hold. XXX: This logic should be reviewed.
|
|
*/
|
|
|
|
if (tfile_input_version == 3 || offset.bd_count() > 0)
|
|
tfile_output_version = 3;
|
|
else
|
|
tfile_output_version = 2;
|
|
|
|
|
|
fprintf(t->file, "# producing transformation file syntax version %d\n", tfile_output_version);
|
|
fprintf(t->file, "V %d\n", tfile_output_version);
|
|
|
|
fprintf(t->file, "# Comment: Target output file is %s\n", t->target);
|
|
fprintf(t->file, "# Comment: Original frame is %s\n", t->orig);
|
|
fprintf(t->file, "# Comment: Avg magnitude [r=%f g=%f b=%f]\n", (double) t->orig_apm[0], (double) t->orig_apm[1], (double) t->orig_apm[2]);
|
|
|
|
if (tfile_output_version < 3) {
|
|
fclose(t->file);
|
|
return;
|
|
}
|
|
|
|
if (offset.bd_count() > 0) {
|
|
assert (tfile_output_version >= 3);
|
|
unsigned int i;
|
|
|
|
fprintf(t->file, "B ");
|
|
fprintf(t->file, "%u ", offset.bd_count());
|
|
for (i = 0; i < offset.bd_count(); i++)
|
|
fprintf(t->file, "%f ", (double) offset.bd_get(i));
|
|
fprintf(t->file, "\n");
|
|
}
|
|
|
|
|
|
if (is_projective) {
|
|
int i, j;
|
|
|
|
fprintf(t->file, "P ");
|
|
fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
|
|
for (i = 0; i < 4; i++)
|
|
for (j = 1; j >= 0; j--)
|
|
fprintf(t->file, "%f ", (double) offset.gpt_get(i, j));
|
|
} else {
|
|
fprintf(t->file, "E ");
|
|
fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
|
|
fprintf(t->file, "%f ", (double) offset.eu_get(1));
|
|
fprintf(t->file, "%f ", (double) offset.eu_get(0));
|
|
fprintf(t->file, "%f ", (double) offset.eu_get(2));
|
|
}
|
|
|
|
fprintf(t->file, "\n");
|
|
|
|
fclose(t->file);
|
|
}
|
|
|
|
/*
|
|
* Save the next transformation to a transformation data file associated with
|
|
* transformation data file structure T, or do nothing if T is NULL.
|
|
*
|
|
* OFFSET is the transformation to be saved.
|
|
*
|
|
* IS_PROJECTIVE indicates whether to write a projective transformation.
|
|
*
|
|
* IS_PRIMARY indicates whether to write a primary transformation
|
|
*
|
|
*/
|
|
|
|
static inline void tsave_next(struct tsave_t *t, transformation offset, int is_projective,
|
|
int is_primary) {
|
|
|
|
if (t == NULL)
|
|
return;
|
|
|
|
t->file = fopen(t->filename, "a");
|
|
|
|
if (is_primary && offset.bd_count() > 0) {
|
|
assert (tfile_output_version >= 3);
|
|
unsigned int i;
|
|
|
|
fprintf(t->file, "B ");
|
|
fprintf(t->file, "%u ", offset.bd_count());
|
|
for (i = 0; i < offset.bd_count(); i++)
|
|
fprintf(t->file, "%f ", (double) offset.bd_get(i));
|
|
fprintf(t->file, "\n");
|
|
}
|
|
|
|
if (is_projective) {
|
|
int i, j;
|
|
|
|
fprintf(t->file, is_primary ? "P " : "Q ");
|
|
fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
|
|
for (i = 0; i < 4; i++)
|
|
for (j = 1; j >= 0; j--)
|
|
fprintf(t->file, "%f ", (double) offset.gpt_get(i, j));
|
|
} else {
|
|
fprintf(t->file, is_primary ? "E " : "F ");
|
|
fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
|
|
fprintf(t->file, "%f ", (double) offset.eu_get(1));
|
|
fprintf(t->file, "%f ", (double) offset.eu_get(0));
|
|
fprintf(t->file, "%f ", (double) offset.eu_get(2));
|
|
}
|
|
|
|
if (!is_primary) {
|
|
transformation::multi_coordinate mc = offset.get_current_coordinate();
|
|
fprintf(t->file, "%d %d %d ", mc.degree, mc.x, mc.y);
|
|
}
|
|
|
|
fprintf(t->file, "\n");
|
|
|
|
fclose(t->file);
|
|
}
|
|
|
|
/*
|
|
* Write information to a transformation file indicating the target output
|
|
* file.
|
|
*/
|
|
|
|
static inline void tsave_target(struct tsave_t *t, const char *filename) {
|
|
if (t == NULL)
|
|
return;
|
|
|
|
t->target = filename;
|
|
if (t != NULL) {
|
|
t->file = fopen(t->filename, "a");
|
|
|
|
|
|
fclose(t->file);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Write information to a transformation data file indicating the filename
|
|
* of the original frame (i.e. the first frame in the sequence of input
|
|
* frames).
|
|
*/
|
|
|
|
static inline void tsave_orig(struct tsave_t *t, const char *filename, pixel apm) {
|
|
if (t == NULL)
|
|
return;
|
|
|
|
t->orig = filename;
|
|
t->orig_apm = apm;
|
|
}
|
|
|
|
/*
|
|
* Write information to a transformation data file indicating the filename
|
|
* of a supplemental frame (i.e. a frame in the sequence of input frames
|
|
* that is not the first frame).
|
|
*/
|
|
|
|
static inline void tsave_info(struct tsave_t *t, const char *filename) {
|
|
if (t != NULL) {
|
|
t->file = fopen(t->filename, "a");
|
|
|
|
fprintf(t->file, "# Comment: Supplemental frame %s\n", filename);
|
|
|
|
fclose(t->file);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Write information to a transformation data file indicating the tonal
|
|
* registration multiplier.
|
|
*/
|
|
|
|
static inline void tsave_trm(struct tsave_t *t, ale_real r, ale_real g, ale_real b) {
|
|
if (t != NULL) {
|
|
t->file = fopen(t->filename, "a");
|
|
|
|
fprintf(t->file, "# Comment: Exposure [r=%f g=%f b=%f]\n", (double) r, (double) g, (double) b);
|
|
|
|
fclose(t->file);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Write information to a transformation data file indicating the average
|
|
* pixel magnitude.
|
|
*/
|
|
|
|
static inline void tsave_apm(struct tsave_t *t, ale_real r, ale_real g, ale_real b) {
|
|
if (t != NULL) {
|
|
t->file = fopen(t->filename, "a");
|
|
|
|
fprintf(t->file, "# Comment: Avg magnitude [r=%f g=%f b=%f]\n", (double) r, (double) g, (double) b);
|
|
|
|
fclose(t->file);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Destroy a tload_t transformation data file structure.
|
|
*/
|
|
|
|
static inline void tload_delete(struct tload_t *victim) {
|
|
if (victim)
|
|
fclose(victim->file);
|
|
free(victim);
|
|
}
|
|
|
|
/*
|
|
* Destroy a tsave_t transformation data file structure.
|
|
*/
|
|
|
|
static inline void tsave_delete(struct tsave_t *victim) {
|
|
free(victim);
|
|
}
|
|
|
|
#endif
|