Zygote, Flux, and Interpolations

For those finding your way here from Google, the following function gives a bilinear interpolation over the axes of a matrix and is easily auto differentiable with Zygote and others. You should generally prefer the battle-tested Interpolations.jl implementations where you can, but this one works in a pinch.


function bilininterp(data::AbstractMatrix, x, y)
    x1 = floor(Int,x)
    x2 = ceil(Int,x)
    y1 = floor(Int,y)
    y2 = ceil(Int,y)

    # Handle case of perfect grid alignment
    if x1 == x2
        x2 = x1 + 1
    end
    if y1 == y2
        y2 = y1 + 1
    end

    # Handle boundary conditions
    if x1 == 0
        x1 += 1
        x2 += 1
    end
    if y1 == 0
        y1 += 1
        y2 += 1
    end
    if x1 == size(data,1)
        x1 -= 1
        x2 -= 1
    end
    if y1 == size(data,2)
        y1 -= 1
        y2 -= 1
    end

    mat = [
        1 x1 y1 (x1 * y1)
        1 x1 y2 (x1 * y2)
        1 x2 y1 (x2 * y1)
        1 x2 y2 (x2 * y2)
    ]
    # Get surrounding pixels if finite (fallback to image median otherwise)
    col = [
        data[x1, y1]
        data[x1, y2]
        data[x2, y1]
        data[x2, y2]
    ]
    # Solve the system of equations without inverting
    coeffs = mat \ col
    interp =
        coeffs[1] + coeffs[2] * x + coeffs[3] * y + coeffs[4] * x * y
    return interp
end
3 Likes