Rotation with FFT

Via shear it is possible to rotate an image. Shearing is basically a shift operation but with different shift distance in each row.


For full interactivity, have a look at this Pluto notebook.

using Revise, FourierTools, Plots, TestImages, PlutoUI, ImageShow

    img = Float32.(testimage("fabio_512_gray"))
    z = zeros(Float32, (768, 768))
    FourierTools.center_set!(z, img)

Gray.(FourierTools.shear(z, -305))

Function references

shear(arr, Δ, shear_dir_dim=1, shear_dim=2; fix_nyquist=false, adapt_size=false::Bool, pad_value=zero(eltype(arr)))

Shears an array by the amount of Δ pixels via an FFT approach. Δ is the relative shift between the top and bottom row shifted with respect to each other. shear_dir_dim decides the direction of the shear and shear_dim is the second dimension where the shear happens. There is also shear! available.


  • arr: array to shear
  • shear_dir_dim: dimension of the shift during shear
  • shear_dim: dimension along which to progress and apply variing shears along shear_dir_dim
  • fix_nyquist: apply a fix to the highest frequency during the Fourier-space application of the exponential factor
  • adapt_size: if true, pad the data prior to the shear. The result array will be larger
  • pad_value: the value to pad with (only applies if adapt_size=true)
  • assign_wrap=assign_wrap: replaces wrap-around areas by pad_value (only of adapt_size is false)

For complex arrays we use fft, for real array we use rfft.

shear!(arr, Δ, shear_dir_dim=1, shear_dim=2; fix_nyquist=false, assign_wrap=false, pad_value=zero(eltype(arr)))

For more details see shear.

Extra Arguments

assign_wrap: if true wrap-around areas are replaced by pad_value pad_value: the value to replace wrap-around areas with

For complex arrays we can completely avoid large memory allocations. For real arrays, we need at least allocate on array in the fourier space.