﻿

# Barrels and pincushions

... and correcting them.

## Sample input

We will distort this input image:

 ```set SRC=bpc_src.png call %PICTBAT%gridOver ^ toes.png %SRC% 8 8```

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```

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``` Enlarging ```%IMG7%magick ^ %SRC% ^ -background Blue ^ -virtual-pixel Background ^ -distort Barrel 0,0,0,0.8 ^ bpc_d1b.png```

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``` ```%IMG7%magick ^ %SRC% ^ -background Blue ^ -virtual-pixel Background ^ -distort Barrel 0,0,0.2,0.8 ^ bpc_d3.png```

Setting just b and d:

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

Setting just a and d:

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

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``` ```%IMG7%magick ^ %SRC% ^ -background Blue ^ -virtual-pixel Background ^ -distort Barrel 0,1,0,0 ^ bpc_d9.png``` ```%IMG7%magick ^ %SRC% ^ -background Blue ^ -virtual-pixel Background ^ -distort Barrel 1,0,0,0 ^ bpc_d10.png```

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``` ```%IMG7%magick ^ %SRC% ^ -background Blue ^ -virtual-pixel Background ^ -distort Barrel 0.2,0,-0.2,1 ^ bpc_m2.png``` ```%IMG7%magick ^ %SRC% ^ -background Blue ^ -virtual-pixel Background ^ -distort Barrel -0.2,0,0.4,0.8 ^ bpc_m3.png``` ```%IMG7%magick ^ %SRC% ^ -background Blue ^ -virtual-pixel Background ^ -distort Barrel 0.2,0,-0.4,1.2 ^ bpc_m4.png```

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``` ```%IMG7%magick ^ %SRC% ^ -background Blue ^ -virtual-pixel Background ^ -distort BarrelInverse 0,0,0.2,0.8 ^ bpc_di3.png```

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``` ```%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```

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%``` ```%HUG%fulla ^ -g 0:0:0.2:0.8 ^ --dont-rescale ^ -o bpc_f3.png ^ %SRC%```

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:

• forward abcd parameters (default 0,0,0,1);
• number of samples (at least 4);
• min and max radii for rdst (default min=0, max=diag/shortSide);
• whether to apply distortions and replace images.

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
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.