assembling: Use fixed point for image assembly
Using floating point causes architecture dependent results due to accuracy/rounding differences. It is not hard to switch to fixed point, and while this does cause quite different rounding errors, the difference is small. Fixes: #200
This commit is contained in:
parent
a7541b1f76
commit
8cc0fd321f
2 changed files with 21 additions and 11 deletions
|
@ -385,8 +385,10 @@ median_filter (int *data, int size, int filtersize)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
interpolate_lines (struct fpi_line_asmbl_ctx *ctx,
|
interpolate_lines (struct fpi_line_asmbl_ctx *ctx,
|
||||||
GSList *line1, float y1, GSList *line2,
|
GSList *line1, gint32 y1_f,
|
||||||
float y2, unsigned char *output, float yi, int size)
|
GSList *line2, gint32 y2_f,
|
||||||
|
unsigned char *output, gint32 yi_f,
|
||||||
|
int size)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned char p1, p2;
|
unsigned char p1, p2;
|
||||||
|
@ -396,10 +398,12 @@ interpolate_lines (struct fpi_line_asmbl_ctx *ctx,
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
|
gint unscaled;
|
||||||
p1 = ctx->get_pixel (ctx, line1, i);
|
p1 = ctx->get_pixel (ctx, line1, i);
|
||||||
p2 = ctx->get_pixel (ctx, line2, i);
|
p2 = ctx->get_pixel (ctx, line2, i);
|
||||||
output[i] = (float) p1
|
|
||||||
+ (yi - y1) / (y2 - y1) * (p2 - p1);
|
unscaled = (yi_f - y1_f) * p2 + (y2_f - yi_f) * p1;
|
||||||
|
output[i] = (unscaled) / (y2_f - y1_f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +428,13 @@ fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx,
|
||||||
/* Number of output lines per distance between two scanners */
|
/* Number of output lines per distance between two scanners */
|
||||||
int i;
|
int i;
|
||||||
GSList *row1, *row2;
|
GSList *row1, *row2;
|
||||||
float y = 0.0;
|
/* The y coordinate is tracked as a 16.16 fixed point number. All
|
||||||
|
* variables postfixed with _f follow this format here and in
|
||||||
|
* interpolate_lines.
|
||||||
|
* We could also use floating point here, but using fixed point means
|
||||||
|
* we get consistent results across architectures.
|
||||||
|
*/
|
||||||
|
gint32 y_f = 0;
|
||||||
int line_ind = 0;
|
int line_ind = 0;
|
||||||
int *offsets = g_new0 (int, num_lines / 2);
|
int *offsets = g_new0 (int, num_lines / 2);
|
||||||
unsigned char *output = g_malloc0 (ctx->line_width * ctx->max_height);
|
unsigned char *output = g_malloc0 (ctx->line_width * ctx->max_height);
|
||||||
|
@ -476,21 +486,21 @@ fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx,
|
||||||
int offset = offsets[i / 2];
|
int offset = offsets[i / 2];
|
||||||
if (offset > 0)
|
if (offset > 0)
|
||||||
{
|
{
|
||||||
float ynext = y + (float) ctx->resolution / offset;
|
gint32 ynext_f = y_f + (ctx->resolution << 16) / offset;
|
||||||
while (line_ind < ynext)
|
while ((line_ind << 16) < ynext_f)
|
||||||
{
|
{
|
||||||
if (line_ind > ctx->max_height - 1)
|
if (line_ind > ctx->max_height - 1)
|
||||||
goto out;
|
goto out;
|
||||||
interpolate_lines (ctx,
|
interpolate_lines (ctx,
|
||||||
row1, y,
|
row1, y_f,
|
||||||
g_slist_next (row1),
|
g_slist_next (row1),
|
||||||
ynext,
|
ynext_f,
|
||||||
output + line_ind * ctx->line_width,
|
output + line_ind * ctx->line_width,
|
||||||
line_ind,
|
line_ind << 16,
|
||||||
ctx->line_width);
|
ctx->line_width);
|
||||||
line_ind++;
|
line_ind++;
|
||||||
}
|
}
|
||||||
y = ynext;
|
y_f = ynext_f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
Loading…
Reference in a new issue