From 7390ad520bb87408a604bc5522c990cf71c572c7 Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Thu, 20 Oct 2022 00:07:07 +0200 Subject: [PATCH] PlutoUI.DrawCanvas --- src/WebcamInput.jl | 314 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 300 insertions(+), 14 deletions(-) diff --git a/src/WebcamInput.jl b/src/WebcamInput.jl index df27e139..e6e0dc9a 100644 --- a/src/WebcamInput.jl +++ b/src/WebcamInput.jl @@ -53,14 +53,14 @@ Accepts a `Dict{Any, Any}` similar to the ImageData type, i.e. with keys - `data`: image data - 3 elements per pixel, ``3*width*height`` total length """ -function ImageDataToRGBA(d::Dict) +function ImageDataToRGBA(T, d::Dict) width = d["width"] height = d["height"] PermutedDimsArray( # lazy transpose reshape( # lazy unflatten - reinterpret( # lazy UInt8 to RGB{N0f8} - RGB{N0f8}, d["data"]::Vector{UInt8}), + reinterpret( # lazy UInt8 to T + T, d["data"]::Vector{UInt8}), width, height ), (2,1) @@ -85,7 +85,7 @@ function RGBAToImageData(img) end # ╔═╡ 6dd82485-a392-4110-9148-f70f0e7c0985 -const standard_default_avoid_allocs = ImageDataToRGBA(Dict{Any,Any}( +const standard_default_avoid_allocs = ImageDataToRGBA(RGB{N0f8}, Dict{Any,Any}( "width" => 1, "height" => 1, "data" => UInt8[0,0,0], )) @@ -228,7 +228,7 @@ const help = @htl(""" """) # ╔═╡ 06062a16-d9e1-46ef-95bd-cdae8b03bafd -function html(webcam) +function webcam_html(webcam) @htl(""" @@ -469,6 +469,271 @@ function html(webcam) """) end +# ╔═╡ 04bbfc5b-2eb2-4024-a035-ddc8fe60a932 +# ╠═╡ skip_as_script = true +#=╠═╡ +test_img = rand(RGB{N0f8}, 8, 8) + ╠═╡ =# + +# ╔═╡ c0b1da1e-8023-4b88-86c2-d93afd40618b +md""" +# DrawCanvas +""" + +# ╔═╡ 86c652d4-fa0f-4cfa-831f-e9a893351b81 +function canvas_html(canvas) + @htl """
""" +end + +# ╔═╡ b31f6b0e-45be-441b-9694-4c786235f132 +begin + local result = begin + Base.@kwdef struct DrawCanvas + help::Bool = true + avoid_allocs::Bool = false + output_size::Tuple{Int64,Int64}=(200,200) + default::Union{Nothing,AbstractMatrix{RGB{N0f8}}}=nothing + end + + @doc """ + ```julia + @bind image DrawCanvas(; kwargs...) + ``` + + A canvas that you can draw on with your mouse / touch screen. The current drawing is returned as a `Matrix{RGB}` via `@bind`. + + # How to use a `Matrix{RGB}` + + The output type is of the type `Matrix{RGB{N0f8}}`, let's break that down: + - `Matrix`: This is a 2D **Array**, which you can index like `img[10,20]` to get an entry, of type `RGB{N0f8}`. + - `RGB` (from [ColorTypes.jl](https://github.com/JuliaGraphics/ColorTypes.jl)): a `struct` with fields `r` (Red), `g` (Green) and `b` (Blue), each of type `N0f8`. These are the digital 'channel' value that make up a color. + - `N0f8` (from [FixedPointNumbers.jl](https://github.com/JuliaMath/FixedPointNumbers.jl)): a special type of floating point number that uses only 8 bits. Think of it as a `Float8`, rather than the usual `Float64`. You can use `Float64(x)` to convert to a normal `Float64`. + + By default, a `Matrix{RGB}` will be displayed using text, but if you add + ```julia + import ImageShow, ImageIO + ``` + somewhere in your notebook, then Pluto will be able to display the matrix as a color image. + + For more image manipulation capabilities, check out [`Images.jl`](https://github.com/JuliaImages/Images.jl). + + # Keyword arguments + + - `help::Bool=true` by default, we display a little help message when you use `WebcamInput`. You can disable that here. + - `default::Matrix{RGB{N0f8}}` set a default image, which is used until the user captures an image. Defaults to a **1x1 transparent image**. + - `max_size::Int64` when given, this constraints the largest dimension of the image, while maintaining aspect ratio. A lower value has better performance. + - `avoid_allocs::Bool=false` when set to `true`, we lazily convert the raw `Vector{UInt8}` camera data to a `AbstractMatrix{RGB{N0f8}}`, with zero allocations. This will lead to better performance, but the bound value will be an `AbstractMatrix`, not a `Matrix`. + + # Examples + + ```julia + @bind image WebcamInput() + ``` + + Let's see what we captured: + + ```julia + import ImageShow, ImageIO + ``` + ```julia + image + ``` + + Let's look at the **size** of the matrix: + + ```julia + size(image) + ``` + + To get the **green** channel value of the **top right** pixel of the image: + + ```julia + image[1, end].g + ``` + + """ DrawCanvas + end + + function AbstractPlutoDingetjes.Bonds.initial_value(w::DrawCanvas) + return w.default !== nothing ? + w.default : + w.avoid_allocs ? standard_default_avoid_allocs : standard_default + end + Base.get(w::DrawCanvas) = AbstractPlutoDingetjes.Bonds.initial_value(w) + + # function AbstractPlutoDingetjes.Bonds.transform_value(w::DrawCanvas, d) + # if d isa Dict + # img_lazy = ImageDataToRGBA(RGB{N0f8}, d) + # w.avoid_allocs ? img_lazy : collect(img_lazy) + # else + # AbstractPlutoDingetjes.Bonds.initial_value(w) + # end + # end + + function Base.show(io::IO, m::MIME"text/html", webcam::DrawCanvas) + webcam.help && @info help + Base.show(io, m, canvas_html(webcam)) + end + result +end + # ╔═╡ d9b806a2-de81-4b50-88cd-acf7db35da9a begin local result = begin @@ -547,7 +812,7 @@ begin function AbstractPlutoDingetjes.Bonds.transform_value(w::WebcamInput, d) if d isa Dict - img_lazy = ImageDataToRGBA(d) + img_lazy = ImageDataToRGBA(RGB{N0f8}, d) w.avoid_allocs ? img_lazy : collect(img_lazy) else AbstractPlutoDingetjes.Bonds.initial_value(w) @@ -556,7 +821,7 @@ begin function Base.show(io::IO, m::MIME"text/html", webcam::WebcamInput) webcam.help && @info help - Base.show(io, m, html(webcam)) + Base.show(io, m, webcam_html(webcam)) end result end @@ -612,12 +877,6 @@ typeof(img2) img2 ╠═╡ =# -# ╔═╡ 04bbfc5b-2eb2-4024-a035-ddc8fe60a932 -# ╠═╡ skip_as_script = true -#=╠═╡ -test_img = rand(RGB{N0f8}, 8, 8) - ╠═╡ =# - # ╔═╡ 3ed223be-2808-4e8f-b3c0-f2caaa11a6d2 #=╠═╡ @bind img3 WebcamInput(; default=test_img, help=false) @@ -638,6 +897,24 @@ typeof(img3) img3 ╠═╡ =# +# ╔═╡ b75fcead-799b-4022-af43-79c4387d64dc +cb1 = @bind c1 DrawCanvas(help=false, output_size=(199,199)) + +# ╔═╡ 6eed9b89-4e42-49c1-85e5-6e04d35c889c +# ImageDataToRGBA(Bool, c1) + +# ╔═╡ 0f9aeadb-03a6-40b3-8030-2497c0ab2e7d +ImageDataToRGBA(Gray{N0f8}, c1) + +# ╔═╡ 0ce12c7d-38d2-42ed-80a4-2cec28ab5f54 +cb1 + +# ╔═╡ 6b5a4aca-3abc-4670-adcc-37539d7530ac +c1 + +# ╔═╡ d87918b5-4879-491b-93e0-28d707c17423 +reinterpret(Bool,c1["data"]) + # ╔═╡ Cell order: # ╠═1791669b-d1ee-4c62-9485-52d8493888a7 # ╠═5d9f2eeb-4cf6-4ab7-8475-301547570a32 @@ -655,7 +932,7 @@ img3 # ╟─d9b806a2-de81-4b50-88cd-acf7db35da9a # ╟─97e2467e-ca58-4b5f-949d-ad95253b1ac0 # ╟─3d2ed3d4-60a7-416c-aaae-4dc662127f5b -# ╠═06062a16-d9e1-46ef-95bd-cdae8b03bafd +# ╟─06062a16-d9e1-46ef-95bd-cdae8b03bafd # ╠═ba3b6ecb-062e-4dd3-bfbe-a757fd63c4a7 # ╠═d0b8b2ac-60be-481d-8085-3e57525e4a74 # ╠═55ca59b0-c292-4711-9aa6-81499184423c @@ -670,3 +947,12 @@ img3 # ╠═e72950c1-2130-4a49-8d9c-0216c365683f # ╠═a5308e5b-77d2-4bc3-b368-15320d6a4049 # ╠═af7b1cec-2a47-4d90-8e66-90940ae3a087 +# ╟─c0b1da1e-8023-4b88-86c2-d93afd40618b +# ╠═b31f6b0e-45be-441b-9694-4c786235f132 +# ╠═86c652d4-fa0f-4cfa-831f-e9a893351b81 +# ╠═b75fcead-799b-4022-af43-79c4387d64dc +# ╠═6eed9b89-4e42-49c1-85e5-6e04d35c889c +# ╠═0f9aeadb-03a6-40b3-8030-2497c0ab2e7d +# ╠═0ce12c7d-38d2-42ed-80a4-2cec28ab5f54 +# ╠═6b5a4aca-3abc-4670-adcc-37539d7530ac +# ╠═d87918b5-4879-491b-93e0-28d707c17423