Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GaussianBlur and ColorJitter ops. #84

Merged
merged 14 commits into from
Jul 12, 2021
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ MLDataPattern = "9920b226-0b2a-5f5f-9153-9aa70a013f8b"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[compat]
ComputationalResources = "0.3"
Expand Down
5 changes: 5 additions & 0 deletions src/Augmentor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ export

ElasticDistortion,

AdjustContrastBrightness,
GaussianBlur,

augment,
augment!,
augmentbatch!,
Expand All @@ -95,6 +98,8 @@ include("operations/resize.jl")
include("operations/scale.jl")
include("operations/zoom.jl")
include("operations/either.jl")
include("operations/brightness.jl")
include("operations/blur.jl")

include("distortionfields.jl")
include("distortedview.jl")
Expand Down
38 changes: 38 additions & 0 deletions src/operations/blur.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import ImageFiltering: imfilter, KernelFactors.gaussian

struct GaussianBlur{K <: AbstractVector, S <: AbstractVector} <: ImageOperation
k::K
σ::S

function GaussianBlur(k::K, σ::S) where {K <: AbstractVector{<:Integer},
S <: AbstractVector{<:Real}}
minimum(k) > 0 || throw(ArgumentError("Kernel size must be positive: $(k)"))
minimum(σ) > 0 || throw(ArgumentError("σ must be positive: $(σ)"))
new{K, S}(k, σ)
end
end

GaussianBlur(k, σ) = GaussianBlur(vectorize(k), vectorize(σ))

randparam(op::GaussianBlur, img) = (safe_rand(op.k), safe_rand(op.σ))

@inline supports_eager(::GaussianBlur) = true

function applyeager(op::GaussianBlur, img::AbstractArray, (k, σ))
kernel = gaussian((σ, σ), (k, k))
barucden marked this conversation as resolved.
Show resolved Hide resolved
return imfilter(img, kernel)
end
barucden marked this conversation as resolved.
Show resolved Hide resolved

function showconstruction(io::IO, op::GaussianBlur)
print(io, typeof(op).name.name, '(', op.k, ", ", op.σ,')')
end

function Base.show(io::IO, op::GaussianBlur)
if get(io, :compact, false)
print(io, "GaussianBlur with k=$(op.k) and σ=$(op.σ)")
else
print(io, "Augmentor.")
showconstruction(io, op)
end
end

101 changes: 101 additions & 0 deletions src/operations/brightness.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import ImageCore: clamp01
import Statistics: mean

"""
AdjustContrastBrightness <: ImageOperation

Description
--------------

Adjusts the brightness and contrast of each pixel.
barucden marked this conversation as resolved.
Show resolved Hide resolved

Usage
--------------

AdjustContrastBrightness(α, β)

Arguments
--------------

- **`α`** : `Real` or `AbstractVector` of `Real` that denote
the coefficient(s) for contrast adjustment.
- **`β`** : `Real` or `AbstractVector` of `Real` that denote
the coefficient(s) for brightness adjustment.

Examples
--------------

```
using Augmentor
img = testpattern()

# use exactly 1.2 for contrast, and one of 0.5 and 0.8 for brightness
augment(img, AdjustContrastBrightness(1.2, [0.5, 0.8]))

# pick the coefficients randomly from the specified ranges
augment(img, AdjustContrastBrightness(0.8:0.1:2.0, 0.5:0.1:1.1))
```
"""
struct AdjustContrastBrightness{T<:AbstractVector} <: ImageOperation
α::T
β::T

function AdjustContrastBrightness(α::T, β::T) where {T<:AbstractVector{<:Real}}
length(α) > 0 || throw(ArgumentError("Range $(α) is empty"))
length(β) > 0 || throw(ArgumentError("Range $(β) is empty"))
new{T}(α, β)
end
end

AdjustContrastBrightness(α, β) = AdjustContrastBrightness(vectorize(α),
vectorize(β))

randparam(op::AdjustContrastBrightness, img) = (safe_rand(op.α), safe_rand(op.β))

@inline supports_eager(::AdjustContrastBrightness) = true
@inline supports_lazy(::AdjustContrastBrightness) = true

function applyeager(op::AdjustContrastBrightness, img::AbstractArray, (α, β))
M = _get_M(op, img)
return _map_pix.(α, β, M, img)
end

function applylazy(op::AdjustContrastBrightness, img::AbstractArray, (α, β))
M = _get_M(op, img)
return AdjustedView(img, α, β, M)
end

function showconstruction(io::IO, op::AdjustContrastBrightness)
print(io, typeof(op).name.name, '(', op.α, ", ", op.β,')')
end

function Base.show(io::IO, op::AdjustContrastBrightness)
if get(io, :compact, false)
print(io, "Adjust contrast & brightness with coffecients from $(op.α) and $(op.β), respectively")
else
print(io, "Augmentor.")
showconstruction(io, op)
end
end

_map_pix(α, β, M, pix) = clamp01(α * pix + β * M)
_get_M(op::AdjustContrastBrightness, img) = mean(img)

# This wraps an image so that its pixels appear as after the contrast and
# brightness adjustment. This is done in the `getindex` method.
struct AdjustedView{T, P<:AbstractMatrix{T}, R} <: AbstractArray{T, 2}
orig::P
α::R
β::R
M::T

function AdjustedView(img::P, α::R, β::R, M) where {P <: AbstractMatrix,
R <: Real}
new{eltype(P), P, R}(img, α, β, M)
end
end

Base.parent(A::AdjustedView) = A.parent
Base.size(A::AdjustedView) = size(A.orig)
Base.axes(A::AdjustedView) = axes(A.orig)
Base.getindex(A::AdjustedView, i, j) = _map_pix(A.α, A.β, A.M, A.orig[i, j])