Library testbed. This program can access most library functionality.
#include "image.h"
#include <glib.h>
#include <locale.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#define COMBINE_13
#if defined(_MSC_VER)
#define strcasecmp _stricmp
#define snprintf _snprintf
#define strtof (float)strtod
#endif
static struct
{
const char *Program;
const char *Output;
int ModifyFlags;
bool Inverse;
const char *Lens;
float Scale;
float Crop;
float Focal;
float Aperture;
float Distance;
Image::InterpolationMethod Interpolation;
} opts =
{
NULL,
"out-%s",
0,
false,
"Sigma 14mm f/2.8 EX",
1.0,
0,
0,
0,
1.0,
Image::I_NEAREST,
};
static void DisplayVersion ()
{
g_print ("lensfun version %d.%d.%d: test image modifier routines\n",
g_print ("Copyright (C) 2007 Andrew Zabolotny\n\n");
g_print ("For distribution rules and conditions of use see the file\n");
g_print ("COPYING which is part of the distribution.\n");
}
static void DisplayUsage ()
{
DisplayVersion ();
g_print ("\nCommand-line options:\n\n");
g_print (" -d --distortion Apply lens distortion\n");
g_print (" -g# --geometry=# Convert image geometry to given (one of:\n");
g_print (" rectilinear,fisheye,panoramic,equirectangular,\n");
g_print (" orthographic, stereographic, equisolid, thoby)\n");
g_print (" -t --tca Apply lens chromatic aberrations\n");
g_print (" -v --vignetting Apply lens vignetting\n");
g_print (" -i --inverse Inverse correction of the image (e.g. simulate\n");
g_print (" lens distortions instead of correcting them)\n");
g_print (" -s# --scale=# Apply additional scale on the image\n");
g_print (" -l# --lens=# Use calibration data for this lens\n");
g_print (" -C# --crop=# Set camera crop factor\n");
g_print (" -F# --focal=# Set focal length at which image has been taken\n");
g_print (" -A# --aperture=# Set aperture at which image has been taken\n");
g_print (" -D# --distance=# Set subject distance at which image has been taken\n");
g_print (" -I# --interpol=# Choose interpolation algorithm (n[earest], b[ilinear], l[anczos])\n");
g_print (" -o# --output=# Set file name for output image\n");
g_print (" -V --version Display program version and exit\n");
g_print (" -h --help Display this help text\n");
}
static float _atof (const char *s)
{
char *end = NULL;
float r = strtof (s, &end);
if (end && *end)
{
g_print ("ERROR: Invalid number `%s', parsed as %g\n", s, r);
g_print ("Use your locale-specific number format (e.g. ',' or '.' etc)\n");
exit (-1);
}
return r;
}
static Image *ApplyModifier (int modflags, bool reverse, Image *img,
{
Image *newimg = new Image ();
newimg->Resize (img->width, img->height);
#ifdef COMBINE_13
int lwidth = img->width * 2 * 3;
#else
int lwidth = img->width * 2;
lwidth *= 3;
#endif
float *pos = new float [lwidth];
int step_start = reverse ? 2 : 0;
int step_delta = reverse ? -1 : +1;
int step_finish = reverse ? -1 : 3;
for (int step = step_start; step != step_finish; step += step_delta)
{
RGBpixel *dst = newimg->image;
char *imgdata = (char *)img->image;
bool ok = true;
img->InitInterpolation (opts.Interpolation);
for (unsigned y = 0; ok && y < img->height; y++)
switch (step)
{
#ifdef COMBINE_13
case 0:
ok = false;
break;
case 2:
#else
case 0:
#endif
if (ok)
{
float *src = pos;
for (unsigned x = 0; x < img->width; x++)
{
dst->red = img->GetR (src [0], src [1]);
dst->green = img->GetG (src [2], src [3]);
dst->blue = img->GetB (src [4], src [5]);
src += 2 * 3;
dst++;
}
}
break;
case 1:
LF_CR_4 (RED, GREEN, BLUE, UNKNOWN), 0);
imgdata += img->width * 4;
break;
#ifndef COMBINE_13
case 2:
if (ok)
{
float *src = pos;
for (unsigned x = 0; x < img->width; x++)
{
img->Get (*dst, src [0], src [1]);
src += 2;
dst++;
}
}
break;
#endif
}
if (ok && (step == 0 || step == 2))
{
Image *tmp = newimg;
newimg = img;
img = tmp;
}
}
delete [] pos;
delete newimg;
return img;
}
static bool smartstreq (const char *str, const char *pattern)
{
const char *src = str;
while (*src)
{
char cs = toupper (*src++);
char cp = toupper (*pattern++);
if (!cs)
return (src != str);
if (!cp)
return false;
if (cs != cp)
return false;
}
return true;
}
int main (int argc, char **argv)
{
static struct option long_options[] =
{
{"output", required_argument, NULL, 'o'},
{"distortion", no_argument, NULL, 'd'},
{"geometry", optional_argument, NULL, 'g'},
{"tca", no_argument, NULL, 't'},
{"vignetting", no_argument, NULL, 'v'},
{"inverse", no_argument, NULL, 'i'},
{"scale", required_argument, NULL, 's'},
{"autoscale", no_argument, NULL, 'S'},
{"lens", required_argument, NULL, 'l'},
{"crop", required_argument, NULL, 'C'},
{"focal", required_argument, NULL, 'F'},
{"aperture", required_argument, NULL, 'A'},
{"distance", required_argument, NULL, 'D'},
{"interpol", required_argument, NULL, 'I'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
{0, 0, 0, 0}
};
setlocale (LC_ALL, "");
opts.Program = argv [0];
int c;
while ((c = getopt_long (argc, argv, "o:dg::tvcis:Sl:C:F:A:D:I:hV", long_options, NULL)) != EOF)
{
switch (c)
{
case 'o':
opts.Output = optarg;
break;
case 'd':
break;
case 'g':
if (optarg)
{
if (!strcasecmp (optarg, "rectilinear"))
else if (!strcasecmp (optarg, "fisheye"))
else if (!strcasecmp (optarg, "panoramic"))
else if (!strcasecmp (optarg, "equirectangular"))
else if (!strcasecmp (optarg, "orthographic"))
else if (!strcasecmp (optarg, "stereographic"))
else if (!strcasecmp (optarg, "equisolid"))
else if (!strcasecmp (optarg, "thoby"))
else
{
g_print ("Target lens geometry must be one of 'rectilinear', 'fisheye', 'panoramic', 'equirectangular'\n'orthographic', 'stereographic', 'equisolid', 'thoby'\n");
return -1;
}
}
break;
case 't':
break;
case 'v':
break;
case 'i':
opts.Inverse = true;
break;
case 's':
opts.Scale = _atof (optarg);
break;
case 'S':
opts.Scale = 0.0;
break;
case'l':
opts.Lens = optarg;
break;
case 'C':
opts.Crop = _atof (optarg);
break;
case 'F':
opts.Focal = _atof (optarg);
break;
case 'A':
opts.Aperture = _atof (optarg);
break;
case 'D':
opts.Distance = _atof (optarg);
break;
case 'I':
if (smartstreq (optarg, "nearest"))
opts.Interpolation = Image::I_NEAREST;
else if (smartstreq (optarg, "bilinear"))
opts.Interpolation = Image::I_BILINEAR;
else if (smartstreq (optarg, "lanczos"))
opts.Interpolation = Image::I_LANCZOS;
else
{
g_print ("Unknown interpolation method `%s'\n", optarg);
return -1;
}
break;
case 'h':
DisplayUsage ();
return 0;
case 'V':
DisplayVersion ();
return 0;
default:
return -1;
}
}
if (optind >= argc)
{
g_print ("No files given on command line\n\n");
DisplayUsage ();
return -1;
}
if (!lenses)
{
g_print ("Cannot find the lens `%s' in database\n", opts.Lens);
return -1;
}
const lfLens *lens = lenses [0];
if (!opts.Crop)
if (!opts.Focal)
if (!opts.Aperture)
g_print ("%sCorrecting image as taken by lens `%s, %s'\n"
" at crop factor %g, focal length %g, aperture %g, distance %g\n",
opts.Inverse ?
"Inverse " :
"", lens->
Maker, lens->
Model,
opts.Crop, opts.Focal, opts.Aperture, opts.Distance);
for (; optind < argc; optind++)
{
Image *img = new Image ();
g_print ("Loading `%s' ...", argv [optind]);
if (!img->Open (argv [optind]))
{
g_print ("\rWarning: failed to open file `%s'\n", argv [optind]);
delete img;
continue;
}
if (!img->LoadPNG ())
{
g_print ("\rWarning: failed to parse PNG data from file `%s'\n", argv [optind]);
delete img;
continue;
}
g_print ("\b\b\b[%ux%u], processing", img->width, img->height);
opts.Aperture, opts.Distance, opts.Scale, opts.TargetGeom,
opts.ModifyFlags, opts.Inverse);
if (!mod)
{
g_print ("\rWarning: failed to create modifier\n");
delete img;
continue;
}
if (modflags & LF_MODIFY_TCA)
g_print ("[tca]");
g_print ("[vign]");
g_print ("[dist]");
g_print ("[geom]");
if (opts.Scale != 1.0)
g_print ("[scale]");
g_print (" ...");
clock_t st;
clock_t xt = clock ();
while (xt == (st = clock ()))
;
img = ApplyModifier (modflags, opts.Inverse, img, mod);
clock_t et = clock ();
g_print ("\b\b\b(%.2g secs)", double (et - st) / CLOCKS_PER_SEC);
char out_fname [200];
snprintf (out_fname, sizeof (out_fname), opts.Output, argv [optind]);
g_print (", saving `%s'...", out_fname);
bool ok = img->SavePNG (out_fname);
delete img;
g_print ("\b\b\b\b, %s\n", ok ? "done" : "FAILED");
}
return 0;
}