-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
streamline API for warp and WarpedView and add InvWarpedView (#24)
* refactor warp to be consistent with WarpedView and perform backward mode * clean up WarpedView API and add warpedview * add InvWarpedView as wrapper around WarpedView * add ImageInTerminal style visual tests * enable color on travis and appveyor * improve and add tests for warp helper functions * implement a deprecation strategy for old warp * add warp support for OneTo inds * add docstring for warpedview and invwarpedview
- Loading branch information
Showing
22 changed files
with
954 additions
and
140 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# FIXME: upstream https://github.com/JuliaGraphics/ColorVectorSpace.jl/issues/75 | ||
@inline _nan(::Type{HSV{Float16}}) = HSV{Float16}(NaN16,NaN16,NaN16) | ||
@inline _nan(::Type{HSV{Float32}}) = HSV{Float32}(NaN32,NaN32,NaN32) | ||
@inline _nan(::Type{HSV{Float64}}) = HSV{Float64}(NaN,NaN,NaN) | ||
@inline _nan{T}(::Type{T}) = nan(T) | ||
|
||
# The default values used by extrapolation for off-domain points | ||
@compat const FillType = Union{Number,Colorant,Flat,Periodic,Reflect} | ||
@compat const FloatLike{T<:AbstractFloat} = Union{T,AbstractGray{T}} | ||
@compat const FloatColorant{T<:AbstractFloat} = Colorant{T} | ||
@inline _default_fill{T<:FloatLike}(::Type{T}) = convert(T, NaN) | ||
@inline _default_fill{T<:FloatColorant}(::Type{T}) = _nan(T) | ||
@inline _default_fill{T}(::Type{T}) = zero(T) | ||
|
||
box_extrapolation(etp::AbstractExtrapolation) = etp | ||
|
||
function box_extrapolation{T}(itp::AbstractInterpolation{T}, fill::FillType = _default_fill(T)) | ||
etp = extrapolate(itp, fill) | ||
box_extrapolation(etp) | ||
end | ||
|
||
function box_extrapolation{T,N,D<:Union{Linear,Constant}}(parent::AbstractArray{T,N}, degree::D = Linear(), args...) | ||
itp = Interpolations.BSplineInterpolation{T,N,typeof(parent),BSpline{D},OnGrid,0}(parent) | ||
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...) | ||
throw(ArgumentError("Boxing an interpolation in another interpolation is discouraged. Did you specify the parameter \"$degree\" on purpose?")) | ||
end | ||
|
||
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 | ||
|
||
function box_extrapolation(itp::AbstractExtrapolation, fill::FillType) | ||
throw(ArgumentError("Boxing an extrapolation in another extrapolation is discouraged. Did you specify the parameter \"$fill\" on purpose?")) | ||
end | ||
|
||
# This is type-piracy, but necessary if we want Interpolations to be | ||
# independent of OffsetArrays. | ||
function AxisAlgorithms.A_ldiv_B_md!(dest::OffsetArray, F, src::OffsetArray, dim::Integer, b::AbstractVector) | ||
indsdim = indices(parent(src), dim) | ||
indsF = indices(F)[2] | ||
if indsF == indsdim | ||
AxisAlgorithms.A_ldiv_B_md!(parent(dest), F, parent(src), dim, b) | ||
return dest | ||
end | ||
throw(DimensionMismatch("indices $(indices(parent(src))) do not match $(indices(F))")) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
""" | ||
InvWarpedView(img, tinv, [indices]) -> wv | ||
Create a view of `img` that lazily transforms any given index `I` | ||
passed to `wv[I]` to correspond to `img[inv(tinv)(I)]`. While | ||
technically this approach is known as backward mode warping, note | ||
that `InvWarpedView` is created by supplying the forward | ||
transformation | ||
The conceptual difference to [`WarpedView`](@ref) is that | ||
`InvWarpedView` is intended to be used when reasoning about the | ||
image is more convenient that reasoning about the indices. | ||
Furthermore, `InvWarpedView` allows simple nesting of | ||
transformations, in which case the transformations will be | ||
composed into a single one. | ||
The optional parameter `indices` can be used to specify the | ||
domain of the resulting `wv`. By default the indices are computed | ||
in such a way that `wv` contains all the original pixels in | ||
`img`. | ||
see [`invwarpedview`](@ref) for more information. | ||
""" | ||
immutable InvWarpedView{T,N,A,F,I,FI<:Transformation,E} <: AbstractArray{T,N} | ||
inner::WarpedView{T,N,A,F,I,E} | ||
inverse::FI | ||
end | ||
|
||
function InvWarpedView{T,N,TA,F,I,E}(inner::WarpedView{T,N,TA,F,I,E}) | ||
tinv = inv(inner.transform) | ||
InvWarpedView{T,N,TA,F,I,typeof(tinv),E}(inner, tinv) | ||
end | ||
|
||
function InvWarpedView(A::AbstractArray, tinv::Transformation, inds::Tuple = autorange(A, tinv)) | ||
InvWarpedView(WarpedView(A, inv(tinv), inds), tinv) | ||
end | ||
|
||
function InvWarpedView(inner::InvWarpedView, outer_tinv::Transformation) | ||
tinv = compose(outer_tinv, inner.inverse) | ||
InvWarpedView(parent(inner), tinv) | ||
end | ||
|
||
Base.parent(A::InvWarpedView) = parent(A.inner) | ||
@inline Base.indices(A::InvWarpedView) = indices(A.inner) | ||
|
||
@compat Compat.IndexStyle{T<:InvWarpedView}(::Type{T}) = IndexCartesian() | ||
@inline Base.getindex{T,N}(A::InvWarpedView{T,N}, I::Vararg{Int,N}) = A.inner[I...] | ||
|
||
Base.size(A::InvWarpedView) = size(A.inner) | ||
Base.size(A::InvWarpedView, d) = size(A.inner, d) | ||
|
||
function ShowItLikeYouBuildIt.showarg(io::IO, A::InvWarpedView) | ||
print(io, "InvWarpedView(") | ||
showarg(io, parent(A)) | ||
print(io, ", ") | ||
print(io, A.inverse) | ||
print(io, ')') | ||
end | ||
|
||
Base.summary(A::InvWarpedView) = summary_build(A) | ||
|
||
""" | ||
invwarpedview(img, tinv, [indices], [degree = Linear()], [fill = NaN]) -> wv | ||
Create a view of `img` that lazily transforms any given index `I` | ||
passed to `wv[I]` to correspond to `img[inv(tinv)(I)]`. While | ||
technically this approach is known as backward mode warping, note | ||
that `InvWarpedView` is created by supplying the forward | ||
transformation. The given transformation `tinv` must accept a | ||
`SVector` as input and support `inv(tinv)`. A useful package to | ||
create a wide variety of such transformations is | ||
[CoordinateTransformations.jl](https://github.com/FugroRoames/CoordinateTransformations.jl). | ||
When invoking `wv[I]`, values for `img` must be reconstructed at | ||
arbitrary locations `inv(tinv)(I)`. `InvWarpedView` serves as a | ||
wrapper around [`WarpedView`](@ref) which takes care of | ||
interpolation and extrapolation. The parameters `degree` and | ||
`fill` can be used to specify the b-spline degree and the | ||
extrapolation scheme respectively. | ||
The optional parameter `indices` can be used to specify the | ||
domain of the resulting `wv`. By default the indices are computed | ||
in such a way that `wv` contains all the original pixels in | ||
`img`. | ||
""" | ||
@inline invwarpedview(A::AbstractArray, tinv::Transformation, args...) = | ||
InvWarpedView(A, tinv, args...) | ||
|
||
function invwarpedview{T}( | ||
A::AbstractArray{T}, | ||
tinv::Transformation, | ||
degree::Union{Linear,Constant}, | ||
fill::FillType = _default_fill(T)) | ||
invwarpedview(box_extrapolation(A, degree, fill), tinv) | ||
end | ||
|
||
function invwarpedview{T}( | ||
A::AbstractArray{T}, | ||
tinv::Transformation, | ||
indices::Tuple, | ||
degree::Union{Linear,Constant}, | ||
fill::FillType = _default_fill(T)) | ||
invwarpedview(box_extrapolation(A, degree, fill), tinv, indices) | ||
end | ||
|
||
function invwarpedview( | ||
A::AbstractArray, | ||
tinv::Transformation, | ||
fill::FillType) | ||
invwarpedview(A, tinv, Linear(), fill) | ||
end | ||
|
||
function invwarpedview( | ||
A::AbstractArray, | ||
tinv::Transformation, | ||
indices::Tuple, | ||
fill::FillType) | ||
invwarpedview(A, tinv, indices, Linear(), fill) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.