snibgo's ImageMagick pages

Barrels and pincushions

... and correcting them.

References

Sample input

We will distort this input image:

set SRC=bpc_src.png

call %PICTBAT%gridOver ^
  toes.png %SRC% 8 8
bpc_src.pngjpg

Images don't usually have grids, but this helps us see what is happening.

The equation

One equation can be used to specify both barrel and pincushion distortions. For each output (destination) pixel we know its radial distance from the centre rdst, and we calculate the radial distance for the source pixel rsrc with the equation ...

rsrc = a*rdst4 + b*rdst3 + c*rdst2 + d*rdst   ... [1]

... where a, b, c and d are constants. The equation can be re-written as:

rsrc = rdst * (a*rdst3 + b*rdst2 + c*rdst + d)   ... [1a]

The radius is normalised so the inscribed circle has a radius of 1.0. Put another way, pixels half way along the longest side are at radius=1.0. Beware: normalisation can be defined in alternative ways, such as radius=1.0 at the corners.

IM "-distort Barrel"

IM's "-distort Barrel" operation applies the equation [1] shown above, using the four abcd parameters. The output has the same dimensions as the input. The "+" form is no different.

When a=b=c=0 and d=1, then rsrc = rdst, so there is no distortion:

The null distortion

%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0,0,0,1 ^
  bpc_d1.png
bpc_d1.pngjpg

If a+b+c+d==1, the image size at r==1 won't change. If the sum is greater than one, rsrc > rdst, so the image will shrink.

Shrinking

%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0,0,0,1.2 ^
  bpc_d1a.png
bpc_d1a.pngjpg

Enlarging

%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0,0,0,0.8 ^
  bpc_d1b.png
bpc_d1b.pngjpg

For a, b and c, negative values create pincushion distortions, and positive values create barrel distortions.

Setting just c and d:

%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0,0,-0.2,1.2 ^
  bpc_d2.png
bpc_d2.pngjpg
%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0,0,0.2,0.8 ^
  bpc_d3.png
bpc_d3.pngjpg

Setting just b and d:

%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0,-0.2,0,1.2 ^
  bpc_d4.png
bpc_d4.pngjpg
%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0,0.2,0,0.8 ^
  bpc_d5.png
bpc_d5.pngjpg

Setting just a and d:

%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel -0.2,0,0,1.2 ^
  bpc_d6.png
bpc_d6.pngjpg
%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0.2,0,0,0.8 ^
  bpc_d7.png
bpc_d7.pngjpg

Negative parameters can make reflections at large values of r. For example, at rdst=1.5, rsrc=-0.2*1.54+1.2*1.5 = 0.7875.

Differentiating gives the gradient of rsrc with rdst:

drsrc/drdst = 4*a*rdst3 + 3*b*rdst2 + 2*c*rdst + d   ... [2]

Reflections will start when this gradient is zero. For example, if b=c=0 then this occurs at:

0 = 4*a*rdst3 + d

rdst = (-d/4a)1/3

In the example bpc_d6.png shown above, a=-0.2 and d=1.2, so the gradient is zero at rdst = 1.1447, which is a little outside the inscribed circle.

At radii near the centre, parameters for the lower powers have the greatest effect. At radii near the corners, parameters for the higher powers have the greatest effect.

%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0,0,1,0 ^
  bpc_d8.png
bpc_d8.pngjpg
%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0,1,0,0 ^
  bpc_d9.png
bpc_d9.pngjpg
%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 1,0,0,0 ^
  bpc_d10.png
bpc_d10.pngjpg

Combining positive and negative values for a, b and c creates pincushion or barrel distortion at different radii.

%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel -0.2,0,0.2,1 ^
  bpc_m1.png
bpc_m1.pngjpg
%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0.2,0,-0.2,1 ^
  bpc_m2.png
bpc_m2.pngjpg
%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel -0.2,0,0.4,0.8 ^
  bpc_m3.png
bpc_m3.pngjpg
%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel 0.2,0,-0.4,1.2 ^
  bpc_m4.png
bpc_m4.pngjpg

A transition from barrel to pincusion occurs at a radius where the differential [2] is one. This may occur at three different radii. For the example bpc_m3.png, one such radius is rdst=0.83756.

IM "-distort BarrelInverse"

The equation for this distortion is ...

rsrc = rdst / (a*rdst3 + b*rdst2 + c*rdst + d)   ... [3]

... which is the same as equation [1a] but with a divide instead of a multiply. This is the inverse of the ordinary "-distort Barrel" only in the sense that, for the same parameters, barrel becomes pincushion and pincushion becomes barrel.

%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort BarrelInverse 0,0,-0.2,1.2 ^
  bpc_di2.png
bpc_di2.pngjpg
%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort BarrelInverse 0,0,0.2,0.8 ^
  bpc_di3.png
bpc_di3.pngjpg

A "-distort Barrel" followed by "-distort BarrelInverse" with the same parameters is approximately a null transformation, but not exactly:

%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel        0,0,-0.2,1.2 ^
  -distort BarrelInverse 0,0,-0.2,1.2 ^
  bpc_dir2.png
bpc_dir2.pngjpg
%IMG7%magick ^
  %SRC% ^
  -background Blue ^
  -virtual-pixel Background ^
  -distort Barrel        0,0,0.2,0.8 ^
  -distort BarrelInverse 0,0,0.2,0.8 ^
  bpc_dir3.png
bpc_dir3.pngjpg

In both cases, the yellow grid lines are no longer straight.

fulla.exe

One component of the Hugin toolset is fulla.exe. Among other operations, this program can apply a barrel/pincushion distortion. "--green" or "-g" applies the same abcd distortion to all the channels. If "--red" or "--blue" are specified, these are applied on top of the "--green" distortion, to correct for chromatic aberration (see Chromatic aberration).

The output has the same dimensions as the input. By default, fulla.exe rescales the output to avoid added black borders (equivalent to IM "-crop" and "-resize"). We can prevent this with the "--dont-rescale" option.

%HUG%fulla ^
  -g 0:0:-0.2:1.2 ^
  --dont-rescale ^
  -o bpc_f2.png ^
  %SRC%
bpc_f2.pngjpg
%HUG%fulla ^
  -g 0:0:0.2:0.8 ^
  --dont-rescale ^
  -o bpc_f3.png ^
  %SRC%
bpc_f3.pngjpg

In the bpc_f3.png result, the yellow/black boundary is aliased (stepped) compared to the IM result. fulla's distortion code is clearly cruder than IM's. However, the problem seems limited to edges; yellow lines within the image do not seem aliased.

Future: Process module

How do we calculate the reverse of "-distort Barrel" and "-distort BarrelInverse"? From four different values of rdst we can use the forward calculation to calculate rsrc, then use (possibly over-specified) simultaneous equations to calculate the parameters abcd for the reverse.

A process module could have options for:

We could also do another process module, solvesimul, that solves general-purpose simultaneous equations, reading the data from a text file.

Scripts

For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.

tcaCorr.bat

rem From image %1,
rem makes output %2
rem using transverse chromatic aberration (TCA) parameters %3
rem as created by Hugin tca_correct.exe, probably quoted.
@rem
@rem Updated:
@rem   8-August-2022 for IM v7.
@rem

@if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal enabledelayedexpansion

@call echoOffSave

call %PICTBAT%setInOut %1 tcac

if not "%2"=="" if not "%2"=="." set OUTFILE=%2

set PARAMS=%~3

for /F "tokens=1-10 delims=: " %%A in ("%PARAMS%") do (
  if not "%%A"=="-r" exit /B 1
  if not "%%F"=="-b" exit /B 1
  set ar=%%B
  set br=%%C
  set cr=%%D
  set dr=%%E
  set ab=%%G
  set bb=%%H
  set cb=%%I
  set db=%%J
)

for /F "usebackq" %%L in (`%IMG7%magick identify ^
  -format "sumr=%%[fx:%ar%+(%br%)+(%cr%)+(%dr%)]\nsumb=%%[fx:%ab%+(%bb%)+(%cb%)+(%db%)]\n" ^
  xc:`) do set %%L

echo sumr=%sumr% sumb=%sumb%

%IMG7%magick ^
  %INFILE% ^
  -channel RGB ^
  -separate ^
  +channel ^
  -verbose ^
  ( -clone 0 ^
    -distort BarrelInverse %ar%,%br%,%cr%,%dr% ) ^
  -swap 0,3 +delete ^
  ( -clone 2 ^
    -distort BarrelInverse %ab%,%bb%,%cb%,%db% ) ^
  +verbose ^
  +swap +delete ^
  -combine ^
  %OUTFILE%

call echoRestore

endlocal & set tcacOUTFILE=%OUTFILE%

All images on this page were created by the commands shown, using:

%IMG7%magick -version
Version: ImageMagick 7.1.0-42 Q16-HDRI x64 396d87c:20220709 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenCL 
Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib
Compiler: Visual Studio 2022 (193231332)
%HUG%tca_correct -h | findstr version 
tca_correct version 2020.0.0.2f576e5d5b4a built by Thomas

To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG or TIFF or MIFF to JPG.

Source file for this web page is barrelpc.h1. To re-create this web page, execute "procH1 barrelpc".


This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.

Anyone is permitted to re-publish this page, but only for non-commercial use.

Anyone is permitted to link to this page, including for commercial use.


Page version v1.0 10-June-2018.

Page created 15-Aug-2022 16:33:19.

Copyright © 2022 Alan Gibson.