Skip to content

Commit

Permalink
Merge pull request #46 from lorenzoh/lorenzoh/fastai-fixes
Browse files Browse the repository at this point in the history
Fixing some bugs and making some transforms more generic
  • Loading branch information
lorenzoh authored Jul 11, 2021
2 parents a040aa5 + cc45e73 commit 469b393
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 11 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.2.3]

### Changed

- `BufferedThreadsafe` now properly passes through explicit random state
- `ScaleKeepAspect` no longer sometimes produces a black border
- *fix* `Sequence |> Sequence` now has a method
- `ToTensor` now works on different color types and N-dimensional arrays
- `MaskMulti` now has a constructor for `IndirectArray`s

## [0.1.5] - 2021-04-17

### Added
Expand Down
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "DataAugmentation"
uuid = "88a5189c-e7ff-4f85-ac6b-e6158070f02e"
authors = ["lorenzoh <[email protected]>"]
version = "0.2.3"
version = "0.2.4"

[deps]
ColorBlendModes = "60508b50-96e1-4007-9d6c-f475c410f16b"
Expand All @@ -10,6 +10,7 @@ Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
ImageDraw = "4381153b-2b60-58ae-a1ba-fd683676385f"
ImageTransformations = "02fcd773-0e25-5acc-982a-7f6622650795"
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
IndirectArrays = "9b13fd28-a010-5f03-acff-a1bbcff69959"
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MosaicViews = "e94cdb99-869f-56ef-bcf0-1ae2bcbe0389"
Expand Down
1 change: 1 addition & 0 deletions src/DataAugmentation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module DataAugmentation
using ColorBlendModes
using CoordinateTransformations
using Distributions: Sampleable, Uniform, Categorical
using IndirectArrays: IndirectArray
using ImageDraw
using Images
using Images: Colorant, permuteddimsview
Expand Down
1 change: 1 addition & 0 deletions src/buffered.jl
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ struct BufferedThreadsafe <: Transform
end
end

getrandstate(btfm::BufferedThreadsafe) = getrandstate(btfm.buffereds[1])
Base.show(io::IO, bt::BufferedThreadsafe) = print(io, "BufferedThreadsafe($(bt.buffereds[1].tfm))")


Expand Down
2 changes: 2 additions & 0 deletions src/items/mask.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ end

MaskMulti(a::AbstractArray{<:Gray{T}}, args...) where T = MaskMulti(reinterpret(T, a), args...)
MaskMulti(a::AbstractArray{<:Normed{T}}, args...) where T = MaskMulti(reinterpret(T, a), args...)
MaskMulti(a::IndirectArray, classes = a.values, bounds = Bounds(size(a))) =
MaskMulti(a.index, classes, bounds)

Base.show(io::IO, mask::MaskMulti{N, T}) where {N, T} =
print(io, "MaskMulti{$N, $T}() with size $(size(itemdata(mask))) and $(length(mask.classes)) classes")
Expand Down
49 changes: 42 additions & 7 deletions src/preprocessing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,23 +166,58 @@ function apply!(buf, ::ImageToTensor, image::Image; randstate = nothing)
end

function imagetotensor(image::AbstractArray{C, N}, T = Float32) where {C<:Color, N}
T.(permuteddimsview(channelview(image), ((i for i in 2:N+1)..., 1)))
T.(permuteddimsview(_channelview(image), ((i for i in 2:N+1)..., 1)))
end

#=
function imagetotensor(image::AbstractArray{C, N}, T = Float32) where {TC, C<:Color{TC, 1}, N}
return T.(channelview(image))
return T.(_channelview(image))
end
=#


function imagetotensor!(buf, image::AbstractArray{<:AbstractRGB, N}) where N
# TODO: relax color type constraint, implement for other colors
# single-channel colors need a `channelview` that also expands the array
function imagetotensor!(buf, image::AbstractArray{<:Color, N}) where N
permutedims!(
buf,
channelview(image),
(2, 3, 1))
_channelview(image),
(2:N+1..., 1))
end
tensortoimage(a::AbstractArray{T, 3}) where T = colorview(RGB, permuteddimsview(a, (3, 1, 2)))
tensortoimage(a::AbstractArray{T, 2}) where T = colorview(Gray, a)

function tensortoimage(a::AbstractArray)
nchannels = size(a)[end]
if nchannels == 3
return tensortoimage(RGB, a)
elseif nchannels == 1
return tensortoimage(Gray, a)
else
error("Found image tensor with $nchannels color channels. Pass in color type
explicitly.")
end
end

function tensortoimage(C::Type{<:Color}, a::AbstractArray{T, N}) where {T, N}
perm = (N, 1:N-1...)
return _colorview(C, permuteddimsview(a, perm))
end


function _channelview(img)
chview = channelview(img)
# for single-channel colors, expand the color dimension anyway
if size(img) == size(chview)
chview = reshape(chview, 1, size(chview)...)
end
return chview
end

function _colorview(C::Type{<:Color}, img) where T
if size(img, 1) == 1
img = reshape(img, size(img)[2:end])
end
return colorview(C, img)
end

# OneHot encoding

Expand Down
9 changes: 6 additions & 3 deletions src/projective/affine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ end


function getprojection(scale::ScaleKeepAspect{N}, bounds; randstate = nothing) where N
# If no scaling needs to be done, return a noop transform
scale.minlengths == length.(bounds.rs) && return IdentityTransformation()

# Offset `minlengths` by 1 to avoid black border on one side
ratio = maximum((scale.minlengths .+ 1) ./ length.(bounds.rs))
upperleft = SVector{N, Float32}(minimum.(bounds.rs)) .- 1
upperleft = SVector{N, Float32}(minimum.(bounds.rs)) .- 0.5
P = scaleprojection(Tuple(ratio for _ in 1:N))
if upperleft != SVector(0, 0)
P = P Translation(-upperleft)
P = P Translation((Float32.(P(upperleft)) .+ 0.5f0))
end
return P
end
Expand All @@ -55,7 +58,7 @@ function projectionbounds(tfm::ScaleKeepAspect{N}, P, bounds::Bounds{N}; randsta
ratio = maximum((tfm.minlengths) ./ origsz)
sz = floor.(Int,ratio .* origsz)
bounds_ = transformbounds(bounds, P)
bs_ = offsetcropbounds(sz, bounds_, ntuple(_ -> 1., N))
bs_ = offsetcropbounds(sz, bounds_, ntuple(_ -> 0.5, N))
return bs_
end

Expand Down
1 change: 1 addition & 0 deletions src/sequence.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ compose(seq::Sequence, tfm::Transform) = Sequence(seq.transforms..., tfm)
compose(tfm::Transform, seq::Sequence) = compose(tfm, seq.transforms...)
compose(::Identity, seq::Sequence) = seq
compose(seq::Sequence, ::Identity) = seq
compose(seq1::Sequence, seq2::Sequence) = compose(seq1.transforms..., seq2.transforms...)


function apply(seq::Sequence, items::Tuple; randstate = getrandstate(seq))
Expand Down

0 comments on commit 469b393

Please sign in to comment.