ImageLensCorrection provides corrections for the four most common camera-lens defects — radial (barrel/pincushion) distortion, vignetting, lateral chromatic aberration (TCA), and geometric projection — for images created or processed with the :image library. Calibration coefficients come from the lensfun project's community-maintained database, which is bundled with the package as a compact ~5 MB Erlang term file covering 1000+ camera bodies and 1400+ lenses.
Corrections are evaluated as libvips arithmetic expressions on top of Vix, so every correction stays inside the Vix pipeline; no external C library is required at runtime.
Documentation can be found at https://hexdocs.pm/image_lens_correction.
-
Radial distortion correction — implements the lensfun
:ptlens,:poly3and:poly5models, all inverted per pixel via Newton's method evaluated aslibvipsarithmetic. -
Vignetting correction — implements the lensfun
:pamodelCd = Cs * (1 + k1*r² + k2*r⁴ + k3*r⁶), inverted analytically. -
Lateral chromatic aberration (TCA) — implements the lensfun
:linearand:poly3TCA models. The image is decomposed into bands, red and blue are remapped per channel viamapim, green is taken as the reference, and RGBA inputs preserve their alpha channel. -
Geometric projection — converts between
:rectilinear,:fisheyeand:equirectangularprojections. -
EXIF-driven, one-call correction —
Image.LensFun.Correct.correct/2reads camera and lens metadata from the image's EXIF tags, looks the lens up in the bundled database, interpolates the calibration to the image's focal length and aperture, rescales coefficients to the camera's crop factor, and applies the requested corrections in one pipeline. Every EXIF tag is overridable via options for images that lack metadata. -
Database lookup primitives —
Image.LensFun.find_lens/3,Image.LensFun.find_camera/2,Image.LensFun.interpolate_distortion/2,Image.LensFun.interpolate_vignetting/4andImage.LensFun.interpolate_tca/2for direct programmatic access to the bundled calibration data, with case-insensitive maker matching, fuzzy-substring lens-model matching and crop-factor-narrowing. -
Bundled calibration database —
priv/lensfun/lensfun.etfis generated from the lensfun XML database at build time and decoded once into a:persistent_termcache on first use.
The package can be installed by adding image_lens_correction to your list of dependencies in mix.exs:
def deps do
[
{:image_lens_correction, "~> 0.1.0"}
]
endFor an image whose EXIF metadata identifies the camera and lens, all available corrections (distortion, vignetting and TCA) can be applied with a single call:
{:ok, image} = Image.open("photo.jpg")
{:ok, corrected} = Image.LensFun.Correct.correct(image)For an image without complete EXIF metadata, supply the missing parameters as options. Every parameter that correct/2 reads from EXIF is overridable:
{:ok, corrected} =
Image.LensFun.Correct.correct(image,
make: "Canon",
model: "Canon EOS 5D Mark III",
lens_make: "Canon",
lens_model: "Canon EF 100mm f/2.8 Macro USM",
focal_length: 100.0,
aperture: 5.6
)The :corrections option selects which corrections to run; the default is [:distortion, :vignetting, :tca]. Projection conversion is opt-in (since it changes the field of view) via corrections: [:projection] and an optional :target_projection.
When you have your own calibration data — or you're experimenting — each model is exposed as a standalone function that takes raw coefficients in the Hugin coordinate convention (r = 1 at the half short-edge for distortion / TCA / projection, r = 1 at the corner for vignetting):
# ptlens distortion (Hugin form)
{:ok, image} = Image.LensCorrection.radial_distortion_correction(image, -0.0077, 0.087, 0.0)
# poly3 distortion
{:ok, image} = Image.LensCorrection.poly3_correction(image, -0.005)
# poly5 distortion
{:ok, image} = Image.LensCorrection.poly5_correction(image, -0.005, 0.001)
# Vignetting (Adobe Camera Model "pa")
{:ok, image} = Image.LensCorrection.vignette_correction(image, -0.2764, -1.26031, 0.7727)
# Linear TCA
{:ok, image} = Image.LensCorrection.Tca.linear_tca_correction(image, 1.0004, 1.0002)
# Fisheye → rectilinear
focal = Image.LensCorrection.Geometry.focal_length_in_pixels(8.0, 1.5, 5000.0)
{:ok, image} = Image.LensCorrection.Geometry.fisheye_to_rectilinear(image, focal)# Find a lens (case-insensitive maker, fuzzy-substring model)
{:ok, lens} = Image.LensFun.find_lens("Canon", "Canon EF 100mm f/2.8 Macro USM")
# Interpolate the calibration to a specific focal length
{:ok, distortion} = Image.LensFun.interpolate_distortion(lens, 100.0)
# Vignetting needs focal length, aperture and focus distance
{:ok, vignetting} = Image.LensFun.interpolate_vignetting(lens, 100.0, 5.6, 1000.0)
# TCA needs focal length only
{:ok, tca} = Image.LensFun.interpolate_tca(lens, 100.0)
# Apply the result
{:ok, image} = Image.LensCorrection.apply_distortion(image, distortion)
{:ok, image} = Image.LensCorrection.apply_vignetting(image, vignetting)
{:ok, image} = Image.LensCorrection.Tca.apply_tca(image, tca)The lens defects this library corrects, the mathematical models it uses, and the relationship to the upstream lensfun project are described in detail in the Lens corrections guide.
git clone https://github.com/lensfun/lensfun ../lensfun
mix run -e 'Image.LensFun.Importer.import()'This library re-implements the calibration math and bundles a snapshot of the calibration data from the lensfun project. Lens calibration data is distributed under CC BY-SA 3.0; the lensfun reference C library is LGPL v3 (this library does not link to or distribute it).
ImageLensCorrection is licensed under the Apache 2.0 License.