Skip to content

Commit 9a623a8

Browse files
committed
add index page and a swirl example
1 parent 506ddd7 commit 9a623a8

File tree

7 files changed

+194
-9
lines changed

7 files changed

+194
-9
lines changed

docs/Project.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
[deps]
22
CoordinateTransformations = "150eb455-5306-5404-9cee-2592286d6298"
3+
DemoCards = "311a05b2-6137-4a5a-b473-18580a3d38b5"
34
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
5+
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
6+
ImageBase = "c817782e-172a-44cc-b673-b171935fbb9e"
47
ImageCore = "a09fc81d-aa75-5fe9-8630-4744c3626534"
58
ImageIO = "82e4d734-157c-48bb-816b-45c225c6df19"
69
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
710
ImageShow = "4e3cecfd-b093-5904-9786-8bbb286a6a31"
811
ImageTransformations = "02fcd773-0e25-5acc-982a-7f6622650795"
912
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
13+
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
1014
Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc"
15+
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
1116
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"
1217

1318
[compat]
14-
Documenter = "0.26"
19+
DemoCards = "0.4"
20+
Documenter = "0.27"

docs/examples/config.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"theme": "grid"
3+
}

docs/examples/operations/swirl.jl

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# ---
2+
# cover: assets/swirl.gif
3+
# title: Swirl effect using warp operation
4+
# ---
5+
6+
# In this example, we illustrate how to construct a custom warping map
7+
# and pass it to `warp`. This swirl example comes from
8+
# [the Princeton Computer Graphics course for Image Warping (Fall 2000)](https://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/warp/warp.pdf)
9+
# and [scikit-image swirl example](https://scikit-image.org/docs/dev/auto_examples/transform/plot_swirl.html).
10+
11+
using ImageTransformations
12+
using OffsetArrays, StaticArrays
13+
using ImageShow, TestImages
14+
using LinearAlgebra
15+
16+
img = imresize(testimage("cameraman"), (256, 256));
17+
18+
# As we've illustrated in [image warping](@ref index_image_warping), a warp operation
19+
# consists of two operations: backward coordinate map `ϕ` and intensity estimator.
20+
# To implement swirl operation, we need to customize the coordinate map `ϕ`.
21+
# A valid coordinate map `q = ϕ(p)` follows the following interface:
22+
#
23+
# ```julia
24+
# # SVector comes from StaticArrays
25+
# ϕ(::SVector{N})::SVector{N} where N
26+
# ```
27+
#
28+
# A cartesian position `(x, y)` can be transfered to/from polar coordinate `(ρ, θ)`
29+
# using formula:
30+
#
31+
# ```julia
32+
# # Cartesian to Polar
33+
# ρ = norm(y-y0, x-x0)
34+
# θ = atan(y/x)
35+
#
36+
# # Polar to Cartesian
37+
# y = y0 + ρ*sin(θ)
38+
# x = x0 + ρ*cos(θ)
39+
# ```
40+
#
41+
# For given input index `p`, a swirl operation enforces more rotations in its polar coordinate using
42+
# `θ̃ = θ + ϕ + s*exp(-ρ/r)`, and returns the cartesian index (x̃, ỹ) from the warped polor coordinate
43+
# (ρ, θ̃). (Here we use the formula from [scikit-image swirl example](https://scikit-image.org/docs/dev/auto_examples/transform/plot_swirl.html)
44+
# to build our version.)
45+
46+
function swirl(rotation, strength, radius)
47+
x0 = OffsetArrays.center(img)
48+
r = log(2)*radius/5
49+
50+
function swirl_map(x::SVector{N}) where N
51+
xd = x .- x0
52+
ρ = norm(xd)
53+
θ = atan(reverse(xd)...)
54+
55+
## Note that `x == x0 .+ ρ .* reverse(sincos(θ))`
56+
## swirl adds more rotations to θ based on the distance to center point
57+
θ̃ = θ + rotation + strength * exp(-ρ/r)
58+
59+
SVector{N}(x0 .+ ρ .* reverse(sincos(θ̃)))
60+
end
61+
62+
warp(img, swirl_map, axes(img))
63+
end
64+
65+
# Now let's see how radius argument affects the result
66+
67+
preview = ImageShow.gif([swirl(0, 10, radius) for radius in 10:10:150]; fps=5)
68+
69+
using FileIO #src
70+
save("assets/swirl.gif", preview; fps=5) #src

docs/make.jl

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
1-
using Documenter, ImageCore, ImageTransformations, ImageShow
1+
using Documenter, DemoCards
2+
using ImageBase, ImageTransformations, ImageShow
23
using TestImages
34
using CoordinateTransformations, Interpolations, Rotations
45

5-
testimage("cameraman") # this is used to trigger artifact download
6+
# this is used to trigger artifact download and IO backend precompilation
7+
testimage.(["cameraman", "lighthouse"])
68

9+
examples, postprocess_cb, examples_assets = makedemos("examples")
710
format = Documenter.HTML(edit_link = "master",
8-
prettyurls = get(ENV, "CI", nothing) == "true")
11+
prettyurls = get(ENV, "CI", nothing) == "true",
12+
assets = [examples_assets,])
913

10-
makedocs(modules = [ImageTransformations],
14+
makedocs(modules = [ImageTransformations, ImageBase],
1115
format = format,
1216
sitename = "ImageTransformations",
13-
pages = ["index.md", "reference.md"])
17+
pages = [
18+
"index.md",
19+
examples,
20+
"reference.md"])
21+
22+
postprocess_cb()
1423

1524
deploydocs(repo = "github.com/JuliaImages/ImageTransformations.jl.git")

docs/src/assets/warp_resize.png

107 KB
Loading

docs/src/index.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,83 @@
11
# ImageTransformations.jl
22

3+
```@setup overview
4+
using ImageShow
5+
```
6+
37
This package provides support for image resizing, image rotation, and
48
other spatial transformations of arrays.
9+
10+
## Overview
11+
12+
ImageTransformations.jl consists of two sets of API: the low level warping operations, and the high-level operations that built on top of it.
13+
14+
- Low-level warping API:
15+
- `warp`: backward-mode warping
16+
- `WarpedView`: the lazy view version of `warp`
17+
- `InvWarpedView`: the inverse of `WarpedView`
18+
- high-level spatial operations:
19+
- `imresize`: aspect adjustment
20+
- `restrict`: a much more efficient version of `imresize` that two-folds/down-samples image to approximate 1/2 size. (This is now provided by ImageBase.)
21+
- `imrotate`: rotation
22+
23+
For detailed usage of these functions, please refer to [function references](@ref package_references) and [examples](@ref Examples). The following section explains
24+
the core concept image warping so that you can get a clear understanding about
25+
this package while using it.
26+
27+
## [Image warping](@id index_image_warping)
28+
29+
!!! info
30+
This is just a very simple explaination on the internal of ImageTransformations. For more information about image warping, you can take a look at [the Princeton Computer Graphics course for Image Warping (Fall 2000)](https://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/warp/warp.pdf)
31+
32+
Most image spatial transformation operations (e.g., rotation, resizing, translation) fall into the category of warping operation. Mathematically, for given input image `X`, a (backward-mode) warping operation `f` consists of two functions: coordination map `ϕ` and intensity estimator `τ`.
33+
34+
```math
35+
Y_{i,j} = f(X)_{i, j} = τ(X, ϕ(i, j))
36+
```
37+
38+
Take the following resizing operation as an example, for every pixel position `p` in output image `Y`, we 1) use the backward coordinate map `ϕ` to get its corresponding pixel position `q` in original image `X`. Since `q` may not be on grid, we need to 2) estimate the value of `X` on position `q` using function `τ`, and finally 3) assign `X[q]` back to `Y[p]`. In Julia words, it is
39+
40+
```julia
41+
for p in CartesianIndexes(Y)
42+
q = ϕ(p) # backward coordinate map
43+
v = τ(X, q) # estimate the value
44+
Y[p] = v # assign value back
45+
end
46+
```
47+
48+
As you may have notice, we use backward coordinate map because this is the simplest way to iterate every pixel of the output image. This is why it is called backward-mode warping. In some literature, it is also called reverse warping.
49+
50+
![warp resize demo](assets/warp_resize.png)
51+
52+
In ImageTransformations, the `warp`-based operation uses Interpolations as our intensity estimator `τ`:
53+
54+
```@example overview
55+
using Interpolations, ImageCore, TestImages
56+
using ImageTransformations
57+
58+
X = imresize(testimage("cameraman"), (64, 64)) # use small image as an example
59+
60+
sz = (128, 128)
61+
Y = similar(X, sz...)
62+
63+
# intensity estimator using interpolation
64+
itp = interpolate(X, BSpline(Linear())) # bilinear interpolation
65+
τ(q) = itp(q...)
66+
67+
# A linear coordinate map that satisfies:
68+
# - `ϕ(1, 1) == (1, 1)`
69+
# - `ϕ(128, 128) == (64, 64)`
70+
K = (size(X) .- (1, 1))./(sz .- (1, 1))
71+
b = (1, 1) .- K
72+
ϕ(p) = @. K*p + b
73+
74+
for p in CartesianIndices(Y)
75+
q = ϕ(p.I)
76+
Y[p] = τ(q)
77+
end
78+
79+
mosaic(X, Y; nrow=1)
80+
```
81+
82+
This is the internal of ImageTransformations. For common usage of ImageTransformations, you should use either the low-level API `warp` or
83+
high-level API `imresize` and others.

docs/src/reference.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
11
# [Package References](@id package_references)
22

33

4-
```@autodocs
5-
Modules = [ImageTransformations]
6-
Order = [:type, :function]
4+
# High-level API
5+
6+
```@docs
7+
ImageBase.restrict
8+
ImageTransformations.imrotate
9+
ImageTransformations.imresize
10+
```
11+
12+
# Low-level warping API
13+
14+
```@docs
15+
ImageTransformations.warp
16+
ImageTransformations.WarpedView
17+
ImageTransformations.InvWarpedView
18+
ImageTransformations.invwarpedview
19+
```
20+
21+
# Utilities
22+
23+
```@docs
24+
ImageTransformations.autorange
725
```

0 commit comments

Comments
 (0)