Library testbed. This program can access most library functionality.
#include <glib.h>
#include <locale.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include "image.h"
#include "auxfun.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 *Input;
const char *Output;
int ModifyFlags;
bool Inverse;
const char *Lens;
const char *Camera;
float Scale;
float Crop;
float Focal;
float Aperture;
float Distance;
Image::InterpolationMethod Interpolation;
bool Verbose;
} opts =
{
NULL,
NULL,
"output.png",
0,
false,
NULL,
NULL,
1.0f,
0,
0,
0,
1.0f,
Image::I_LANCZOS,
false
};
static void DisplayVersion ()
{
g_print ("Lenstool reference implementation for Lensfun version %d.%d.%d\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 (" -a --all Apply all possible corrections (tca, vign, dist)\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 ("\n");
g_print (" -C# --camera=# Camera name\n");
g_print (" -c# --crop=# Set camera crop factor in case the camera is not given\n");
g_print ("\n");
g_print (" -L# --lens=# Lens name to search for in the database\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 ("\n");
g_print (" -s# --scale=# Apply additional scale on the image\n");
g_print (" -I# --interpol=# Choose interpolation algorithm (n[earest], b[ilinear], l[anczos])\n");
g_print ("\n");
g_print (" -o# --output=# Set file name for output image\n");
g_print (" --verbose Verbose output\n");
g_print (" --version Display program version and exit\n");
g_print (" -h --help Display this help text\n");
}
static bool ParseParameters(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'},
{"all", no_argument, NULL, 'a'},
{"inverse", no_argument, NULL, 'i'},
{"scale", required_argument, NULL, 'S'},
{"lens", required_argument, NULL, 'L'},
{"camera", required_argument, NULL, 'C'},
{"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, 4},
{"verbose", no_argument, NULL, 5},
{0, 0, 0, 0}
};
opts.Program = argv [0];
int c;
while ((c = getopt_long (argc, argv, "o:dg::tvaiS:L:C:c:F:A:D:I:h", 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 {
DisplayUsage();
g_print ("\nTarget lens geometry must be one of 'rectilinear', 'fisheye', 'panoramic', 'equirectangular'\n'orthographic', 'stereographic', 'equisolid', 'thoby'\n");
return false;
}
}
break;
case 't':
break;
case 'v':
break;
case 'a':
break;
case 'i':
opts.Inverse = true;
break;
case 'S':
opts.Scale = _atof (optarg);
break;
case'L':
opts.Lens = optarg;
break;
case'C':
opts.Camera = 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 {
DisplayUsage();
g_print ("\nUnknown interpolation method `%s'\n", optarg);
return false;
}
break;
case 'h':
DisplayUsage ();
return false;
case 4:
DisplayVersion ();
return false;
case 5:
opts.Verbose = true;
break;
default:
return false;
}
}
if (optind <= argc)
opts.Input = argv [optind];
if (!opts.Lens && !opts.Camera) {
DisplayUsage();
g_print ("\nAt least a lens or camera name is required to perform a database lookup!\n");
return false;
}
if (!opts.Lens && opts.Input) {
DisplayUsage();
g_print ("\nNo lens information (-L) supplied to process specified input image!\n");
return false;
}
return true;
}
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;
}
int main (int argc, char **argv)
{
setlocale (LC_ALL, "");
if (!ParseParameters(argc, argv))
return -1;
delete ldb;
g_print ("\rERROR: Database could not be loaded\n");
return -1;
}
if (opts.Camera) {
if (cameras)
cam = cameras[0];
else
g_print ("Cannot find a camera matching `%s' in database\n", opts.Camera);
}
if (opts.Lens) {
if (lenses)
lens = lenses [0];
else
g_print ("Cannot find a lens matching `%s' in database\n", opts.Lens);
}
if (opts.Verbose || !opts.Input) {
if (cam && lens) {
g_print("Matching lens and camera combination found in the database:\n");
PrintCamera(cam, ldb);
PrintLens(lens, ldb);
} else if (!cam && lens) {
g_print("Matching lens found in the database:\n");
PrintLens(lens, ldb);
} else if (!lens && cam) {
g_print("Matching camera found in the database:\n");
PrintCamera(cam, ldb);
}
} else {
if (cam && lens) {
g_print(
"= Selecting %s / %s\n", cam->
Model, lens->
Model);
} else if (!cam && lens) {
g_print(
"= Selecting %s\n", lens->
Model);
}
}
if (!opts.Input) {
delete ldb;
return 0;
}
if (cam)
else if (!opts.Crop)
if (!opts.Focal)
if (!opts.Aperture)
if (opts.Verbose) {
g_print("\nProcessing parameters:\n"
" |- Image crop factor: %g\n"
" |- Focal length: %gmm\n"
" |- Aperture: f/%g\n"
" |- Distance: %gm\n\n",
opts.Crop, opts.Focal, opts.Aperture, opts.Distance);
} else {
g_print("= Processing parameters: Crop %g, Focal %gmm, Aperture f/%g, Distance: %gm\n",
opts.Crop, opts.Focal, opts.Aperture, opts.Distance);
}
Image *img = new Image ();
g_print ("~ Loading `%s' ... ", opts.Input);
if (!img->Open (opts.Input)) {
g_print ("\rERROR: failed to open file `%s'\n", opts.Input);
delete img;
delete ldb;
return -1;
}
if (!img->LoadPNG ()) {
g_print ("\rERROR: failed to parse PNG data from file `%s'\n", opts.Input);
delete img;
delete ldb;
return -1;
}
g_print ("done.\n~ Image size [%ux%u].\n", img->width, img->height);
if (!mod) {
g_print ("\rWarning: failed to create modifier\n");
delete img;
delete ldb;
return -1;
}
opts.Aperture, opts.Distance, opts.Scale, opts.TargetGeom,
opts.ModifyFlags, opts.Inverse);
g_print("~ Selected modifications: ");
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]");
if (modflags==0)
g_print ("[NOTHING]");
g_print ("\n");
g_print("~ Run processing chain... ");
clock_t st;
clock_t xt = clock ();
while (xt == (st = clock ()))
;
img = ApplyModifier (modflags, opts.Inverse, img, mod);
clock_t et = clock ();
g_print ("done (%.3g secs)\n", double (et - st) / CLOCKS_PER_SEC);
delete mod;
g_print ("~ Save output as `%s'...", opts.Output);
bool ok = img->SavePNG (opts.Output);
delete img;
delete ldb;
if (ok) {
g_print (" done\n");
return 0;
} else {
g_print (" FAILED\n");
return -1;
}
}