DiffImageRotation._check_trivial_rotations!Method
_check_trivial_rotations!(out, arr, θ, midpoint)

When θ = 0 || π /2 || π || 3/2 || π and if midpoint is in the middle of the array. For an even array of size 4, the midpoint would need to be 2.5. For an odd array of size 5, the midpoint would need to be 3.

In those cases, rotations are trivial just by reversing or swapping some axes.

DiffImageRotation.imrotate!Method
imrotate!(out, arr::AbstractArray, θ; method=:bilinear, midpoint=size(arr) .÷ 2 .+ 1)

In-place version of imrotate.

Warning

The values in out are not overwritten but added to the values of the rotation operation! So out .+ arr == imrotate!(out, arr, θ)

DiffImageRotation.imrotateMethod
imrotate(arr::AbstractArray, θ; method=:bilinear, midpoint=size(arr) .÷ 2 .+ 1)

Rotates a matrix around the center pixel midpoint. The angle θ is interpreted in radians.

The adjoint is defined with ChainRulesCore.jl. This method also runs with CUDA (and in principle all KernelAbstractions.jl supported backends). If arr is a AbstractArray{T, 3}, the third dimension is interpreted as batch dimension.

Keywords

  • method=:bilinear for bilinear interpolation or method=:nearest for nearest neighbour
  • midpoint=size(arr) .÷ 2 .+ 1 means there is always a real center pixel around it is rotated.

Examples

julia> arr = zeros((6, 6)); arr[3:4, 4] .= 1;

julia> arr
6×6 Matrix{Float64}:
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  1.0  0.0  0.0
 0.0  0.0  0.0  1.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0

julia> imrotate(arr, deg2rad(45))
6×6 view(::Array{Float64, 3}, :, :, 1) with eltype Float64:
 0.0  0.0  0.0        0.0        0.0       0.0
 0.0  0.0  0.0        0.0        0.0       0.0
 0.0  0.0  0.0        0.292893   0.585786  0.0
 0.0  0.0  0.0857864  1.0        0.292893  0.0
 0.0  0.0  0.0        0.0857864  0.0       0.0
 0.0  0.0  0.0        0.0        0.0       0.0

julia> imrotate(arr, deg2rad(90))
6×6 view(::Array{Float64, 3}, :, :, 1) with eltype Float64:
 0.0  0.0  0.0  0.0  0.0          0.0
 0.0  0.0  0.0  0.0  0.0          0.0
 0.0  0.0  0.0  0.0  1.11022e-16  0.0
 0.0  0.0  0.0  1.0  1.0          0.0
 0.0  0.0  0.0  0.0  0.0          0.0
 0.0  0.0  0.0  0.0  0.0          0.0

julia> imrotate(arr, deg2rad(90), midpoint=(3,3))
6×6 view(::Array{Float64, 3}, :, :, 1) with eltype Float64:
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  1.0  1.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0

julia> imrotate(arr, deg2rad(90), method=:nearest)
6×6 view(::Array{Float64, 3}, :, :, 1) with eltype Float64:
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  1.0  1.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0

julia> using CUDA

julia> Array(imrotate(CuArray(arr), deg2rad(90))) ≈ imrotate(arr, deg2rad(90))
true

julia> using Zygote

julia> f(x) = sum(abs2.(imrotate(x, π/4)))
f (generic function with 1 method)

julia> Zygote.gradient(f, arr)
([0.0 0.0 … 0.0 0.0; 0.0 0.0 … 5.387705551013979e-17 0.0; … ; 0.0 0.0 … 0.08578643762690495 0.0; 0.0 0.0 … 0.0 0.0],)
DiffImageRotation.rotate_coordinatesMethod
rotate_coordinates(sinθ, cosθ, i, j, midpoint, round_or_floor)

this rotates the coordinates and either applies round(nearest neighbour) or floor for :bilinear interpolation)

DiffImageRotation.∇imrotateMethod
∇imrotate(dy, arr::AbstractArray{T, 3}, θ; method=:bilinear,
                                           midpoint=size(arr) .÷ 2 .+ 1)

Adjoint for imrotate. Gradient only with respect to arr and not θ.

Arguments

  • dy: input gradient
  • arr: Input from primal computation
  • θ: rotation angle in radians
  • method=:bilinear or method=:nearest
  • midpoint=size(arr) .÷ 2 .+ 1 rotates around a real center pixel for even and odd sized arrays