Skip to content

Commit

Permalink
work in a round of reviews
Browse files Browse the repository at this point in the history
  • Loading branch information
Evizero committed Apr 27, 2017
1 parent 106f2d0 commit a2aa627
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 72 deletions.
7 changes: 6 additions & 1 deletion src/interpolations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@ function box_extrapolation{T,N,D<:Union{Linear,Constant}}(parent::AbstractArray{
box_extrapolation(itp, args...)
end

function box_extrapolation{T,N}(parent::AbstractArray{T,N}, degree::Interpolations.Degree, args...)
itp = interpolate(parent, BSpline(degree), OnGrid())
box_extrapolation(itp, args...)
end

function box_extrapolation(parent::AbstractArray, fill::FillType)
box_extrapolation(parent, Linear(), fill)
end

function box_extrapolation(itp::AbstractInterpolation, degree::Union{Linear,Constant}, args...)
function box_extrapolation(itp::AbstractInterpolation, degree::Interpolations.Degree, args...)
throw(ArgumentError("Boxing an interpolation in another interpolation is discouraged. Did you specify the parameter \"$degree\" on purpose?"))
end

Expand Down
1 change: 1 addition & 0 deletions src/resizing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ imresize_type(c::FixedPoint) = typeof(c)
imresize_type(c) = typeof((c*1)/1)

function imresize!{T,S,N}(resized::AbstractArray{T,N}, original::AbstractArray{S,N})
# FIXME: avoid allocation for interpolation
itp = interpolate(original, BSpline(Linear()), OnGrid())
imresize!(resized, itp)
end
Expand Down
51 changes: 27 additions & 24 deletions src/warp.jl
Original file line number Diff line number Diff line change
@@ -1,38 +1,41 @@
"""
warp(img, tform, [indices], [degree = Linear()], [fill = NaN]) -> imgw
Transform the coordinates of `img`, returning a new `imgw` satisfying
`imgw[I] = img[tform(I)]`. This approach is known as backward
mode warping. The transformation `tform` must accept a `SVector` as
input. A useful package to create a wide variety of such transformations is
Transform the coordinates of `img`, returning a new `imgw`
satisfying `imgw[I] = img[tform(I)]`. This approach is known as
backward mode warping. The transformation `tform` must accept a
`SVector` as input. A useful package to create a wide variety of
such transformations is
[CoordinateTransformations.jl](https://github.com/FugroRoames/CoordinateTransformations.jl).
# Interpolation scheme
# Reconstruction scheme
At off-grid points, `imgw` is calculated by interpolation. The
degree of the b-spline can be specified with the optional
parameter `degree`, which can take the values `Linear()` or
`Constant()`.
During warping, values for `img` must be reconstructed at
arbitrary locations `tform(I)` which do not lie on to the lattice
of pixels. How this reconstruction is done depends on the type of
`img` and the optional parameter `degree`.
The b-spline interpolation is used when `img` is a plain array
and `img[tform(I)]` is inbound. In the case `tform(I)` maps to
indices outside the original `img`, those locations are set to a
value `fill` (which defaults to `NaN` if the element type supports
it, and `0` otherwise).
When `img` is a plain array, b-spline interpolation is used with
`degree = Linear()` for linear interpolation or `degree =
Constant()` for nearest neighbor interpolation. In the case
`tform(I)` maps to indices outside the original `img`, those
locations are set to a value `fill` (which defaults to `NaN` if
the element type supports it, and `0` otherwise).
For more control over the interpolation scheme --- and how
For more control over the reconstruction scheme --- and how
beyond-the-edge points are handled --- pass `img` as an
`AbstractInterpolation` or `AbstractExtrapolation` from
[Interpolations.jl](https://github.com/JuliaMath/Interpolations.jl).
# The meaning of the coordinates
The output array `imgw` has indices that would result from applying
`inv(tform)` to the indices of `img`. This can be very handy for keeping
track of how pixels in `imgw` line up with pixels in `img`.
The output array `imgw` has indices that would result from
applying `inv(tform)` to the indices of `img`. This can be very
handy for keeping track of how pixels in `imgw` line up with
pixels in `img`.
If you just want a plain array, you can "strip" the custom indices
with `parent(imgw)`.
If you just want a plain array, you can "strip" the custom
indices with `parent(imgw)`.
# Examples: a 2d rotation (see JuliaImages documentation for pictures)
Expand All @@ -46,7 +49,7 @@ julia> indices(img)
# Rotate around the center of `img`
julia> tfm = recenter(RotMatrix(-pi/4), center(img))
AffineMap([0.707107 -0.707107; 0.707107 0.707107], [347.01,-68.7554])
AffineMap([0.707107 0.707107; -0.707107 0.707107], [-196.755,293.99])
julia> imgw = warp(img, tfm);
Expand Down Expand Up @@ -111,8 +114,8 @@ inv(tform), args...)` right now.
To change to the new behaviour, set `const warp =
ImageTransformations.warp_new` right after package import.
"""
@generated function warp_old(img::AbstractArray, tform, args...)
Base.depwarn("'warp(img, tform)' is deprecated in favour of the new interpretation 'warp(img, inv(tform))'. Set 'const warp = ImageTransformations.warp_new' right after package import to change to the new behaviour right away. See https://github.com/JuliaImages/ImageTransformations.jl/issues/25 for more background information", :warp)
:(warp_new(img, inv(tform), args...))
function warp_old(img::AbstractArray, tform, args...)
Base.depwarn("'warp(img, tform)' is deprecated in favour of the new interpretation 'warp(img, inv(tform))'. Set 'const warp = ImageTransformations.warp_new' right after package import to change to the new behaviour right away. See https://github.com/JuliaImages/ImageTransformations.jl/issues/25 for more background information", :warp_old)
warp_new(img, inv(tform), args...)
end
const warp = warp_old
103 changes: 56 additions & 47 deletions test/interpolations.jl
Original file line number Diff line number Diff line change
@@ -1,94 +1,103 @@
@testset "_default_fill" begin
@test_throws UndefVarError _default_fill
@test typeof(ImageTransformations._default_fill) <: Function
import ImageTransformations._default_fill

@test @inferred(_default_fill(N0f8)) === N0f8(0)
@test @inferred(_default_fill(Int)) === 0
@test @inferred(_default_fill(Float16)) === NaN16
@test @inferred(_default_fill(Float32)) === NaN32
@test @inferred(_default_fill(Float64)) === NaN

@test @inferred(_default_fill(Gray{N0f8})) === Gray{N0f8}(0)
@test @inferred(_default_fill(Gray{Float16})) === Gray{Float16}(NaN16)
@test @inferred(_default_fill(Gray{Float32})) === Gray{Float32}(NaN32)
@test @inferred(_default_fill(Gray{Float64})) === Gray{Float64}(NaN)

@test @inferred(_default_fill(GrayA{N0f8})) === GrayA{N0f8}(0,0)
@test @inferred(_default_fill(GrayA{Float16})) === GrayA{Float16}(NaN16,NaN16)
@test @inferred(_default_fill(GrayA{Float32})) === GrayA{Float32}(NaN32,NaN32)
@test @inferred(_default_fill(GrayA{Float64})) === GrayA{Float64}(NaN,NaN)

@test @inferred(_default_fill(RGB{N0f8})) === RGB{N0f8}(0,0,0)
@test @inferred(_default_fill(RGB{Float16})) === RGB{Float16}(NaN16,NaN16,NaN16)
@test @inferred(_default_fill(RGB{Float32})) === RGB{Float32}(NaN32,NaN32,NaN32)
@test @inferred(_default_fill(RGB{Float64})) === RGB{Float64}(NaN,NaN,NaN)

@test @inferred(_default_fill(RGBA{N0f8})) === RGBA{N0f8}(0,0,0,0)
@test @inferred(_default_fill(RGBA{Float16})) === RGBA{Float16}(NaN16,NaN16,NaN16,NaN16)
@test @inferred(_default_fill(RGBA{Float32})) === RGBA{Float32}(NaN32,NaN32,NaN32,NaN32)
@test @inferred(_default_fill(RGBA{Float64})) === RGBA{Float64}(NaN,NaN,NaN,NaN)

@test @inferred(_default_fill(HSV{Float16})) === HSV{Float16}(NaN16,NaN16,NaN16)
@test @inferred(_default_fill(HSV{Float32})) === HSV{Float32}(NaN32,NaN32,NaN32)
@test @inferred(_default_fill(HSV{Float64})) === HSV{Float64}(NaN,NaN,NaN)

@test @inferred(ImageTransformations._default_fill(N0f8)) === N0f8(0)
@test @inferred(ImageTransformations._default_fill(Int)) === 0
@test @inferred(ImageTransformations._default_fill(Float16)) === NaN16
@test @inferred(ImageTransformations._default_fill(Float32)) === NaN32
@test @inferred(ImageTransformations._default_fill(Float64)) === NaN

@test @inferred(ImageTransformations._default_fill(Gray{N0f8})) === Gray{N0f8}(0)
@test @inferred(ImageTransformations._default_fill(Gray{Float16})) === Gray{Float16}(NaN16)
@test @inferred(ImageTransformations._default_fill(Gray{Float32})) === Gray{Float32}(NaN32)
@test @inferred(ImageTransformations._default_fill(Gray{Float64})) === Gray{Float64}(NaN)

@test @inferred(ImageTransformations._default_fill(GrayA{N0f8})) === GrayA{N0f8}(0,0)
@test @inferred(ImageTransformations._default_fill(GrayA{Float16})) === GrayA{Float16}(NaN16,NaN16)
@test @inferred(ImageTransformations._default_fill(GrayA{Float32})) === GrayA{Float32}(NaN32,NaN32)
@test @inferred(ImageTransformations._default_fill(GrayA{Float64})) === GrayA{Float64}(NaN,NaN)

@test @inferred(ImageTransformations._default_fill(RGB{N0f8})) === RGB{N0f8}(0,0,0)
@test @inferred(ImageTransformations._default_fill(RGB{Float16})) === RGB{Float16}(NaN16,NaN16,NaN16)
@test @inferred(ImageTransformations._default_fill(RGB{Float32})) === RGB{Float32}(NaN32,NaN32,NaN32)
@test @inferred(ImageTransformations._default_fill(RGB{Float64})) === RGB{Float64}(NaN,NaN,NaN)

@test @inferred(ImageTransformations._default_fill(RGBA{N0f8})) === RGBA{N0f8}(0,0,0,0)
@test @inferred(ImageTransformations._default_fill(RGBA{Float16})) === RGBA{Float16}(NaN16,NaN16,NaN16,NaN16)
@test @inferred(ImageTransformations._default_fill(RGBA{Float32})) === RGBA{Float32}(NaN32,NaN32,NaN32,NaN32)
@test @inferred(ImageTransformations._default_fill(RGBA{Float64})) === RGBA{Float64}(NaN,NaN,NaN,NaN)

@test @inferred(ImageTransformations._default_fill(HSV{Float16})) === HSV{Float16}(NaN16,NaN16,NaN16)
@test @inferred(ImageTransformations._default_fill(HSV{Float32})) === HSV{Float32}(NaN32,NaN32,NaN32)
@test @inferred(ImageTransformations._default_fill(HSV{Float64})) === HSV{Float64}(NaN,NaN,NaN)
end

@testset "box_extrapolation" begin
@test_throws UndefVarError box_extrapolation
@test typeof(ImageTransformations.box_extrapolation) <: Function
import ImageTransformations.box_extrapolation

img = rand(Gray{N0f8}, 2, 2)

etp = @inferred box_extrapolation(img)
@test @inferred(box_extrapolation(etp)) === etp
etp = @inferred ImageTransformations.box_extrapolation(img)
@test @inferred(ImageTransformations.box_extrapolation(etp)) === etp
@test summary(etp) == "2×2 extrapolate(interpolate(::Array{Gray{N0f8},2}, BSpline(Linear()), OnGrid()), Gray{N0f8}(0.0)) with element type ColorTypes.Gray{FixedPointNumbers.Normed{UInt8,8}}"
@test typeof(etp) <: Interpolations.FilledExtrapolation
@test etp.fillvalue === Gray{N0f8}(0.0)
@test etp.itp.coefs === img

@test_throws ArgumentError box_extrapolation(etp, 0)
@test_throws ArgumentError box_extrapolation(etp, Flat())
@test_throws ArgumentError box_extrapolation(etp, Constant())
@test_throws ArgumentError box_extrapolation(etp, Constant(), Flat())
@test_throws ArgumentError box_extrapolation(etp.itp, Constant())
@test_throws ArgumentError box_extrapolation(etp.itp, Constant(), Flat())
@test_throws ArgumentError ImageTransformations.box_extrapolation(etp, 0)
@test_throws ArgumentError ImageTransformations.box_extrapolation(etp, Flat())
@test_throws ArgumentError ImageTransformations.box_extrapolation(etp, Quadratic(Flat()))
@test_throws ArgumentError ImageTransformations.box_extrapolation(etp, Quadratic(Flat()), Flat())
@test_throws ArgumentError ImageTransformations.box_extrapolation(etp, Constant())
@test_throws ArgumentError ImageTransformations.box_extrapolation(etp, Constant(), Flat())
@test_throws ArgumentError ImageTransformations.box_extrapolation(etp.itp, Constant())
@test_throws ArgumentError ImageTransformations.box_extrapolation(etp.itp, Constant(), Flat())

etp2 = @inferred box_extrapolation(etp.itp)
etp2 = @inferred ImageTransformations.box_extrapolation(etp.itp)
@test summary(etp2) == "2×2 extrapolate(interpolate(::Array{Gray{N0f8},2}, BSpline(Linear()), OnGrid()), Gray{N0f8}(0.0)) with element type ColorTypes.Gray{FixedPointNumbers.Normed{UInt8,8}}"
@test typeof(etp2) <: Interpolations.FilledExtrapolation
@test etp2.fillvalue === Gray{N0f8}(0.0)
@test etp2 !== etp
@test etp2.itp === etp.itp

etp2 = @inferred box_extrapolation(etp.itp, Flat())
etp2 = @inferred ImageTransformations.box_extrapolation(etp.itp, Flat())
@test summary(etp2) == "2×2 extrapolate(interpolate(::Array{Gray{N0f8},2}, BSpline(Linear()), OnGrid()), Flat()) with element type ColorTypes.Gray{FixedPointNumbers.Normed{UInt8,8}}"
@test typeof(etp2) <: Interpolations.Extrapolation
@test etp2 !== etp
@test etp2.itp === etp.itp

etp = @inferred box_extrapolation(img, 1)
etp = @inferred ImageTransformations.box_extrapolation(img, 1)
@test summary(etp) == "2×2 extrapolate(interpolate(::Array{Gray{N0f8},2}, BSpline(Linear()), OnGrid()), Gray{N0f8}(1.0)) with element type ColorTypes.Gray{FixedPointNumbers.Normed{UInt8,8}}"
@test typeof(etp) <: Interpolations.FilledExtrapolation
@test etp.fillvalue === Gray{N0f8}(1.0)
@test etp.itp.coefs === img

etp = @inferred box_extrapolation(img, Flat())
@test @inferred(box_extrapolation(etp)) === etp
etp = @inferred ImageTransformations.box_extrapolation(img, Flat())
@test @inferred(ImageTransformations.box_extrapolation(etp)) === etp
@test summary(etp) == "2×2 extrapolate(interpolate(::Array{Gray{N0f8},2}, BSpline(Linear()), OnGrid()), Flat()) with element type ColorTypes.Gray{FixedPointNumbers.Normed{UInt8,8}}"
@test typeof(etp) <: Interpolations.Extrapolation
@test etp.itp.coefs === img

etp = @inferred box_extrapolation(img, Constant())
etp = @inferred ImageTransformations.box_extrapolation(img, Constant())
@test summary(etp) == "2×2 extrapolate(interpolate(::Array{Gray{N0f8},2}, BSpline(Constant()), OnGrid()), Gray{N0f8}(0.0)) with element type ColorTypes.Gray{FixedPointNumbers.Normed{UInt8,8}}"
@test typeof(etp) <: Interpolations.FilledExtrapolation
@test etp.itp.coefs === img

etp = @inferred box_extrapolation(img, Constant(), Flat())
etp = @inferred ImageTransformations.box_extrapolation(img, Constant(), Flat())
@test summary(etp) == "2×2 extrapolate(interpolate(::Array{Gray{N0f8},2}, BSpline(Constant()), OnGrid()), Flat()) with element type ColorTypes.Gray{FixedPointNumbers.Normed{UInt8,8}}"
@test typeof(etp) <: Interpolations.Extrapolation
@test etp.itp.coefs === img

imgfloat = Float64.(img)
etp = @inferred ImageTransformations.box_extrapolation(imgfloat, Quadratic(Flat()))
@test typeof(etp) <: Interpolations.FilledExtrapolation
@test summary(etp) == "2×2 extrapolate(interpolate(::Array{Float64,2}, BSpline(Quadratic(Flat())), OnGrid()), NaN) with element type Float64"

etp = @inferred ImageTransformations.box_extrapolation(imgfloat, Cubic(Flat()), Flat())
@test typeof(etp) <: Interpolations.Extrapolation
@test summary(etp) == "2×2 extrapolate(interpolate(::Array{Float64,2}, BSpline(Cubic(Flat())), OnGrid()), Flat()) with element type Float64"
end

@testset "AxisAlgorithms.A_ldiv_B_md" begin
Expand Down
Loading

0 comments on commit a2aa627

Please sign in to comment.