From 7ed7c551ac5235e183477f775c4bcf97e5f541ba Mon Sep 17 00:00:00 2001 From: Johnny Chen Date: Thu, 27 Aug 2020 16:34:57 +0800 Subject: [PATCH] rebuild operation docs with DemoCards --- docs/.gitignore | 4 +- docs/Project.toml | 1 + docs/make.jl | 55 ++------ docs/operations/affine/config.json | 12 ++ docs/operations/affine/flip.jl | 37 +++++ docs/operations/affine/resize.jl | 30 ++++ docs/operations/affine/rotate.jl | 54 ++++++++ docs/operations/affine/scale.jl | 44 ++++++ docs/operations/affine/shear.jl | 49 +++++++ docs/operations/affine/zoom.jl | 44 ++++++ docs/operations/assets/utilities.jl | 90 ++++++++++++ docs/operations/config.json | 9 ++ docs/operations/distortions/config.json | 7 + .../distortions/elasticdistortion.jl | 31 +++++ docs/operations/index.md | 11 ++ docs/operations/misc/config.json | 6 + docs/operations/misc/layout.jl | 51 +++++++ docs/operations/misc/utilities.jl | 33 +++++ docs/operations/size/config.json | 9 ++ docs/operations/size/crop.jl | 58 ++++++++ docs/operations/size/cropratio.jl | 37 +++++ docs/operations/size/cropsize.jl | 37 +++++ docs/src/index.md | 35 +++-- docs/src/operations.md | 129 ------------------ docs/src/operations/aggmapfun.md | 5 - docs/src/operations/cacheimage.md | 5 - docs/src/operations/combinechannels.md | 5 - docs/src/operations/converteltype.md | 10 -- docs/src/operations/crop.md | 10 -- docs/src/operations/cropnative.md | 17 --- docs/src/operations/cropratio.md | 10 -- docs/src/operations/cropsize.md | 10 -- docs/src/operations/either.md | 5 - docs/src/operations/elasticdistortion.md | 15 -- docs/src/operations/flipx.md | 10 -- docs/src/operations/flipy.md | 10 -- docs/src/operations/mapfun.md | 5 - docs/src/operations/noop.md | 5 - docs/src/operations/permutedims.md | 5 - docs/src/operations/rcropratio.md | 10 -- docs/src/operations/reshape.md | 5 - docs/src/operations/resize.md | 10 -- docs/src/operations/rotate.md | 25 ---- docs/src/operations/rotate180.md | 10 -- docs/src/operations/rotate270.md | 10 -- docs/src/operations/rotate90.md | 10 -- docs/src/operations/scale.md | 27 ---- docs/src/operations/shearx.md | 23 ---- docs/src/operations/sheary.md | 23 ---- docs/src/operations/splitchannels.md | 5 - docs/src/operations/zoom.md | 18 --- src/utils.jl | 18 ++- 52 files changed, 697 insertions(+), 497 deletions(-) create mode 100644 docs/operations/affine/config.json create mode 100644 docs/operations/affine/flip.jl create mode 100644 docs/operations/affine/resize.jl create mode 100644 docs/operations/affine/rotate.jl create mode 100644 docs/operations/affine/scale.jl create mode 100644 docs/operations/affine/shear.jl create mode 100644 docs/operations/affine/zoom.jl create mode 100644 docs/operations/assets/utilities.jl create mode 100644 docs/operations/config.json create mode 100644 docs/operations/distortions/config.json create mode 100644 docs/operations/distortions/elasticdistortion.jl create mode 100644 docs/operations/index.md create mode 100644 docs/operations/misc/config.json create mode 100644 docs/operations/misc/layout.jl create mode 100644 docs/operations/misc/utilities.jl create mode 100644 docs/operations/size/config.json create mode 100644 docs/operations/size/crop.jl create mode 100644 docs/operations/size/cropratio.jl create mode 100644 docs/operations/size/cropsize.jl delete mode 100644 docs/src/operations.md delete mode 100644 docs/src/operations/aggmapfun.md delete mode 100644 docs/src/operations/cacheimage.md delete mode 100644 docs/src/operations/combinechannels.md delete mode 100644 docs/src/operations/converteltype.md delete mode 100644 docs/src/operations/crop.md delete mode 100644 docs/src/operations/cropnative.md delete mode 100644 docs/src/operations/cropratio.md delete mode 100644 docs/src/operations/cropsize.md delete mode 100644 docs/src/operations/either.md delete mode 100644 docs/src/operations/elasticdistortion.md delete mode 100644 docs/src/operations/flipx.md delete mode 100644 docs/src/operations/flipy.md delete mode 100644 docs/src/operations/mapfun.md delete mode 100644 docs/src/operations/noop.md delete mode 100644 docs/src/operations/permutedims.md delete mode 100644 docs/src/operations/rcropratio.md delete mode 100644 docs/src/operations/reshape.md delete mode 100644 docs/src/operations/resize.md delete mode 100644 docs/src/operations/rotate.md delete mode 100644 docs/src/operations/rotate180.md delete mode 100644 docs/src/operations/rotate270.md delete mode 100644 docs/src/operations/rotate90.md delete mode 100644 docs/src/operations/scale.md delete mode 100644 docs/src/operations/shearx.md delete mode 100644 docs/src/operations/sheary.md delete mode 100644 docs/src/operations/splitchannels.md delete mode 100644 docs/src/operations/zoom.md diff --git a/docs/.gitignore b/docs/.gitignore index 052485c1..3f8b53fe 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,4 +1,4 @@ build/ site/ -src/generated/* -/Manifest.toml \ No newline at end of file +src/democards +/Manifest.toml diff --git a/docs/Project.toml b/docs/Project.toml index 4bf77f17..8c761b7c 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,6 +2,7 @@ Augmentor = "02898b10-1f73-11ea-317c-6393d7073e15" DemoCards = "311a05b2-6137-4a5a-b473-18580a3d38b5" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +ImageDraw = "4381153b-2b60-58ae-a1ba-fd683676385f" ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1" Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0" MLDatasets = "eb30cadb-4394-5ae3-aed4-317e484a6458" diff --git a/docs/make.jl b/docs/make.jl index a2dee626..4e68d252 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,56 +1,19 @@ -using Documenter, Augmentor -using Images +using Documenter, DemoCards +using Augmentor using Random using MLDatasets -# predownload the dataset to skip the interactive prompt -if !isdir(first(Base.DEPOT_PATH)) - MNIST.download(;i_accept_the_terms_of_use=true) -end +ENV["DATADEPS_ALWAYS_ACCEPT"] = true # MLDatasets -# Define the documentation order of the operations. The whole -# purpose of this vector is literally just to dictate in what -# chronological order the operations are documented. -op_fnames = [ - "flipx", - "flipy", - "rotate90", - "rotate270", - "rotate180", - "rotate", - "shearx", - "sheary", - "scale", - "zoom", - "elasticdistortion", - "crop", - "cropnative", - "cropsize", - "cropratio", - "rcropratio", - "resize", - "converteltype", - "mapfun", - "aggmapfun", - "splitchannels", - "combinechannels", - "permutedims", - "reshape", - "noop", - "cacheimage", - "either", -] -dict_order = Dict(fname * ".md" => i for (i, fname) in enumerate(op_fnames)) -myless(a, b) = dict_order[a] < dict_order[b] +op_templates, op_theme = cardtheme("grid") +operations, operations_cb = makedemos("operations", op_templates) -# -------------------------------------------------------------------- - -Random.seed!(1337) format = Documenter.HTML(edit_link = "master", prettyurls = get(ENV, "CI", nothing) == "true", assets = [ joinpath("assets", "favicon.ico"), - joinpath("assets", "style.css") + joinpath("assets", "style.css"), + op_theme ] ) @@ -69,7 +32,7 @@ makedocs( ], "User's Guide" => [ "interface.md", - hide("operations.md", Any[joinpath("operations", fname) for fname in sort(readdir(joinpath(@__DIR__, "src", "operations")), lt = myless) if splitext(fname)[2] == ".md"]), + operations, ], # "Tutorials" => joinpath.("generated", ExampleWeaver.listmarkdown()), hide("Indices" => "indices.md"), @@ -77,4 +40,6 @@ makedocs( ] ) +operations_cb() + deploydocs(repo = "github.com/Evizero/Augmentor.jl.git") diff --git a/docs/operations/affine/config.json b/docs/operations/affine/config.json new file mode 100644 index 00000000..96eead3e --- /dev/null +++ b/docs/operations/affine/config.json @@ -0,0 +1,12 @@ +{ + "title": "Affine Transformations", + "order": [ + "flip.jl", + "rotate.jl", + "shear.jl", + "scale.jl", + "resize.jl", + "zoom.jl" + ], + "description": "A sizeable amount of the provided operations fall under the category of **affine transformations**. As such, they can be described using what is known as an [affine map](https://en.wikipedia.org/wiki/Affine_transformation), which are inherently compose-able if chained together. However, utilizing such a affine formulation requires (costly) interpolation, which may not always be needed to achieve the desired effect. For that reason do some of the operations below also provide a special purpose implementation to produce their specified result. Those are usually preferred over the affine formulation if sensible considering the complete pipeline." +} diff --git a/docs/operations/affine/flip.jl b/docs/operations/affine/flip.jl new file mode 100644 index 00000000..4683ae3c --- /dev/null +++ b/docs/operations/affine/flip.jl @@ -0,0 +1,37 @@ +# --- +# title: Flip +# cover: flip.gif +# description: flip the input image horizontally or vertically +# --- + +# [`FlipX`](@ref)/[`FlipY`](@ref) can be used to flip the input image horizontally/vertically. + +using Augmentor +using ImageShow, ImageCore + +img_in = testpattern(RGB, ratio=0.5) + +mosaicview( + img_in, + augment(img_in, FlipX()), + augment(img_in, FlipY()); + fillvalue=colorant"white", nrow=1, npad=10 +) + +# To perform a random flip, you can also pass the probablity to the constructor. For example, `FlipX(0.5)` +# flips the image with half chance. + +# ## References + +#md # ```@docs +#md # FlipX +#md # FlipY +#md # ``` + + +## save covers #src +using ImageMagick #src +using FileIO #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(testpattern(RGB, ratio=0.5), Either(FlipX(), FlipY()), 4) #src +ImageMagick.save("flip.gif", cover; fps=1) #src diff --git a/docs/operations/affine/resize.jl b/docs/operations/affine/resize.jl new file mode 100644 index 00000000..5bab5243 --- /dev/null +++ b/docs/operations/affine/resize.jl @@ -0,0 +1,30 @@ +# --- +# title: Resize +# cover: resize.gif +# --- + +# Set the static size of the image + +using Augmentor +using ImageShow, ImageCore + +img_in = testpattern(RGB, ratio=0.5) + +mosaicview( + img_in, + augment(img_in, Resize(240, 320)); + fillvalue=colorant"white", nrow=1, npad=10 +) + + +# ## References + +#md # ```@docs +#md # Resize +#md # ``` + +## save covers #src +using ImageMagick #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(testpattern(RGB, ratio=0.5), Resize(240, 320), 2) #src +ImageMagick.save("resize.gif", cover; fps=1) #src diff --git a/docs/operations/affine/rotate.jl b/docs/operations/affine/rotate.jl new file mode 100644 index 00000000..e6860e8c --- /dev/null +++ b/docs/operations/affine/rotate.jl @@ -0,0 +1,54 @@ +# --- +# title: Rotate +# cover: rotate.gif +# description: rotate image anticlockwise +# --- + +# The type [`Rotate`](@ref) defines a generic anticlockwise rotation operation around the center +# of the image. It is also possible to pass some abstract vector to the constructor, in which case +# Augmentor will randomly sample one of its elements every time the operation is applied. + +using Augmentor +using ImageShow, ImageCore +using Random +Random.seed!(0) + +img_in = testpattern(RGB, ratio=0.5) +mosaicview( + img_in, + + ## deterministic rotation + augment(img_in, Rotate(45)), + + ## random rotation + augment(img_in, Rotate(-45:45)); + fillvalue=colorant"white", nrow=1, npad=10 +) + +# Note that the output image size will be changed after rotation, [`CropNative`](@ref) can be particalually +# useful to preserve the image size. + +mosaicview( + augment(img_in, Rotate(45)), + augment(img_in, Rotate(45) |> CropNative(axes(img_in))); + nrow=1, npad=10 +) + +# Rotation by some special degree (e.g.,90, 180 and 270) can be handled more efficiently without interpolation. +# Compared to `Rotate(90)`, it is recommended to use [`Rotate90`](@ref) when possible. [`Rotate180`](@ref) and +# [`Rotate270`](@ref) are available, too. + +# ## References + +#md # ```@docs +#md # Rotate +#md # Rotate90 +#md # Rotate180 +#md # Rotate270 +#md # ``` + +## save covers #src +using ImageMagick #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(testpattern(RGB, ratio=0.5), Rotate(-20:20), 5) #src +ImageMagick.save("rotate.gif", cover; fps=1) #src diff --git a/docs/operations/affine/scale.jl b/docs/operations/affine/scale.jl new file mode 100644 index 00000000..82954ed3 --- /dev/null +++ b/docs/operations/affine/scale.jl @@ -0,0 +1,44 @@ +# --- +# title: Scale +# cover: scale.gif +# --- + +# Relatively resizing image + +using Augmentor +using ImageShow, ImageCore +using Random + +# In the case that only a single scale factor is specified, the +# operation will assume that the intention is to scale all +# dimensions uniformly by that factor. + +img_in = testpattern(RGB, ratio=0.5) + +mosaicview( + img_in, + augment(img_in, Scale(0.8)), + augment(img_in, Scale(0.8, 1)); + + fillvalue=colorant"white", nrow=1, npad=10 +) + +# It is also possible to pass some abstract vector(s) to the +# constructor, in which case Augmentor will randomly sample one of +# its elements every time the operation is applied. + +Random.seed!(1337) +img_out = [augment(img_in, Scale(0.9:0.05:1.2)) for _ in 1:4] +mosaicview(img_out...; fillvalue=colorant"white", nrow=2) + +# ## References + +#md # ```@docs +#md # Scale +#md # ``` + +## save covers #src +using ImageMagick #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(testpattern(RGB, ratio=0.5), Scale(0.9:0.1:1.5), 5) #src +ImageMagick.save("scale.gif", cover; fps=1) #src diff --git a/docs/operations/affine/shear.jl b/docs/operations/affine/shear.jl new file mode 100644 index 00000000..d705975f --- /dev/null +++ b/docs/operations/affine/shear.jl @@ -0,0 +1,49 @@ +# --- +# title: Shear +# cover: shear.gif +# description: shear the input image horizontally or vertically +# --- + +# [`ShearX`](@ref)/[`ShearY`](@ref) can be used to shear the input image horizontally/vertically. +# The input to the constructor can be a scalar or a vector. In the case of a vector, the transformation +# will be a stochastic process. + +using Augmentor +using ImageShow, ImageCore +using Random +Random.seed!(0) +img_in = testpattern(RGB, ratio=0.5) + +mosaicview( + ## deterministic transformation + augment(img_in, ShearX(20)), + augment(img_in, ShearY(20)), + + ## random transformation + augment(img_in, ShearX(-20:20)), + augment(img_in, ShearY(-20:20)); + + fillvalue=colorant"white", nrow=2, npad=10 +) + +# Note that the output image size will be changed after transformation, [`CropNative`](@ref) can be +# particalually useful to preserve the image size. + +mosaicview( + augment(img_in, ShearX(10)), + augment(img_in, ShearX(10) |> CropNative(axes(img_in))); + fillvalue=colorant"white", nrow=1, npad=10 +) + +# ## References + +#md # ```@docs +#md # ShearX +#md # ShearY +#md # ``` + +## save covers #src +using ImageMagick #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(testpattern(RGB, ratio=0.5), Either(ShearX(-10:10), ShearY(-10:10)), 5) #src +ImageMagick.save("shear.gif", cover; fps=1) #src diff --git a/docs/operations/affine/zoom.jl b/docs/operations/affine/zoom.jl new file mode 100644 index 00000000..48eb3d2f --- /dev/null +++ b/docs/operations/affine/zoom.jl @@ -0,0 +1,44 @@ +# --- +# title: Zoom +# cover: zoom.gif +# --- + +# Scale without resize + +using Augmentor +using ImageShow, ImageCore +using Random + +# In the case that only a single Zoom factor is specified, the +# operation will assume that the intention is to Zoom all +# dimensions uniformly by that factor. + +img_in = testpattern(RGB, ratio=0.5) + +mosaicview( + img_in, + augment(img_in, Zoom(1.3)), + augment(img_in, Zoom(1.3, 1)); + fillvalue=colorant"white", nrow=1, npad=10 +) + +# It is also possible to pass some abstract vector(s) to the +# constructor, in which case Augmentor will randomly sample one of +# its elements every time the operation is applied. + +Random.seed!(1337) +img_out = [augment(img_in, Zoom(0.9:0.05:1.2)) for _ in 1:4] + +mosaicview(img_out...; nrow=2) + +# ## References + +#md # ```@docs +#md # Zoom +#md # ``` + +## save covers #src +using ImageMagick #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(testpattern(RGB, ratio=0.5), Zoom(0.9:0.1:1.5), 5) #src +ImageMagick.save("zoom.gif", cover; fps=1) #src diff --git a/docs/operations/assets/utilities.jl b/docs/operations/assets/utilities.jl new file mode 100644 index 00000000..d47ea4d3 --- /dev/null +++ b/docs/operations/assets/utilities.jl @@ -0,0 +1,90 @@ +using Augmentor +using ImageCore +using Random +using ImageCore: GenericImage + +""" + make_gif(img, pl, num_sample; random_seed=1337, kwargs...) + +Augment `img` with pipeline `pl` for num_sample times, and concatenate them into a 3 dimensional +image. + +# Examples + +The main purpose of this function is to generate a 3-dimensional image so that we could save a gif +cover using `ImageMagick.save`. + +```julia +using Augmentor, ImageMagick +cover = make_gif(testpattern(RGB), FlipX(), 2) +ImageMagick.save("flipx.gif", cover; fps=1) +``` + +`img` can be a list of images, too. In this case, additional `kwargs` are passed to `mosaicview` so +that you could control how images are ordered. + +```julia +pl = ElasticDistortion(6, scale=0.3, border=true) |> + Rotate([10, -5, -3, 0, 3, 5, 10]) |> + ShearX(-10:10) * ShearY(-10:10) |> + CropSize(28, 28) |> + Zoom(0.9:0.1:1.2) + +n_samples, n_frames = 24, 10 +imgs = [MNIST.convert2image(MNIST.traintensor(i)) for i in 1:n_samples] +preview = make_gif(imgs, pl, n_frames; nrow=1) +``` +""" +function make_gif(img::GenericImage, pl, num_sample; post_op=center_pad ∘ drawborder, random_seed=1337) + Random.seed!(random_seed) + + fillvalue = oneunit(eltype(img)) + frames = sym_paddedviews( + fillvalue, + post_op(img), + [post_op(augment(img, pl)) for _ in 1:num_sample-1]... + ) + cat(frames..., dims=3) +end + +function make_gif(img, pl, num_sample; post_op=drawborder, random_seed=1337, kwargs...) + fillvalue = oneunit(eltype(img[1])) + + init_frame = mosaicview(post_op.(img); kwargs...) + frames = map(1:num_sample-1) do _ + mosaicview(map(x->post_op(augment(x, pl)), img)...; kwargs...) + end + + frames = sym_paddedviews(fillvalue, init_frame, frames...) + cat(frames..., dims=3) +end + +""" + center_pad(img, sz=(240, 200)) + +Pad img with white pixels to height:width ratio `sz[1]:sz[2]`. + +Note that `sz` here is not the output size. +""" +function center_pad(img::AbstractMatrix, sz=(240, 200)) + # the default size (240, 200) is used in DemoCards + fillvalue = oneunit(eltype(img)) + + # make sure we don't shrink the image + h, w = size(img) + ratio = sz[1]/sz[2] + pad_sz = h/w > ratio ? (h, round(Int, w / ratio)) : (round(Int, h * ratio), w) + pad_sz = max.(size(img), pad_sz) + + offset = (pad_sz .- size(img)) .÷ 2 + PaddedView(fillvalue, img, ntuple(i -> -offset[i]:pad_sz[i]-offset[i]+1, ndims(img))) +end + +function drawborder(img, fillvalue=colorant"pink") + img = copy(img) + img[1, 1:end] .= fillvalue + img[1:end, 1] .= fillvalue + img[end, 1:end] .= fillvalue + img[1:end, end] .= fillvalue + img +end diff --git a/docs/operations/config.json b/docs/operations/config.json new file mode 100644 index 00000000..3acad879 --- /dev/null +++ b/docs/operations/config.json @@ -0,0 +1,9 @@ +{ + "order": [ + "affine", + "distortions", + "size", + "misc" + ] +} + \ No newline at end of file diff --git a/docs/operations/distortions/config.json b/docs/operations/distortions/config.json new file mode 100644 index 00000000..36de087a --- /dev/null +++ b/docs/operations/distortions/config.json @@ -0,0 +1,7 @@ +{ + "title": "Distortions", + "order": [ + "elasticdistortion.jl" + ], + "description": "Aside from affine transformations, Augmentor also provides functionality for performing a variety of distortions. These types of operations usually provide a much larger distribution of possible output images." +} diff --git a/docs/operations/distortions/elasticdistortion.jl b/docs/operations/distortions/elasticdistortion.jl new file mode 100644 index 00000000..6e6dfec2 --- /dev/null +++ b/docs/operations/distortions/elasticdistortion.jl @@ -0,0 +1,31 @@ +# --- +# title: ElasticDistortion +# cover: elasticdistortion.gif +# --- + +# Smoothed random distortion + +using Augmentor +using ImageShow, ImageCore +using Random + +img_in = testpattern(RGB, ratio=0.5) + +mosaicview( + img_in, + augment(img_in, ElasticDistortion(15,15,0.1)), + augment(img_in, ElasticDistortion(10,10,0.2,4,3,true)); + fillvalue=colorant"white", nrow=1, npad=10 +) + +# ## Reference + +#md # ```@docs +#md # ElasticDistortion +#md # ``` + +## save covers #src +using ImageMagick #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(testpattern(RGB, ratio=0.5), ElasticDistortion(15,15,0.1), 10) #src +ImageMagick.save("elasticdistortion.gif", cover; fps=2) #src diff --git a/docs/operations/index.md b/docs/operations/index.md new file mode 100644 index 00000000..16e3b8ed --- /dev/null +++ b/docs/operations/index.md @@ -0,0 +1,11 @@ +# [Supported Operations](@id operations) + +Augmentor provides a wide variety of build-in image operations. +This page provides an overview of all exported operations +organized by their main category. These categories are chosen +because they serve some practical purpose. For example Affine +Operations allow for a special optimization under the hood when +chained together. + + +{{{democards}}} diff --git a/docs/operations/misc/config.json b/docs/operations/misc/config.json new file mode 100644 index 00000000..74737941 --- /dev/null +++ b/docs/operations/misc/config.json @@ -0,0 +1,6 @@ +{ + "order":[ + "layout.jl", + "utilities.jl" + ] +} diff --git a/docs/operations/misc/layout.jl b/docs/operations/misc/layout.jl new file mode 100644 index 00000000..fc042651 --- /dev/null +++ b/docs/operations/misc/layout.jl @@ -0,0 +1,51 @@ +# --- +# title: Colorant conversion and channel layout +# cover: layout.gif +# description: a set of commonly used basic operations that wrapped by Augmentor +# --- + +# Augmentor has warpped some commonly used basic operations so that you can use to build the augmentation +# pipeline. The `internal` column is what you'd probably do outside of `Augmentor`. + +# | Category | internal | Augmentor | +# | --- | --- | --- | +# | Conversion | `T.(img)` | `ConvertEltype(T)` | +# | Information Layout | `ImageCore.channelview` | `SplitChannels` | +# | Information Layout | `ImageCore.colorview` | `CombineChannels` | +# | Information Layout | `Base.permutedims` | `PermuteDims` | +# | Information Layout | `Base.reshape` | `Reshape` | + +# It is not uncommon that machine learning frameworks require the data in a specific form and layout. +# For example many deep learning frameworks expect the colorchannel of the images to be encoded in +# the third dimension of a 4-dimensional array. Augmentor allows to convert from (and to) these +# different layouts using special operations that are mainly useful in the beginning or end of a +# augmentation pipeline. + +using Augmentor +using ImageCore + +## 300×400 Matrix{RGB{N0f8}, 2} => 300×400×3 Array{Float32, 3} +img = testpattern(RGB, ratio=0.5) +img_in = augment(img, SplitChannels() |> PermuteDims(2, 3, 1) |> ConvertEltype(Float32)) + +## 300×400×3 Array{Float32, 3} => 300×400 Matrix{RGB{N0f8}, 2} +img_out = augment(img_in, ConvertEltype(N0f8) |> PermuteDims(3, 1, 2) |> CombineChannels(RGB)) + +img_out == img + + +# ## References + +#md # ```@docs +#md # ConvertEltype +#md # SplitChannels +#md # CombineChannels +#md # PermuteDims +#md # Reshape +#md # ``` + +## save covers #src +using ImageMagick #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(testpattern(RGB, ratio=0.5), ConvertEltype(Gray{N0f8}), 2) #src +ImageMagick.save("layout.gif", cover; fps=1) #src diff --git a/docs/operations/misc/utilities.jl b/docs/operations/misc/utilities.jl new file mode 100644 index 00000000..e38d2a78 --- /dev/null +++ b/docs/operations/misc/utilities.jl @@ -0,0 +1,33 @@ +# --- +# title: Composition utilities +# cover: utilities.gif +# description: a set of helper opeartions that may be useful when compositing more complex augmentation workflow +# --- + +# Aside from "true" operations that specify some kind of transformation, there are also a couple of +# special utility operations used for functionality such as stochastic branching. + +using Augmentor +using Random +Random.seed!(1337) + +img_in = testpattern(RGB, ratio=0.5) +img_out = augment(img_in, Either(0.5=>NoOp(), 0.25=>FlipX(), 0.25=>FlipY())) +#md nothing #hide + +# ![](utilities.gif) + +# ## References + +#md # ```@docs +#md # NoOp +#md # Either +#md # CacheImage +#md # ``` + +## save covers #src +using ImageMagick #src +include(joinpath("..", "assets", "utilities.jl")) #src +pl = Either(ShearX(-5:5), ShearY(-5:5)) |> Rotate(-10:10) |> Either(NoOp(), FlipX(), FlipY()) |> CropNative(axes(img_in)) #src +cover = make_gif(img_in, pl, 10) #src +ImageMagick.save("utilities.gif", cover; fps=2) #src diff --git a/docs/operations/size/config.json b/docs/operations/size/config.json new file mode 100644 index 00000000..5cd5b418 --- /dev/null +++ b/docs/operations/size/config.json @@ -0,0 +1,9 @@ +{ + "title": "Resizing and Subsetting", + "order": [ + "crop.jl", + "cropsize.jl", + "cropratio.jl" + ], + "description": "The process of cropping is useful to discard parts of the input image. To provide this functionality lazily, applying a crop introduces a layer of representation called a \"view\" or SubArray. This is different yet compatible with how affine operations or other special purpose implementations work. This means that chaining a crop with some affine operation is perfectly fine if done sequentially. However, it is generally not advised to combine affine operations with crop operations within an [`Either`](@ref) block. Doing that would force the [`Either`](@ref) to trigger the eager computation of its branches in order to preserve type-stability." +} diff --git a/docs/operations/size/crop.jl b/docs/operations/size/crop.jl new file mode 100644 index 00000000..d6c0b08c --- /dev/null +++ b/docs/operations/size/crop.jl @@ -0,0 +1,58 @@ +# --- +# title: Crop +# cover: crop.gif +# --- + +# Subset image using `Crop` and `CropNative` + +using Augmentor +using ImageShow, ImageCore +using OffsetArrays + +img_in = testpattern(RGB, ratio=0.5) +img_out = augment(img_in, Crop(20:75,25:120)) + +mosaicview(img_in, img_out; fillvalue=colorant"white", nrow=1) + +# If the input image is plain arrays without offset indices, then `Crop` and `CropNative` is equivalent. + +augment(img_in, Crop(20:75,25:120)) == augment(img_in, CropNative(20:75,25:120)) + +# Whether you should use `Crop` or `CropNative` depends on if you want to take the index offset +# of the input image into consideration. + +imgo_in = OffsetArray(img_in, -50, -50) +imgo_out = augment(imgo_in, Crop(20:75,25:120)) +imgo_out_native = augment(imgo_in, CropNative(20:75,25:120)) + +( + imgo_in[(first.(axes(imgo_in)) .+ (20, 25))...] == imgo_out[1, 1], + imgo_in[20, 25] == imgo_out_native[1, 1] +) + + +# A typical scenario that you may want to use `CropNative` is when you have affine operations, e.g., +# `Rotate` and `ShearX`. + +mosaicview( + augment(img_in, Rotate(30) |> Crop(axes(img_in))), + augment(img_in, Rotate(30) |> CropNative(axes(img_in))), + + augment(img_in, ShearX(10) |> Crop(axes(img_in))), + augment(img_in, ShearX(10) |> CropNative(axes(img_in))); + + fillvalue=colorant"white", rowmajor=true, nrow=2, npad=10 +) + +# ## Reference + +#md # ```@docs +#md # Crop +#md # CropNative +#md # ``` + +## save covers #src +using ImageMagick #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(img_in, Crop(20:75,25:120), 2) #src +ImageMagick.save("crop.gif", cover; fps=1) #src diff --git a/docs/operations/size/cropratio.jl b/docs/operations/size/cropratio.jl new file mode 100644 index 00000000..08279685 --- /dev/null +++ b/docs/operations/size/cropratio.jl @@ -0,0 +1,37 @@ +# --- +# title: CropRatio +# cover: cropratio.gif +# --- + +# Crop centered window to fit given aspect ratio + +using Augmentor +using ImageShow, ImageCore + +img_in = testpattern(RGB, ratio=0.5) +img_out = augment(img_in, CropRatio()) # crop out a square window + +mosaicview(img_in, img_out; nrow=1) + +# `RCropRatio` is a random version that randomly choose a crop center -- not necessarily the center +# of the input image. + +augment(img_in, RCropRatio()) +#md nothing #hide + +# ![](cropratio.gif) + +# ## Reference + +#md # ```@docs +#md # CropRatio +#md # RCropRatio +#md # ``` + + +## save covers #src +using ImageMagick #src +using FileIO #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(img_in, RCropRatio(), 5) #src +ImageMagick.save("cropratio.gif", cover; fps=1) #src diff --git a/docs/operations/size/cropsize.jl b/docs/operations/size/cropsize.jl new file mode 100644 index 00000000..582bcbee --- /dev/null +++ b/docs/operations/size/cropsize.jl @@ -0,0 +1,37 @@ +# --- +# title: CropSize +# cover: cropsize.gif +# --- + +# Crop centered window to given size + +using Augmentor +using ImageShow, ImageCore + +img_in = testpattern(RGB, ratio=0.5) +img_out = augment(img_in, CropSize(70, 70)) # crop out a square window + +mosaicview(img_in, img_out; nrow=1, npad=10) + +# `RCropSize` is a random version that randomly choose a crop center -- not necessarily the center +# of the input image. + +augment(img_in, CropSize(70, 70)) +#md nothing #hide + +# ![](cropsize.gif) + +# ## Reference + +#md # ```@docs +#md # CropSize +#md # RCropSize +#md # ``` + + +## save covers #src +using ImageMagick #src +using FileIO #src +include(joinpath("..", "assets", "utilities.jl")) #src +cover = make_gif(testpattern(RGB, ratio=0.5), RCropSize(70, 70), 5) #src +ImageMagick.save("cropsize.gif", cover; fps=1) #src diff --git a/docs/src/index.md b/docs/src/index.md index 92ff3bd1..eb7dd356 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -29,32 +29,37 @@ first few examples of the [MNIST database](http://yann.lecun.com/exdb/mnist/). ```@eval -using Augmentor, Images -using PaddedViews, OffsetArrays, MosaicViews -using MLDatasets, ImageMagick +using Augmentor, ImageCore, ImageMagick +using MLDatasets using Random +# copied from operations/assets/gif.jl +function make_gif(img, pl, num_sample; random_seed=1337, kwargs...) + fillvalue = oneunit(eltype(img[1])) + + init_frame = mosaicview(img; kwargs...) + frames = map(1:num_sample-1) do _ + mosaicview(map(x->augment(x, pl), img)...; kwargs...) + end + + frames = sym_paddedviews(fillvalue, init_frame, frames...) + cat(frames..., dims=3) +end + pl = ElasticDistortion(6, scale=0.3, border=true) |> Rotate([10, -5, -3, 0, 3, 5, 10]) |> ShearX(-10:10) * ShearY(-10:10) |> CropSize(28, 28) |> Zoom(0.9:0.1:1.2) +n_samples, n_frames = 24, 10 +imgs = [MNIST.convert2image(MNIST.traintensor(i)) for i in 1:n_samples] +preview = make_gif(imgs, pl, n_frames; nrow=1) -n_sample, nrow = 24, 1 -reduce_op = (x,y) -> cat(x, y, dims=3) -img_generator = i->augment(MNIST.convert2image(MNIST.traintensor(i)), pl) -frame_generator = (n, nrow)-> mosaicview(mapreduce(img_generator, reduce_op, 1:n), nrow=nrow) - -preview = mapreduce(reduce_op, 1:10) do i - Random.seed!(i) - frame_generator(n_sample, nrow) -end - -ImageMagick.save("mnist_preview.gif", preview; fps=3) +ImageMagick.save("mnist_preview.gif", RGB(1, 1, 1) .- preview; fps=3) ``` -![](mnist_preview.gif) +![mnist_preview](mnist_preview.gif) The Julia version of **Augmentor** is engineered specifically for high performance applications. It makes use of multiple diff --git a/docs/src/operations.md b/docs/src/operations.md deleted file mode 100644 index 08eabd5c..00000000 --- a/docs/src/operations.md +++ /dev/null @@ -1,129 +0,0 @@ -```@eval -using Augmentor, Images, Colors -srand(1337) -pattern = imresize(restrict(restrict(testpattern())), (60, 80)) -save("assets/tiny_pattern.png", pattern) -# Affine Transformations -save("assets/tiny_FlipX.png", augment(pattern, FlipX())) -save("assets/tiny_FlipY.png", augment(pattern, FlipY())) -save("assets/tiny_Rotate90.png", augment(pattern, Rotate90())) -save("assets/tiny_Rotate270.png", augment(pattern, Rotate270())) -save("assets/tiny_Rotate180.png", augment(pattern, Rotate180())) -save("assets/tiny_Rotate.png", augment(pattern, Rotate(15))) -save("assets/tiny_ShearX.png", augment(pattern, ShearX(10))) -save("assets/tiny_ShearY.png", augment(pattern, ShearY(10))) -save("assets/tiny_Scale.png", augment(pattern, Scale(0.9,1.2))) -save("assets/tiny_Zoom.png", augment(pattern, Zoom(0.9,1.2))) -# Distortions -srand(1337) -save("assets/tiny_ED1.png", augment(pattern, ElasticDistortion(15,15,0.1))) -save("assets/tiny_ED2.png", augment(pattern, ElasticDistortion(10,10,0.2,4,3,true))) -# Resizing and Subsetting -save("assets/tiny_Resize.png", augment(pattern, Resize(60,60))) -save("assets/tiny_Crop.png", augment(pattern, Rotate(45) |> Crop(1:50,1:80))) -save("assets/tiny_CropNative.png", augment(pattern, Rotate(45) |> CropNative(1:50,1:80))) -save("assets/tiny_CropSize.png", augment(pattern, CropSize(20,65))) -save("assets/tiny_CropRatio.png", augment(pattern, CropRatio(1))) -srand(1337) -save("assets/tiny_RCropRatio.png", augment(pattern, RCropRatio(1))) -# Conversion -save("assets/tiny_ConvertEltype.png", augment(pattern, ConvertEltype(GrayA{N0f8}))) -nothing; -``` - -# [Supported Operations](@id operations) - -Augmentor provides a wide varitey of build-in image operations. -This page provides an overview of all exported operations -organized by their main category. These categories are chosen -because they serve some practical purpose. For example Affine -Operations allow for a special optimization under the hood when -chained together. - -!!! tip - - Click on an image operation for more details. - -## Affine Transformations - -A sizeable amount of the provided operations fall under the -category of **affine transformations**. As such, they can be -described using what is known as an [affine -map](https://en.wikipedia.org/wiki/Affine_transformation), which -are inherently compose-able if chained together. However, -utilizing such a affine formulation requires (costly) -interpolation, which may not always be needed to achieve the -desired effect. For that reason do some of the operations below -also provide a special purpose implementation to produce their -specified result. Those are usually preferred over the affine -formulation if sensible considering the complete pipeline. - -| **Input** | | **[`FlipX`](@ref FlipX)** | **[`FlipY`](@ref FlipY)** | **[`Rotate90`](@ref Rotate90)** | **[`Rotate270`](@ref Rotate270)** | **[`Rotate180`](@ref Rotate180)** | -|:---------:|:--:|:-------------------:|:-------------------:|:----------------------:|:-----------------------:|:-----------------------:| -| ![](assets/tiny_pattern.png) | → | [![](assets/tiny_FlipX.png)](@ref FlipX) | [![](assets/tiny_FlipY.png)](@ref FlipY) | [![](assets/tiny_Rotate90.png)](@ref Rotate90) | [![](assets/tiny_Rotate270.png)](@ref Rotate270) | [![](assets/tiny_Rotate180.png)](@ref Rotate180) | -| **Input** | | **[`Rotate`](@ref Rotate)** | **[`ShearX`](@ref ShearX)** | **[`ShearY`](@ref ShearY)** | **[`Scale`](@ref Scale)** | **[`Zoom`](@ref Zoom)** | -| ![](assets/tiny_pattern.png) | → | [![](assets/tiny_Rotate.png)](@ref Rotate) | [![](assets/tiny_ShearX.png)](@ref ShearX) | [![](assets/tiny_ShearY.png)](@ref ShearY) | [![](assets/tiny_Scale.png)](@ref Scale) | [![](assets/tiny_Zoom.png)](@ref Zoom) | - -## Distortions - -Aside from affine transformations, Augmentor also provides -functionality for performing a variety of distortions. These -types of operations usually provide a much larger distribution of -possible output images. - -| **Input** | | **[`ElasticDistortion`](@ref ElasticDistortion)** | -|:---------:|:--:|:-------------------------------------------------:| -| ![](assets/tiny_pattern.png) | → | [![](assets/tiny_ED1.png)](@ref ElasticDistortion) | - -## Resizing and Subsetting - -The input images from a given dataset can be of various shapes -and sizes. Yet, it is often required by the algorithm that the -data must be of uniform structure. To that end Augmentor provides -a number of ways to alter or subset given images. - -| **Input** | | **[`Resize`](@ref Resize)** | -|:---------:|:--:|:---------------------------:| -| ![](assets/tiny_pattern.png) | → | [![](assets/tiny_Resize.png)](@ref Resize) | - -The process of cropping is useful to discard parts of the input -image. To provide this functionality lazily, applying a crop -introduces a layer of representation called a "view" or -`SubArray`. This is different yet compatible with how affine -operations or other special purpose implementations work. This -means that chaining a crop with some affine operation is -perfectly fine if done sequentially. However, it is generally not -advised to combine affine operations with crop operations within -an [`Either`](@ref) block. Doing that would force the -[`Either`](@ref) to trigger the eager computation of its branches -in order to preserve type-stability. - -| **Input** | | **[`Crop`](@ref Crop)** | **[`CropNative`](@ref CropNative)** | **[`CropSize`](@ref CropSize)** | **[`CropRatio`](@ref CropRatio)** | **[`RCropRatio`](@ref RCropRatio)** | -|:---------:|:--:|:------------------:|:------------------------:|:----------------------:|:-----------------------:|:------------------------:| -| ![](assets/tiny_pattern.png) | → | [![](assets/tiny_Crop.png)](@ref Crop) | [![](assets/tiny_CropNative.png)](@ref CropNative) | [![](assets/tiny_CropSize.png)](@ref CropSize) | [![](assets/tiny_CropRatio.png)](@ref CropRatio) | [![](assets/tiny_RCropRatio.png)](@ref RCropRatio) | - -## Element-wise Transformations and Layout - -It is not uncommon that machine learning frameworks require the -data in a specific form and layout. For example many deep -learning frameworks expect the colorchannel of the images to be -encoded in the third dimension of a 4-dimensional array. -Augmentor allows to convert from (and to) these different layouts -using special operations that are mainly useful in the beginning -or end of a augmentation pipeline. - -Category | Available Operations -----------------------|----------------------------------------------- -Conversion | [`ConvertEltype`](@ref ConvertEltype) (e.g. convert to grayscale) -Mapping | [`MapFun`](@ref MapFun), [`AggregateThenMapFun`](@ref AggregateThenMapFun) -Information Layout | [`SplitChannels`](@ref SplitChannels), [`CombineChannels`](@ref CombineChannels), [`PermuteDims`](@ref PermuteDims), [`Reshape`](@ref Reshape) - -## Utility Operations - -Aside from "true" operations that specify some kind of -transformation, there are also a couple of special utility -operations used for functionality such as stochastic branching. - -Category | Available Operations -----------------------|----------------------------------------------- -Utility Operations | [`NoOp`](@ref NoOp), [`CacheImage`](@ref CacheImage), [`Either`](@ref Either) diff --git a/docs/src/operations/aggmapfun.md b/docs/src/operations/aggmapfun.md deleted file mode 100644 index b6608764..00000000 --- a/docs/src/operations/aggmapfun.md +++ /dev/null @@ -1,5 +0,0 @@ -# [AggregateThenMapFun: Aggregate and Map over Image](@id AggregateThenMapFun) - -```@docs -AggregateThenMapFun -``` diff --git a/docs/src/operations/cacheimage.md b/docs/src/operations/cacheimage.md deleted file mode 100644 index 6a76f55c..00000000 --- a/docs/src/operations/cacheimage.md +++ /dev/null @@ -1,5 +0,0 @@ -# [CacheImage: Buffer current state](@id CacheImage) - -```@docs -CacheImage -``` diff --git a/docs/src/operations/combinechannels.md b/docs/src/operations/combinechannels.md deleted file mode 100644 index cb971660..00000000 --- a/docs/src/operations/combinechannels.md +++ /dev/null @@ -1,5 +0,0 @@ -# [ComineChannels: Combine color channels](@id CombineChannels) - -```@docs -CombineChannels -``` diff --git a/docs/src/operations/converteltype.md b/docs/src/operations/converteltype.md deleted file mode 100644 index ae94e80e..00000000 --- a/docs/src/operations/converteltype.md +++ /dev/null @@ -1,10 +0,0 @@ -# [ConvertEltype: Color conversion](@id ConvertEltype) - -```@docs -ConvertEltype -``` - -```@eval -include("optable.jl") -@optable ConvertEltype(GrayA{N0f8}) -``` diff --git a/docs/src/operations/crop.md b/docs/src/operations/crop.md deleted file mode 100644 index 2ef9c8dc..00000000 --- a/docs/src/operations/crop.md +++ /dev/null @@ -1,10 +0,0 @@ -# [Crop: Subset image](@id Crop) - -```@docs -Crop -``` - -```@eval -include("optable.jl") -@optable Crop(70:140,25:155) -``` diff --git a/docs/src/operations/cropnative.md b/docs/src/operations/cropnative.md deleted file mode 100644 index b2447c26..00000000 --- a/docs/src/operations/cropnative.md +++ /dev/null @@ -1,17 +0,0 @@ -# [CropNative: Subset image](@id CropNative) - -```@docs -CropNative -``` - -```@eval -include("optable.jl") -@optable "cropn1" => (Rotate(45),Crop(1:210,1:280)) -@optable "cropn2" => (Rotate(45),CropNative(1:210,1:280)) -tbl = string( - "`(Rotate(45), Crop(1:210,1:280))` | `(Rotate(45), CropNative(1:210,1:280))`\n", - "-----|-----\n", - "![input](../assets/cropn1.png) | ![output](../assets/cropn2.png)\n" -) -Markdown.parse(tbl) -``` diff --git a/docs/src/operations/cropratio.md b/docs/src/operations/cropratio.md deleted file mode 100644 index b32fb61e..00000000 --- a/docs/src/operations/cropratio.md +++ /dev/null @@ -1,10 +0,0 @@ -# [CropRatio: Crop centered window](@id CropRatio) - -```@docs -CropRatio -``` - -```@eval -include("optable.jl") -@optable CropRatio(1) -``` diff --git a/docs/src/operations/cropsize.md b/docs/src/operations/cropsize.md deleted file mode 100644 index bd1393d1..00000000 --- a/docs/src/operations/cropsize.md +++ /dev/null @@ -1,10 +0,0 @@ -# [CropSize: Crop centered window](@id CropSize) - -```@docs -CropSize -``` - -```@eval -include("optable.jl") -@optable CropSize(45,225) -``` diff --git a/docs/src/operations/either.md b/docs/src/operations/either.md deleted file mode 100644 index d4697a1c..00000000 --- a/docs/src/operations/either.md +++ /dev/null @@ -1,5 +0,0 @@ -# [Either: Stochastic branches](@id Either) - -```@docs -Either -``` diff --git a/docs/src/operations/elasticdistortion.md b/docs/src/operations/elasticdistortion.md deleted file mode 100644 index e74101ef..00000000 --- a/docs/src/operations/elasticdistortion.md +++ /dev/null @@ -1,15 +0,0 @@ -# [ElasticDistortion: Smoothed random distortions](@id ElasticDistortion) - -```@docs -ElasticDistortion -``` - -```@eval -include("optable.jl") -@optable 10 => ElasticDistortion(15,15,0.1) -``` - -```@eval -include("optable.jl") -@optable 10 => ElasticDistortion(10,10,0.2,4,3,true) -``` diff --git a/docs/src/operations/flipx.md b/docs/src/operations/flipx.md deleted file mode 100644 index d527c2e9..00000000 --- a/docs/src/operations/flipx.md +++ /dev/null @@ -1,10 +0,0 @@ -# [FlipX: Mirror horizontally](@id FlipX) - -```@docs -FlipX -``` - -```@eval -include("optable.jl") -@optable FlipX() -``` diff --git a/docs/src/operations/flipy.md b/docs/src/operations/flipy.md deleted file mode 100644 index 4f9ddf7d..00000000 --- a/docs/src/operations/flipy.md +++ /dev/null @@ -1,10 +0,0 @@ -# [FlipY: Mirror vertically](@id FlipY) - -```@docs -FlipY -``` - -```@eval -include("optable.jl") -@optable FlipY() -``` diff --git a/docs/src/operations/mapfun.md b/docs/src/operations/mapfun.md deleted file mode 100644 index 4a66e415..00000000 --- a/docs/src/operations/mapfun.md +++ /dev/null @@ -1,5 +0,0 @@ -# [MapFun: Map function over Image](@id MapFun) - -```@docs -MapFun -``` diff --git a/docs/src/operations/noop.md b/docs/src/operations/noop.md deleted file mode 100644 index 404c8890..00000000 --- a/docs/src/operations/noop.md +++ /dev/null @@ -1,5 +0,0 @@ -# [NoOp: Identity function](@id NoOp) - -```@docs -NoOp -``` diff --git a/docs/src/operations/permutedims.md b/docs/src/operations/permutedims.md deleted file mode 100644 index 02c691b4..00000000 --- a/docs/src/operations/permutedims.md +++ /dev/null @@ -1,5 +0,0 @@ -# [PermuteDims: Change dimension order](@id PermuteDims) - -```@docs -PermuteDims -``` diff --git a/docs/src/operations/rcropratio.md b/docs/src/operations/rcropratio.md deleted file mode 100644 index 544ba287..00000000 --- a/docs/src/operations/rcropratio.md +++ /dev/null @@ -1,10 +0,0 @@ -# [RCropRatio: Crop random window](@id RCropRatio) - -```@docs -RCropRatio -``` - -```@eval -include("optable.jl") -@optable 10 => RCropRatio(1) -``` diff --git a/docs/src/operations/reshape.md b/docs/src/operations/reshape.md deleted file mode 100644 index 28e1b71b..00000000 --- a/docs/src/operations/reshape.md +++ /dev/null @@ -1,5 +0,0 @@ -# [Reshape: Reinterpret shape](@id Reshape) - -```@docs -Reshape -``` diff --git a/docs/src/operations/resize.md b/docs/src/operations/resize.md deleted file mode 100644 index 57a51c05..00000000 --- a/docs/src/operations/resize.md +++ /dev/null @@ -1,10 +0,0 @@ -# [Resize: Set static image size](@id Resize) - -```@docs -Resize -``` - -```@eval -include("optable.jl") -@optable Resize(100,150) -``` diff --git a/docs/src/operations/rotate.md b/docs/src/operations/rotate.md deleted file mode 100644 index c21791eb..00000000 --- a/docs/src/operations/rotate.md +++ /dev/null @@ -1,25 +0,0 @@ -# [Rotate: Arbitrary rotations](@id Rotate) - -```@docs -Rotate -``` - -In contrast to the special case rotations outlined above, the -type `Rotate` can describe any arbitrary number of degrees. It -will always perform the rotation around the center of the image. -This can be particularly useful when combining the operation with -[`CropNative`](@ref). - -```@eval -include("optable.jl") -@optable Rotate(15) -``` - -It is also possible to pass some abstract vector to the -constructor, in which case Augmentor will randomly sample one of -its elements every time the operation is applied. - -```@eval -include("optable.jl") -@optable 10 => Rotate(-10:10) -``` diff --git a/docs/src/operations/rotate180.md b/docs/src/operations/rotate180.md deleted file mode 100644 index 48743f47..00000000 --- a/docs/src/operations/rotate180.md +++ /dev/null @@ -1,10 +0,0 @@ -# [Rotate180: Rotate by 180 degree](@id Rotate180) - -```@docs -Rotate180 -``` - -```@eval -include("optable.jl") -@optable Rotate180() -``` diff --git a/docs/src/operations/rotate270.md b/docs/src/operations/rotate270.md deleted file mode 100644 index 71eaba1b..00000000 --- a/docs/src/operations/rotate270.md +++ /dev/null @@ -1,10 +0,0 @@ -# [Rotate270: Rotate downwards 90 degree](@id Rotate270) - -```@docs -Rotate270 -``` - -```@eval -include("optable.jl") -@optable Rotate270() -``` diff --git a/docs/src/operations/rotate90.md b/docs/src/operations/rotate90.md deleted file mode 100644 index f13f42c8..00000000 --- a/docs/src/operations/rotate90.md +++ /dev/null @@ -1,10 +0,0 @@ -# [Rotate90: Rotate upwards 90 degree](@id Rotate90) - -```@docs -Rotate90 -``` - -```@eval -include("optable.jl") -@optable Rotate90() -``` diff --git a/docs/src/operations/scale.md b/docs/src/operations/scale.md deleted file mode 100644 index 216fba96..00000000 --- a/docs/src/operations/scale.md +++ /dev/null @@ -1,27 +0,0 @@ -# [Scale: Relative resizing](@id Scale) - -```@docs -Scale -``` -```@eval -include("optable.jl") -@optable Scale(0.9,0.5) -``` - -In the case that only a single scale factor is specified, the -operation will assume that the intention is to scale all -dimensions uniformly by that factor. - -```@eval -include("optable.jl") -@optable Scale(1.2) -``` - -It is also possible to pass some abstract vector(s) to the -constructor, in which case Augmentor will randomly sample one of -its elements every time the operation is applied. - -```@eval -include("optable.jl") -@optable 10 => Scale(0.9:0.05:1.2) -``` diff --git a/docs/src/operations/shearx.md b/docs/src/operations/shearx.md deleted file mode 100644 index 1ef08993..00000000 --- a/docs/src/operations/shearx.md +++ /dev/null @@ -1,23 +0,0 @@ -# [ShearX: Shear horizontally](@id ShearX) - -```@docs -ShearX -``` - -It will always perform the transformation around the center of -the image. This can be particularly useful when combining the -operation with [`CropNative`](@ref). - -```@eval -include("optable.jl") -@optable ShearX(10) -``` - -It is also possible to pass some abstract vector to the -constructor, in which case Augmentor will randomly sample one of -its elements every time the operation is applied. - -```@eval -include("optable.jl") -@optable 10 => ShearX(-10:10) -``` diff --git a/docs/src/operations/sheary.md b/docs/src/operations/sheary.md deleted file mode 100644 index 6732e25a..00000000 --- a/docs/src/operations/sheary.md +++ /dev/null @@ -1,23 +0,0 @@ -# [ShearY: Shear vertically](@id ShearY) - -```@docs -ShearY -``` - -It will always perform the transformation around the center of -the image. This can be particularly useful when combining the -operation with [`CropNative`](@ref). - -```@eval -include("optable.jl") -@optable ShearY(10) -``` - -It is also possible to pass some abstract vector to the -constructor, in which case Augmentor will randomly sample one of -its elements every time the operation is applied. - -```@eval -include("optable.jl") -@optable 10 => ShearY(-10:10) -``` diff --git a/docs/src/operations/splitchannels.md b/docs/src/operations/splitchannels.md deleted file mode 100644 index ad25e434..00000000 --- a/docs/src/operations/splitchannels.md +++ /dev/null @@ -1,5 +0,0 @@ -# [SplitChannels: Separate color channels](@id SplitChannels) - -```@docs -SplitChannels -``` diff --git a/docs/src/operations/zoom.md b/docs/src/operations/zoom.md deleted file mode 100644 index 00fcf22b..00000000 --- a/docs/src/operations/zoom.md +++ /dev/null @@ -1,18 +0,0 @@ -# [Zoom: Scale without resize](@id Zoom) - -```@docs -Zoom -``` -```@eval -include("optable.jl") -@optable Zoom(1.2) -``` - -It is also possible to pass some abstract vector to the -constructor, in which case Augmentor will randomly sample one of -its elements every time the operation is applied. - -```@eval -include("optable.jl") -@optable 10 => Zoom(0.9:0.05:1.3) -``` diff --git a/src/utils.jl b/src/utils.jl index 0ae90930..03ec4833 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,14 +1,26 @@ """ - testpattern() -> Matrix{RGBA{N0f8}} + testpattern([T=RGBA{N0f8}]; ratio=1.0) -> Matrix{RGBA{N0f8}} -Load and return the provided 300x400 test image. +Load and return the provided 300x400 test image. Additional args and kwargs +are passed to `imresize`. The returned image was specifically designed to be informative about the effects of the applied augmentation operations. It is thus well suited to prototype an augmentation pipeline, because it makes it easy to see what kind of effects one can achieve with it. """ -testpattern() = load(joinpath(@__DIR__, "..", "resources", "testpattern.png")) +function testpattern(args...; ratio=1.0) + imresize(load(joinpath(@__DIR__, "..", "resources", "testpattern.png")), ratio=ratio) +end +function testpattern(T::Type{<:Colorant}; ratio=1.0) + # Directly call T.(testpattern) returns a testpattern with border filled with black pixels + # This patch fills border with white pixels so as to be consistent with ARGB(0, 0, 0, 0). + npad = 20 + temp = testpattern() + out = fill(oneunit(T), size(temp)) + out[npad:end-npad, npad:end-npad] .= temp[npad:end-npad, npad:end-npad] + return imresize(out, ratio=ratio) +end function use_testpattern() @info("No custom image specifed. Using \"testpattern()\" for demonstration.")