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
						
					
					
				
			
		
		
	
	
							257 lines
						
					
					
						
							6.4 KiB
						
					
					
				### A Pluto.jl notebook ###
 | 
						|
# v0.11.10
 | 
						|
 | 
						|
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
 |