-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GaussianBlur and ColorJitter ops. (#84)
- Loading branch information
Showing
12 changed files
with
400 additions
and
3 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"title": "Blurring", | ||
"order": [ | ||
"gaussianblur.jl" | ||
] | ||
} |
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,34 @@ | ||
# --- | ||
# title: GaussianBlur | ||
# cover: gaussianblur.gif | ||
# description: blur the input image using a gaussian kernel | ||
# --- | ||
|
||
# [`GaussianBlur`](@ref) can be used to blur the input image using a gaussian | ||
# kernel with a specified kernel size and standard deviation. | ||
|
||
using Augmentor | ||
using ImageShow, ImageCore | ||
|
||
img_in = testpattern(RGB, ratio=0.5) | ||
|
||
mosaicview( | ||
img_in, | ||
augment(img_in, GaussianBlur(3)), | ||
augment(img_in, GaussianBlur(5, 2.5)); | ||
fillvalue=colorant"white", nrow=1, npad=10 | ||
) | ||
|
||
# ## References | ||
|
||
#md # ```@docs | ||
#md # GaussianBlur | ||
#md # ``` | ||
|
||
|
||
## save covers #src | ||
using ImageMagick #src | ||
using FileIO #src | ||
include(joinpath("..", "assets", "utilities.jl")) #src | ||
cover = make_gif(testpattern(RGB, ratio=0.5), GaussianBlur(5), 2) #src | ||
ImageMagick.save("gaussianblur.gif", cover; fps=1) #src |
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,32 @@ | ||
# --- | ||
# title: ColorJitter | ||
# cover: colorjitter.gif | ||
# description: Adjust contrast and brightness of an image | ||
# --- | ||
|
||
# [`ColorJitter`](@ref) can be used to adjust the contrast and brightness of an input image. | ||
|
||
using Augmentor | ||
using ImageShow, ImageCore | ||
|
||
img_in = testpattern(RGB, ratio=0.5) | ||
|
||
mosaicview( | ||
img_in, | ||
augment(img_in, ColorJitter(1.2, 0.3)), | ||
augment(img_in, ColorJitter(0.75, -0.2)); | ||
fillvalue=colorant"white", nrow=1, npad=10 | ||
) | ||
|
||
# ## References | ||
|
||
#md # ```@docs | ||
#md # ColorJitter | ||
#md # ``` | ||
|
||
## save covers #src | ||
using ImageMagick #src | ||
using FileIO #src | ||
include(joinpath("..", "assets", "utilities.jl")) #src | ||
cover = make_gif(testpattern(RGB, ratio=0.5), ColorJitter(), 4) #src | ||
ImageMagick.save("colorjitter.gif", cover; fps=1) #src |
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,7 @@ | ||
{ | ||
"title": "Color adjustments", | ||
"order": [ | ||
"colorjitter.jl" | ||
], | ||
"description": "" | ||
} |
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 |
---|---|---|
|
@@ -2,8 +2,10 @@ | |
"order": [ | ||
"affine", | ||
"distortions", | ||
"color", | ||
"blur", | ||
"size", | ||
"misc" | ||
] | ||
} | ||
|
||
|
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,76 @@ | ||
import ImageFiltering: imfilter, KernelFactors.gaussian | ||
|
||
""" | ||
GaussianBlur <: ImageOperation | ||
Description | ||
-------------- | ||
Blurs an image using a Gaussian filter. | ||
Usage | ||
-------------- | ||
GaussianBlur(k, [σ]) | ||
Arguments | ||
-------------- | ||
- **`k`** : `Integer` or `AbstractVector` of `Integer` that denote | ||
the kernel size. It must be an odd positive number. | ||
- **`σ`** : Optional. `Real` or `AbstractVector` of `Real` that denote the | ||
standard deviation. It must be a positive number. | ||
Defaults to `0.3 * ((k - 1) / 2 - 1) + 0.8`. | ||
Examples | ||
-------------- | ||
``` | ||
using Augmentor | ||
img = testpattern() | ||
# use exactly k=3 and σ=1.0 | ||
augment(img, GaussianBlur(3, 1.0)) | ||
# pick k and σ randomly from the specified ranges | ||
augment(img, GaussianBlur(3:2:7, 1.0:0.1:2.0)) | ||
``` | ||
""" | ||
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 | ||
|
||
# The default value for σ is taken from Albumentations | ||
GaussianBlur(k) = GaussianBlur(k, 0.3 * ((k - 1) / 2 - 1) + 0.8) | ||
GaussianBlur(k, σ) = GaussianBlur(vectorize(k), vectorize(σ)) | ||
|
||
randparam(op::GaussianBlur, img) = (safe_rand(op.k), safe_rand(op.σ)) | ||
|
||
@inline supports_eager(::Type{<:GaussianBlur}) = true | ||
|
||
function applyeager(op::GaussianBlur, img::AbstractArray, (k, σ)) | ||
n = ndims(img) | ||
kernel = gaussian(ntuple(_->σ, n), ntuple(_->k, n)) | ||
return imfilter(img, kernel) | ||
end | ||
|
||
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 |
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 @@ | ||
import ImageCore: clamp01, gamutmax | ||
import Statistics: mean | ||
|
||
""" | ||
ColorJitter <: ImageOperation | ||
Description | ||
-------------- | ||
Adjusts the brightness and contrast of an image according to the formula | ||
`α * image[i] + β * M`, where `M` is either `mean(image)` or the maximum | ||
intensity value. | ||
Usage | ||
-------------- | ||
ColorJitter() | ||
ColorJitter(α, β; [usemax]) | ||
Arguments | ||
-------------- | ||
- **`α`** : `Real` or `AbstractVector` of `Real` that denote the coefficient(s) | ||
for contrast adjustment. Defaults to `0.8:0.1:1.2`. | ||
- **`β`** : `Real` or `AbstractVector` of `Real` that denote the coefficient(s) | ||
for brightness adjustment. Defaults to `-0.2:0.1:0.2`. | ||
- **`usemax::Bool`**: Optional. If `true`, the brightness will be adjusted by | ||
the maximum intensity value; otherwise, the image mean will be used. | ||
Defaults to `true`. | ||
Examples | ||
-------------- | ||
``` | ||
using Augmentor | ||
img = testpattern() | ||
# use exactly 1.2 for contrast, and one of 0.5 and 0.8 for brightness | ||
augment(img, ColorJitter(1.2, [0.5, 0.8])) | ||
# pick the coefficients randomly from the specified ranges | ||
augment(img, ColorJitter(0.8:0.1:2.0, 0.5:0.1:1.1)) | ||
``` | ||
""" | ||
struct ColorJitter{A<:AbstractVector, B<:AbstractVector} <: ImageOperation | ||
α::A | ||
β::B | ||
usemax::Bool | ||
|
||
function ColorJitter(α::A, β::B, usemax) where {A<:AbstractVector{<:Real}, | ||
B<:AbstractVector{<:Real}} | ||
length(α) > 0 || throw(ArgumentError("Range $(α) is empty")) | ||
length(β) > 0 || throw(ArgumentError("Range $(β) is empty")) | ||
new{A, B}(α, β, usemax) | ||
end | ||
end | ||
|
||
# The default values for α and β are taken from Albumentations | ||
ColorJitter() = ColorJitter(0.8:0.1:1.2, -0.2:0.1:0.2, true) | ||
ColorJitter(α, β; usemax=true) = ColorJitter(vectorize(α), vectorize(β), usemax) | ||
|
||
randparam(op::ColorJitter, img) = (safe_rand(op.α), safe_rand(op.β)) | ||
|
||
@inline supports_eager(::Type{<:ColorJitter}) = true | ||
@inline supports_lazy(::Type{<:ColorJitter}) = true | ||
|
||
function applyeager(op::ColorJitter, img::AbstractArray, (α, β)) | ||
M = _get_M(op, img) | ||
return _map_pix.(α, β, M, img) | ||
end | ||
|
||
function applylazy(op::ColorJitter, img::AbstractArray, (α, β)) | ||
M = _get_M(op, img) | ||
return ColorJitterView(img, α, β, M) | ||
end | ||
|
||
function showconstruction(io::IO, op::ColorJitter) | ||
print(io, typeof(op).name.name, '(', op.α, ", ", op.β, ", ", op.usemax, ')') | ||
end | ||
|
||
function Base.show(io::IO, op::ColorJitter) | ||
if get(io, :compact, false) | ||
maxmsg = op.usemax ? "max. intensity" : "mean value"; | ||
print(io, "Color jitter with coffecients α=$(op.α) and β=$(op.β) (w.r.t. $(maxmsg))") | ||
else | ||
print(io, "Augmentor.") | ||
showconstruction(io, op) | ||
end | ||
end | ||
|
||
_map_pix(α, β, M, pix) = clamp01(α * pix + β * M) | ||
|
||
function _get_M(op::ColorJitter, img) | ||
T = eltype(img) | ||
if op.usemax | ||
return T(gamutmax(T)...) | ||
else | ||
return convert(T, mean(img)) | ||
end | ||
end | ||
|
||
# This wraps an image so that its pixels appear as after the contrast and | ||
# brightness adjustment. This is done in the `getindex` method. | ||
struct ColorJitterView{T, P<:AbstractMatrix{T}, R} <: AbstractArray{T, 2} | ||
orig::P | ||
α::R | ||
β::R | ||
M::T | ||
|
||
function ColorJitterView(img::P, α::R, β::R, M) where {P <: AbstractMatrix, | ||
R <: Real} | ||
new{eltype(P), P, R}(img, α, β, M) | ||
end | ||
end | ||
|
||
Base.parent(A::ColorJitterView) = A.parent | ||
Base.size(A::ColorJitterView) = size(A.orig) | ||
Base.axes(A::ColorJitterView) = axes(A.orig) | ||
Base.@propagate_inbounds Base.getindex(A::ColorJitterView, i, j) = _map_pix(A.α, A.β, A.M, A.orig[i, j]) |
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,35 @@ | ||
@testset "GaussianBlur" begin | ||
@testset "constructor" begin | ||
@test_throws ArgumentError GaussianBlur(0) | ||
@test_throws ArgumentError GaussianBlur(3, 0) | ||
@test_throws ArgumentError GaussianBlur([1, 3], 0) | ||
@test_throws ArgumentError GaussianBlur([1, 0], 1) | ||
@test_throws ArgumentError GaussianBlur(3, -1:1) | ||
end | ||
@testset "randparam" begin | ||
img = testpattern() | ||
ks = [3, 1:2:5, [1, 3, 5]] | ||
σs = [1, 1:0.1:2, [1, 2]] | ||
for k in ks, σ in σs | ||
op = GaussianBlur(k, σ) | ||
p = @inferred Augmentor.randparam(op, img) | ||
@test p[1] in k | ||
@test p[2] in σ | ||
end | ||
end | ||
@testset "eager" begin | ||
@test Augmentor.supports_eager(GaussianBlur) | ||
|
||
k = 3 | ||
σ = 3.2 | ||
|
||
imgs = [testpattern(), camera] | ||
|
||
for img in imgs | ||
img = convert.(RGB, img) | ||
ref = imfilter(img, KernelFactors.gaussian((σ, σ), (k, k))) | ||
res = Augmentor.applyeager(GaussianBlur(k, σ), img) | ||
@test assess_psnr(res, ref) > 25 | ||
end | ||
end | ||
end |
Oops, something went wrong.