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: ");
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;
}
}
#define LF_VERSION_MICRO
Library micro version number.
Definition: lensfun.h:53
#define LF_VERSION_MAJOR
Major library version number.
Definition: lensfun.h:49
#define LF_VERSION_MINOR
Minor library version number.
Definition: lensfun.h:51
@ LF_NO_ERROR
Definition: lensfun.h:116
#define LF_CR_4(a, b, c, d)
This macro defines a pixel format consisting of four components.
Definition: lensfun.h:1832
@ LF_MODIFY_TCA
Definition: lensfun.h:1762
@ LF_MODIFY_VIGNETTING
Definition: lensfun.h:1764
@ LF_MODIFY_GEOMETRY
Definition: lensfun.h:1769
@ LF_MODIFY_DISTORTION
Definition: lensfun.h:1767
@ LF_MODIFY_SCALE
Definition: lensfun.h:1771
@ LF_PF_U8
Definition: lensfun.h:1780
lfLensType
Lens type. See Change of projection for further information.
Definition: lensfun.h:748
@ LF_FISHEYE
Equidistant fisheye.
Definition: lensfun.h:761
@ LF_FISHEYE_EQUISOLID
Equisolid fisheye.
Definition: lensfun.h:781
@ LF_FISHEYE_THOBY
Fisheye as measured by Thoby (for Nikkor 10.5).
Definition: lensfun.h:787
@ LF_FISHEYE_ORTHOGRAPHIC
Orthographic fisheye.
Definition: lensfun.h:777
@ LF_EQUIRECTANGULAR
Equirectangular.
Definition: lensfun.h:775
@ LF_RECTILINEAR
Rectilinear lens.
Definition: lensfun.h:755
@ LF_FISHEYE_STEREOGRAPHIC
Stereographic fisheye.
Definition: lensfun.h:779
@ LF_PANORAMIC
Panoramic (cylindrical)
Definition: lensfun.h:768
Camera data. Unknown fields are set to NULL.
Definition: lensfun.h:321
lfMLstr Model
Model name (ex: "Rolleiflex SL35") – same as in EXIF.
Definition: lensfun.h:325
float CropFactor
Camera crop factor (ex: 1.0). Must be defined.
Definition: lensfun.h:331
A lens database object.
Definition: lensfun.h:1362
const lfLens ** FindLenses(const lfCamera *camera, const char *maker, const char *model, int sflags=0) const
Parse a human-friendly lens description (ex: "smc PENTAX-F 35-105mm F4-5.6" or "SIGMA AF 28-300 F3....
const lfCamera ** FindCamerasExt(const char *maker, const char *model, int sflags=0) const
Searches all translations of camera maker and model.
lfError Load()
Find and load the lens database.
Lens data. Unknown fields are set to NULL or 0.
Definition: lensfun.h:802
lfMLstr Model
Definition: lensfun.h:806
float CropFactor
Definition: lensfun.h:830
float MinFocal
Definition: lensfun.h:808
float MinAperture
Definition: lensfun.h:812
A modifier object contains optimized data required to rectify a image.
Definition: lensfun.h:2016
int Initialize(const lfLens *lens, lfPixelFormat format, float focal, float aperture, float distance, float scale, lfLensType targeom, int flags, bool reverse)
Initialize the process of correcting aberrations in a image.
bool ApplySubpixelGeometryDistortion(float xu, float yu, int width, int height, float *res) const
Apply stage 2 & 3 in one step.
bool ApplyColorModification(void *pixels, float x, float y, int width, int height, int comp_role, int row_stride) const
Image correction step 1: fix image colors.
bool ApplyGeometryDistortion(float xu, float yu, int width, int height, float *res) const
Image correction step 2: apply the transforms on a block of pixel coordinates.
bool ApplySubpixelDistortion(float xu, float yu, int width, int height, float *res) const
Image correction step 3: apply subpixel distortions.