You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
6.4 KiB

### A Pluto.jl notebook ###
# v0.12.11
using Markdown
using InteractiveUtils
# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
quote
local el = $(esc(element))
global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing
el
end
end
# ╔═╡ 15a4ba3e-f0d1-11ea-2ef1-5ff1dee8795f
using Pkg
# ╔═╡ 21e744b8-f0d1-11ea-2e09-7ffbcdf43c37
begin
Pkg.add("Gadfly")
Pkg.add("Compose")
Pkg.add("Statistics")
Pkg.add("Hyperscript")
Pkg.add("Colors")
Pkg.add("Images")
Pkg.add("ImageMagick")
Pkg.add("ImageFiltering")
using Gadfly
using Images
using Compose
using Hyperscript
using Colors
using Statistics
using PlutoUI
using ImageMagick
using ImageFiltering
end
# ╔═╡ 1ab1c808-f0d1-11ea-03a7-e9854427d45f
Pkg.activate(mktempdir())
# ╔═╡ 10f850fc-f0d1-11ea-2a58-2326a9ea1e2a
set_default_plot_size(12cm, 12cm)
# ╔═╡ 7b4d5270-f0d3-11ea-0b48-79005f20602c
function convolve(M, kernel)
height, width = size(kernel)
half_height = height ÷ 2
half_width = width ÷ 2
new_image = similar(M)
# (i, j) loop over the original image
m, n = size(M)
@inbounds for i in 1:m
for j in 1:n
# (k, l) loop over the neighbouring pixels
accumulator = 0 * M[1, 1]
for k in -half_height:-half_height + height - 1
for l in -half_width:-half_width + width - 1
Mi = i - k
Mj = j - l
# First index into M
if Mi < 1
Mi = 1
elseif Mi > m
Mi = m
end
# Second index into M
if Mj < 1
Mj = 1
elseif Mj > n
Mj = n
end
accumulator += kernel[k, l] * M[Mi, Mj]
end
end
new_image[i, j] = accumulator
end
end
return new_image
end
# ╔═╡ 6fd3b7a4-f0d3-11ea-1f26-fb9740cd16e0
function disc(n, r1=0.8, r2=0.8)
white = RGB{Float64}(1,1,1)
blue = RGB{Float64}(colorant"#4EC0E3")
convolve(
[(i-n/2)^2 + (j-n/2)^2 <= (n/2-5)^2 ? white : blue for i=1:n, j=1:n],
Kernel.gaussian((1,1))
)
end
# ╔═╡ fe3559e0-f13b-11ea-06c8-a314e44c20d6
brightness(c) = 0.3 * c.r + 0.59 * c.g + 0.11 * c.b
# ╔═╡ 0ccf76e4-f0d9-11ea-07c9-0159e3d4d733
@bind img_select Radio(["disc", "mario"], default="disc")
# ╔═╡ 236dab08-f13d-11ea-1922-a3b82cfc7f51
begin
url = "http://files.softicons.com/download/game-icons/super-mario-icons-by-sandro-pereira/png/32/Retro%20Mario.png"
img = Dict(
"disc" => disc(25),
"mario" => load(download(url))
)[img_select]
end
# ╔═╡ 03434682-f13b-11ea-2b6e-11ad781e9a51
md"""Show $G_x$ $(@bind Gx CheckBox())
Show $G_y$ $(@bind Gy CheckBox())"""
# ╔═╡ ca13597a-f168-11ea-1a2c-ff7b98b7b2c7
function partial_derivatives(img)
Sy,Sx = Kernel.sobel()
∇x, ∇y = zeros(size(img)), zeros(size(img))
if Gx
∇x = convolve(brightness.(img), Sx)
end
if Gy
∇y = convolve(brightness.(img), Sy)
end
return ∇x, ∇y
end
# ╔═╡ b369584c-f183-11ea-260a-35dc797e63ad
# ╔═╡ b2cbe058-f183-11ea-39dc-23d4a5b92796
# ╔═╡ 9d9cccb2-f118-11ea-1638-c76682e636b2
function arrowhead(θ)
eq_triangle = [(0, 1/sqrt(3)),
(-1/3, -2/(2 * sqrt(3))),
(1/3, -2/(2 * sqrt(3)))]
compose(context(units=UnitBox(-1,-1,2,2), rotation=Rotation(θ, 0, 0)),
polygon(eq_triangle))
end
# ╔═╡ b7ea8a28-f0d7-11ea-3e98-7b19a1f58304
function quiver(points, vecs)
xmin = minimum(first.(points))
ymin = minimum(last.(points))
xmax = maximum(first.(points))
ymax = maximum(last.(points))
hs = map(x->hypot(x...), vecs)
hs = hs / maximum(hs)
vector(p, v, h) = all(iszero, v) ? context() :
(context(),
(context((p.+v.*6 .- .2)..., .4,.4),
arrowhead(atan(v[2], v[1]) - pi/2)),
stroke(RGBA(90/255,39/255,41/255,h)),
fill(RGBA(90/255,39/255,41/255,h)),
line([p, p.+v.*8]))
compose(context(units=UnitBox(xmin,ymin,xmax,ymax)),
vector.(points, vecs, hs)...)
end
# ╔═╡ c821b906-f0d8-11ea-2df0-8f2d06964aa2
function sobel_quiver(img, ∇x, ∇y)
quiver([(j-1,i-1) for i=1:size(img,1), j=1:size(img,2)],
[(∇x[i,j], ∇y[i,j]) for i=1:size(img,1), j=1:size(img,2)])
end
# ╔═╡ 6da3fdfe-f0dd-11ea-2407-7b85217b35cc
# render an Image using squares in Compose
function compimg(img)
xmax, ymax = size(img)
xmin, ymin = 0, 0
arr = [(j-1, i-1) for i=1:ymax, j=1:xmax]
compose(context(units=UnitBox(xmin, ymin, xmax, ymax)),
fill(vec(img)),
rectangle(
first.(arr),
last.(arr),
fill(1.0, length(arr)),
fill(1.0, length(arr))))
end
# ╔═╡ f22aa34e-f0df-11ea-3053-3dcdc070ec2f
let
∇x, ∇y = partial_derivatives(img)
compose(context(),
sobel_quiver(img, ∇x, ∇y),
compimg(img))
end
# ╔═╡ 885ec336-f146-11ea-00c4-c1d1ab4c0001
function show_colored_array(array)
pos_color = RGB(0.36, 0.82, 0.8)
neg_color = RGB(0.99, 0.18, 0.13)
to_rgb(x) = max(x, 0) * pos_color + max(-x, 0) * neg_color
to_rgb.(array) / maximum(abs.(array))
end
# ╔═╡ 9232dcc8-f188-11ea-08fe-b787ea93c598
begin
Sy, Sx = Kernel.sobel()
show_colored_array(Sx)
Sx
end
# ╔═╡ 7864bd00-f146-11ea-0020-7fccb3913d8b
let
∇x, ∇y = partial_derivatives(img)
to_show = (x -> RGB(0, 0, 0)).(zeros(size(img)))
if Gx && Gy
edged = sqrt.(∇x.^2 + ∇y.^2)
to_show = Gray.(edged) / maximum(edged)
elseif Gx
to_show = show_colored_array(∇x)
elseif Gy
to_show = show_colored_array(∇y)
end
compose(
context(),
compimg(to_show)
)
end
# ╔═╡ Cell order:
# ╠═15a4ba3e-f0d1-11ea-2ef1-5ff1dee8795f
# ╠═1ab1c808-f0d1-11ea-03a7-e9854427d45f
# ╠═21e744b8-f0d1-11ea-2e09-7ffbcdf43c37
# ╠═10f850fc-f0d1-11ea-2a58-2326a9ea1e2a
# ╟─7b4d5270-f0d3-11ea-0b48-79005f20602c
# ╠═6fd3b7a4-f0d3-11ea-1f26-fb9740cd16e0
# ╠═fe3559e0-f13b-11ea-06c8-a314e44c20d6
# ╟─b7ea8a28-f0d7-11ea-3e98-7b19a1f58304
# ╟─0ccf76e4-f0d9-11ea-07c9-0159e3d4d733
# ╟─236dab08-f13d-11ea-1922-a3b82cfc7f51
# ╟─03434682-f13b-11ea-2b6e-11ad781e9a51
# ╠═ca13597a-f168-11ea-1a2c-ff7b98b7b2c7
# ╟─f22aa34e-f0df-11ea-3053-3dcdc070ec2f
# ╟─9232dcc8-f188-11ea-08fe-b787ea93c598
# ╠═7864bd00-f146-11ea-0020-7fccb3913d8b
# ╠═b369584c-f183-11ea-260a-35dc797e63ad
# ╠═b2cbe058-f183-11ea-39dc-23d4a5b92796
# ╟─9d9cccb2-f118-11ea-1638-c76682e636b2
# ╟─c821b906-f0d8-11ea-2df0-8f2d06964aa2
# ╟─6da3fdfe-f0dd-11ea-2407-7b85217b35cc
# ╠═885ec336-f146-11ea-00c4-c1d1ab4c0001