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._prepare_imrotate
— Method_prepare_imrotate(arr, θ, midpoint)
Prepate sin
and cos
, creates the output array and converts type of midpoint
if required.
DiffImageRotation.bilinear_helper
— Methodbilinearhelper(yrot, xrot, yrotf, xrotf, yrotint, xrot_int)
Some helper variables
DiffImageRotation.imrotate!
— Methodimrotate!(out, arr::AbstractArray, θ; method=:bilinear, midpoint=size(arr) .÷ 2 .+ 1)
In-place version of imrotate
.
The values in out
are not overwritten but added to the values of the rotation operation! So out .+ arr == imrotate!(out, arr, θ)
DiffImageRotation.imrotate
— Methodimrotate(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 ormethod=:nearest
for nearest neighbourmidpoint=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_coordinates
— Methodrotate_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.∇imrotate
— Method∇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 gradientarr
: Input from primal computationθ
: rotation angle in radiansmethod=:bilinear
ormethod=:nearest
midpoint=size(arr) .÷ 2 .+ 1
rotates around a real center pixel for even and odd sized arrays