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.
808 lines
20 KiB
808 lines
20 KiB
### A Pluto.jl notebook ###
|
|
# v0.11.12
|
|
|
|
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
|
|
|
|
# ╔═╡ 5e688928-e939-11ea-0e16-fbc80af390ab
|
|
using LinearAlgebra
|
|
|
|
# ╔═╡ a50b5f48-e8d5-11ea-1f05-a3741b5d15ba
|
|
html"<button onclick=present()>Present</button>"
|
|
|
|
# ╔═╡ 8a6fed4c-e94b-11ea-1113-d56f56fb293b
|
|
br = HTML("<br>")
|
|
|
|
# ╔═╡ dc53f316-e8c8-11ea-150f-1374dbce114a
|
|
md"""# Welcome to 18.S191 -- Fall 2020!
|
|
|
|
### Introduction to Computational Thinking for Real-World Problems"""
|
|
|
|
# ╔═╡ c3f43d66-e94b-11ea-02bd-23cfeb878ff1
|
|
br
|
|
|
|
# ╔═╡ c6c77738-e94b-11ea-22f5-1dce3dbcc3ca
|
|
md"### <https://github.com/mitmath/18S191>"
|
|
|
|
# ╔═╡ cf80793a-e94b-11ea-0120-f7913ae06f22
|
|
br
|
|
|
|
# ╔═╡ d1638d96-e94b-11ea-2ff4-910e399f864d
|
|
md"##### Alan Edelman, David P. Sanders, Grant Sanderson, James Schloss"
|
|
|
|
# ╔═╡ 0117246a-e94c-11ea-1a76-c981ce8e725d
|
|
md"##### & Philip the Corgi"
|
|
|
|
# ╔═╡ 27060098-e8c9-11ea-2fe0-03b39b1ddc32
|
|
md"""# Class outline
|
|
|
|
### Data and computation
|
|
|
|
- Module 1: Analyzing images
|
|
|
|
- Module 2: Particles and ray tracing
|
|
|
|
- Module 3: Epidemic spread
|
|
|
|
- Module 4: Climate change
|
|
"""
|
|
|
|
# ╔═╡ 4fc58814-e94b-11ea-339b-cb714a63f9b6
|
|
md"## Tools
|
|
|
|
- Julia programming language: <http://www.julialang.org/learning>
|
|
|
|
- Pluto notebook environment
|
|
"
|
|
|
|
# ╔═╡ f067d3b8-e8c8-11ea-20cb-474709ffa99a
|
|
md"""# Module 1: Images"""
|
|
|
|
# ╔═╡ 37c1d012-ebc9-11ea-2dfe-8b86bb78f283
|
|
4 + 4
|
|
|
|
# ╔═╡ a0a97214-e8d2-11ea-0f46-0bfaf016ab6d
|
|
md"""## Data takes many forms
|
|
|
|
- Time series:
|
|
- Number of infections per day
|
|
- Stock price each minute
|
|
- A piece for violin broadcast over the radio
|
|
$(HTML("<br>"))
|
|
|
|
- Video:
|
|
- The view from a window of a self-driving car
|
|
- A hurricane monitoring station
|
|
$(HTML("<br>"))
|
|
|
|
- Images:
|
|
- Diseased versus healthy tissue in a scan
|
|
- Deep space via the Hubble telescope
|
|
- Can your social media account recognise your friends?
|
|
"""
|
|
|
|
# ╔═╡ 1697a756-e93d-11ea-0b6e-c9c78d527993
|
|
md"## Capture your own image!"
|
|
|
|
# ╔═╡ af28faca-ebb7-11ea-130d-0f94bf9bd836
|
|
|
|
|
|
# ╔═╡ ee1d1596-e94a-11ea-0fb4-cd05f62471d3
|
|
md"##"
|
|
|
|
# ╔═╡ 8ab9a978-e8c9-11ea-2476-f1ef4ba1b619
|
|
md"""## What is an image?"""
|
|
|
|
# ╔═╡ 38c54bfc-e8cb-11ea-3d52-0f02452f8ba1
|
|
md"Albrecht Dürer:"
|
|
|
|
# ╔═╡ 983f8270-e8c9-11ea-29d2-adeccb5a7ffc
|
|
# md"# begin
|
|
# using Images
|
|
|
|
# download("https://i.stack.imgur.com/QQL8X.jpg", "durer.jpg")
|
|
|
|
# load("durer.jpg")
|
|
# end
|
|
|
|
md""
|
|
|
|
# ╔═╡ 2fcaef88-e8ca-11ea-23f7-29c48580f43c
|
|
md"""##
|
|
|
|
An image is:
|
|
|
|
- A 2D representation of a 3D world
|
|
|
|
- An approximation
|
|
|
|
"""
|
|
|
|
# ╔═╡ 7636c4b0-e8d1-11ea-2051-757a850a9d30
|
|
begin
|
|
image_text =
|
|
md"""
|
|
## What *is* an image, though?
|
|
|
|
- A grid of coloured squares called **pixels**
|
|
|
|
- A colour for each pair $(i, j)$ of indices
|
|
|
|
- A **discretization**
|
|
|
|
"""
|
|
|
|
image_text
|
|
end
|
|
|
|
# ╔═╡ bca22176-e8ca-11ea-2004-ebeb103116b5
|
|
md"""
|
|
## How can we store an image in the computer?
|
|
|
|
- Is it a 1D array (`Vector`)?
|
|
|
|
- A 2D array (`Matrix`)?
|
|
|
|
- A 3D array (`tensor`)?
|
|
"""
|
|
|
|
# ╔═╡ 0ad91f1e-e8d2-11ea-2c18-93f66c906a8b
|
|
md"""## If in doubt: Ask Julia!
|
|
|
|
- Let's use the `Images.jl` package to load an image and see what we get
|
|
"""
|
|
|
|
# ╔═╡ de373816-ec79-11ea-2772-ebdca52246ac
|
|
begin
|
|
import Pkg
|
|
Pkg.activate(mktempdir())
|
|
end
|
|
|
|
# ╔═╡ 552129ae-ebca-11ea-1fa1-3f9fa00a2601
|
|
begin
|
|
Pkg.add(["Images", "ImageIO", "ImageMagick"])
|
|
using Images
|
|
end
|
|
|
|
# ╔═╡ fbe11200-e938-11ea-12e9-6125c1b56b25
|
|
begin
|
|
Pkg.add("PlutoUI")
|
|
using PlutoUI
|
|
end
|
|
|
|
# ╔═╡ 54c1ba3c-e8d2-11ea-3564-bdaca8563738
|
|
# defines a variable called `url`
|
|
# whose value is a string (written inside `"`):
|
|
|
|
url = "https://i.imgur.com/VGPeJ6s.jpg"
|
|
|
|
# ╔═╡ 6e0fefb6-e8d4-11ea-1f9b-e7a3db40df39
|
|
philip_file = download(url, "philip.jpg") # download to a local file
|
|
|
|
# ╔═╡ 9c359212-ec79-11ea-2d7e-0124dad5f127
|
|
philip = load(philip_file)
|
|
|
|
# ╔═╡ 7703b032-ebca-11ea-3074-0b80a077078e
|
|
philip
|
|
|
|
# ╔═╡ 7eff3522-ebca-11ea-1a65-59e66a4e72ab
|
|
typeof(philip)
|
|
|
|
# ╔═╡ c9cd6c04-ebca-11ea-0990-5fa19ff7ed97
|
|
RGBX(0.9, 0.1, 0.1)
|
|
|
|
# ╔═╡ 0d873d9c-e93b-11ea-2425-1bd79677fb97
|
|
md"##"
|
|
|
|
# ╔═╡ 6b09354a-ebb9-11ea-2d5a-3b75c5ae7aa9
|
|
|
|
|
|
# ╔═╡ 2d6c434e-e93b-11ea-2678-3b9db4975089
|
|
md"##"
|
|
|
|
# ╔═╡ 2b14e93e-e93b-11ea-25f1-5f565f80e778
|
|
typeof(philip)
|
|
|
|
# ╔═╡ 0bdc6058-e8d5-11ea-1889-3f706cea7a1f
|
|
md"""##
|
|
|
|
- According to Julia / Pluto, the variable `philip` *is* an image
|
|
|
|
- Julia always returns output
|
|
|
|
- The output can be displayed in a "rich" way
|
|
|
|
$(HTML("<br>"))
|
|
|
|
- Arthur C. Clarke:
|
|
|
|
> Any sufficiently advanced technology is indistinguishable from magic.
|
|
"""
|
|
|
|
# ╔═╡ e61db924-ebca-11ea-2f79-f9f1c121b7f5
|
|
size(philip)
|
|
|
|
# ╔═╡ ef60fcc4-ebca-11ea-3f69-155afffe8ea8
|
|
philip
|
|
|
|
# ╔═╡ fac550ec-ebca-11ea-337a-dbc16848c617
|
|
philip[1:1000, 1:400]
|
|
|
|
# ╔═╡ 42aa8cfe-e8d5-11ea-3cb9-c365b98e7a8c
|
|
md"
|
|
## How big is Philip?
|
|
|
|
- He's pretty big:
|
|
"
|
|
|
|
# ╔═╡ 4eea5710-e8d5-11ea-3978-af66ee2a137e
|
|
size(philip)
|
|
|
|
# ╔═╡ 57b3a0c2-e8d5-11ea-15aa-8da4549f849b
|
|
md"- Which number is which?"
|
|
|
|
# ╔═╡ 03a7c0fc-ebba-11ea-1c71-79d750c97b16
|
|
philip
|
|
|
|
# ╔═╡ e6fd68fa-e8d8-11ea-3dc4-274caceda222
|
|
md"# So, what *is* an image?"
|
|
|
|
# ╔═╡ 63a1d282-e8d5-11ea-0bba-b9cdd32a218b
|
|
typeof(philip)
|
|
|
|
# ╔═╡ fc5e1af0-e8d8-11ea-1077-07216ff96d29
|
|
md"""
|
|
- It's an `Array`
|
|
|
|
- The `2` means that it has **2 dimensions** (a **matrix**)
|
|
|
|
$(HTML("<br>"))
|
|
|
|
- `RGBX{Normed{UInt8,8}}` is the type of object stored in the array
|
|
|
|
- A Julia object representing a colour
|
|
|
|
- RGB = Red, Green, Blue
|
|
"""
|
|
|
|
# ╔═╡ c79dd836-e8e8-11ea-029d-57be9899979a
|
|
md"## Getting pieces of an image"
|
|
|
|
|
|
|
|
# ╔═╡ ae260168-e932-11ea-38fd-4f2c6f43e21c
|
|
begin
|
|
(h, w) = size(philip)
|
|
head = philip[(h ÷ 2):h, (w ÷ 10): (9w ÷ 10)]
|
|
# `÷` is typed as \div <TAB> -- integer division
|
|
end
|
|
|
|
# ╔═╡ 47d1bc04-ebcb-11ea-3643-d1ba8dea57c8
|
|
size(head)
|
|
|
|
# ╔═╡ 72400458-ebcb-11ea-26b6-678ae1de8e23
|
|
size(philip)
|
|
|
|
# ╔═╡ f57ea7c2-e932-11ea-0d52-4112187bcb38
|
|
md"## Manipulating matrices
|
|
|
|
- An image is just a matrix, so we can manipulate *matrices* to manipulate the *image*
|
|
"
|
|
|
|
# ╔═╡ 740ed2e2-e933-11ea-236c-f3c3f09d0f8b
|
|
[head head]
|
|
|
|
# ╔═╡ 6128a5ba-e93b-11ea-03f5-f170c7b90b25
|
|
md"##"
|
|
|
|
# ╔═╡ 78eafe4e-e933-11ea-3539-c13feb894ef6
|
|
[
|
|
head reverse(head, dims=2)
|
|
reverse(head, dims=1) reverse(reverse(head, dims=1), dims=2)
|
|
]
|
|
|
|
# ╔═╡ bf3f9050-e933-11ea-0df7-e5dcff6bb3ee
|
|
md"## Manipulating an image
|
|
|
|
- How can we get inside the image and change it?
|
|
|
|
- There are two possibilities:
|
|
|
|
- **Modify** (**mutate**) numbers inside the array -- useful to change a small piece
|
|
|
|
- Create a new **copy** of the array -- useful to alter everything together
|
|
"
|
|
|
|
# ╔═╡ 212e1f12-e934-11ea-2f35-51c7a6c8dff1
|
|
md"## Painting a piece of an image
|
|
|
|
- Let's paint a corner red
|
|
|
|
- We'll copy the image first so we don't destroy the original
|
|
"
|
|
|
|
# ╔═╡ 117a98c0-e936-11ea-3aac-8f66337cea68
|
|
new_phil = copy(head)
|
|
|
|
# ╔═╡ 8004d076-e93b-11ea-29cc-a1bfcc75e87f
|
|
md"##"
|
|
|
|
# ╔═╡ 3ac63296-e936-11ea-2144-f94bdbd60eaf
|
|
red = RGB(1, 0, 0)
|
|
|
|
# ╔═╡ 3e3f841a-e936-11ea-0a81-1b95fe0faa83
|
|
for i in 1:100
|
|
for j in 1:300
|
|
new_phil[i, j] = red
|
|
end
|
|
end
|
|
|
|
# ╔═╡ 5978db50-e936-11ea-3145-059a51be2281
|
|
md"Note that `for` loops *do not return anything* (or, rather, they return `nothing`)"
|
|
|
|
# ╔═╡ 21638b14-ebcc-11ea-1761-bbd2f4306a96
|
|
new_phil
|
|
|
|
# ╔═╡ 70cb0e36-e936-11ea-3ade-49fde77cb696
|
|
md"""## Element-wise operations: "Broadcasting"
|
|
|
|
- Julia provides powerful technology for operating element by element: **broadcasting**
|
|
|
|
- Adding "`.`" applies an operation element by element
|
|
"""
|
|
|
|
# ╔═╡ b3ea975e-e936-11ea-067d-81339575a3cb
|
|
begin
|
|
new_phil2 = copy(new_phil)
|
|
new_phil2[100:200, 1:100] .= RGB(0, 1, 0)
|
|
new_phil2
|
|
end
|
|
|
|
# ╔═╡ 918a0762-e93b-11ea-1115-71dbfdb03f27
|
|
md"##"
|
|
|
|
# ╔═╡ daabe66c-e937-11ea-3bc3-d77f2bce406c
|
|
new_phil2
|
|
|
|
# ╔═╡ 095ced62-e938-11ea-1169-939dc7136fd0
|
|
md"## Modifying the whole image at once
|
|
|
|
- We can use the same trick to modify the whole image at once
|
|
|
|
- Let's **redify** the image
|
|
|
|
- We define a **function** that turns a colour into just its red component
|
|
"
|
|
|
|
# ╔═╡ 31f3605a-e938-11ea-3a6d-29a185bbee31
|
|
function redify(c)
|
|
return RGB(c.r, 0, 0)
|
|
end
|
|
|
|
# ╔═╡ 2744a556-e94f-11ea-2434-d53c24e59285
|
|
begin
|
|
color = RGB(0.9, 0.7, 0.2)
|
|
|
|
[color, redify(color)]
|
|
end
|
|
|
|
# ╔═╡ 98412a36-e93b-11ea-1954-f1c105c6ed4a
|
|
md"##"
|
|
|
|
# ╔═╡ 3c32efde-e938-11ea-1ae4-5d88290f5311
|
|
redify.(philip)
|
|
|
|
# ╔═╡ 4b26e4e6-e938-11ea-2635-6d4fc15e13b7
|
|
md"## Transforming an image
|
|
|
|
- The main goal of this week will be to transfrom images in more interesting ways
|
|
|
|
- First let's **decimate** poor Phil
|
|
"
|
|
|
|
|
|
|
|
# ╔═╡ c12e0928-e93b-11ea-0922-2b590a99ee89
|
|
md"##"
|
|
|
|
# ╔═╡ ff5dc538-e938-11ea-058f-693d6b016640
|
|
md"## Experiments come alive with interaction
|
|
|
|
- We start to get a feel for things when we can **experiment**!
|
|
"
|
|
|
|
# ╔═╡ fa24f4a8-e93b-11ea-06bd-25c9672166d6
|
|
md"##"
|
|
|
|
# ╔═╡ 15ce202e-e939-11ea-2387-93be0ec4cf1f
|
|
@bind repeat_count Slider(1:10, show_value=true)
|
|
|
|
# ╔═╡ bf2167a4-e93d-11ea-03b2-cdd24b459ba9
|
|
md"## Summary
|
|
|
|
- Images are readily-accessible data about the world
|
|
|
|
- We want to process them to extract information
|
|
|
|
- Relatively simple mathematical operations can transform images in useful ways
|
|
"
|
|
|
|
# ╔═╡ 58184d88-e939-11ea-2fc8-73b3476ebe92
|
|
expand(image, ratio=5) = kron(image, ones(ratio, ratio))
|
|
|
|
# ╔═╡ 2dd09f16-e93a-11ea-2cdc-13f558e3391d
|
|
extract_red(c) = c.r
|
|
|
|
# ╔═╡ df1b7996-e93b-11ea-1a3a-81b4ec520679
|
|
decimate(image, ratio=5) = image[1:ratio:end, 1:ratio:end]
|
|
|
|
# ╔═╡ 41fa85c0-e939-11ea-1ad8-79805a2083bb
|
|
poor_phil = decimate(head, 5)
|
|
|
|
# ╔═╡ cd5721d0-ede6-11ea-0918-1992c69bccc6
|
|
repeat(poor_phil, repeat_count, repeat_count)
|
|
|
|
# ╔═╡ b8daeea0-ec79-11ea-34b5-3f13e8a56a42
|
|
md"# Appendix"
|
|
|
|
# ╔═╡ bf1bb2c8-ec79-11ea-0671-3ffb34828f3c
|
|
md"## Package environment"
|
|
|
|
# ╔═╡ 69e3aa82-e93c-11ea-23fe-c1103d989cba
|
|
md"## Camera input"
|
|
|
|
# ╔═╡ 739c3bb6-e93c-11ea-127b-efb6a8ab9379
|
|
function camera_input(;max_size=200, default_url="https://i.imgur.com/SUmi94P.png")
|
|
"""
|
|
<span class="pl-image waiting-for-permission">
|
|
<style>
|
|
|
|
.pl-image.popped-out {
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
z-index: 5;
|
|
}
|
|
|
|
.pl-image #video-container {
|
|
width: 250px;
|
|
}
|
|
|
|
.pl-image video {
|
|
border-radius: 1rem 1rem 0 0;
|
|
}
|
|
.pl-image.waiting-for-permission #video-container {
|
|
display: none;
|
|
}
|
|
.pl-image #prompt {
|
|
display: none;
|
|
}
|
|
.pl-image.waiting-for-permission #prompt {
|
|
width: 250px;
|
|
height: 200px;
|
|
display: grid;
|
|
place-items: center;
|
|
font-family: monospace;
|
|
font-weight: bold;
|
|
text-decoration: underline;
|
|
cursor: pointer;
|
|
border: 5px dashed rgba(0,0,0,.5);
|
|
}
|
|
|
|
.pl-image video {
|
|
display: block;
|
|
}
|
|
.pl-image .bar {
|
|
width: inherit;
|
|
display: flex;
|
|
z-index: 6;
|
|
}
|
|
.pl-image .bar#top {
|
|
position: absolute;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.pl-image .bar#bottom {
|
|
background: black;
|
|
border-radius: 0 0 1rem 1rem;
|
|
}
|
|
.pl-image .bar button {
|
|
flex: 0 0 auto;
|
|
background: rgba(255,255,255,.8);
|
|
border: none;
|
|
width: 2rem;
|
|
height: 2rem;
|
|
border-radius: 100%;
|
|
cursor: pointer;
|
|
z-index: 7;
|
|
}
|
|
.pl-image .bar button#shutter {
|
|
width: 3rem;
|
|
height: 3rem;
|
|
margin: -1.5rem auto .2rem auto;
|
|
}
|
|
|
|
.pl-image video.takepicture {
|
|
animation: pictureflash 200ms linear;
|
|
}
|
|
|
|
@keyframes pictureflash {
|
|
0% {
|
|
filter: grayscale(1.0) contrast(2.0);
|
|
}
|
|
|
|
100% {
|
|
filter: grayscale(0.0) contrast(1.0);
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<div id="video-container">
|
|
<div id="top" class="bar">
|
|
<button id="stop" title="Stop video">✖</button>
|
|
<button id="pop-out" title="Pop out/pop in">⏏</button>
|
|
</div>
|
|
<video playsinline autoplay></video>
|
|
<div id="bottom" class="bar">
|
|
<button id="shutter" title="Click to take a picture">📷</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="prompt">
|
|
<span>
|
|
Enable webcam
|
|
</span>
|
|
</div>
|
|
|
|
<script>
|
|
// based on https://github.com/fonsp/printi-static (by the same author)
|
|
|
|
const span = this.currentScript.parentElement
|
|
const video = span.querySelector("video")
|
|
const popout = span.querySelector("button#pop-out")
|
|
const stop = span.querySelector("button#stop")
|
|
const shutter = span.querySelector("button#shutter")
|
|
const prompt = span.querySelector(".pl-image #prompt")
|
|
|
|
const maxsize = $(max_size)
|
|
|
|
const send_source = (source, src_width, src_height) => {
|
|
const scale = Math.min(1.0, maxsize / src_width, maxsize / src_height)
|
|
|
|
const width = Math.floor(src_width * scale)
|
|
const height = Math.floor(src_height * scale)
|
|
|
|
const canvas = html`<canvas width=\${width} height=\${height}>`
|
|
const ctx = canvas.getContext("2d")
|
|
ctx.drawImage(source, 0, 0, width, height)
|
|
|
|
span.value = {
|
|
width: width,
|
|
height: height,
|
|
data: ctx.getImageData(0, 0, width, height).data,
|
|
}
|
|
span.dispatchEvent(new CustomEvent("input"))
|
|
}
|
|
|
|
const clear_camera = () => {
|
|
window.stream.getTracks().forEach(s => s.stop());
|
|
video.srcObject = null;
|
|
|
|
span.classList.add("waiting-for-permission");
|
|
}
|
|
|
|
prompt.onclick = () => {
|
|
navigator.mediaDevices.getUserMedia({
|
|
audio: false,
|
|
video: {
|
|
facingMode: "environment",
|
|
},
|
|
}).then(function(stream) {
|
|
|
|
stream.onend = console.log
|
|
|
|
window.stream = stream
|
|
video.srcObject = stream
|
|
window.cameraConnected = true
|
|
video.controls = false
|
|
video.play()
|
|
video.controls = false
|
|
|
|
span.classList.remove("waiting-for-permission");
|
|
|
|
}).catch(function(error) {
|
|
console.log(error)
|
|
});
|
|
}
|
|
stop.onclick = () => {
|
|
clear_camera()
|
|
}
|
|
popout.onclick = () => {
|
|
span.classList.toggle("popped-out")
|
|
}
|
|
|
|
shutter.onclick = () => {
|
|
const cl = video.classList
|
|
cl.remove("takepicture")
|
|
void video.offsetHeight
|
|
cl.add("takepicture")
|
|
video.play()
|
|
video.controls = false
|
|
console.log(video)
|
|
send_source(video, video.videoWidth, video.videoHeight)
|
|
}
|
|
|
|
|
|
document.addEventListener("visibilitychange", () => {
|
|
if (document.visibilityState != "visible") {
|
|
clear_camera()
|
|
}
|
|
})
|
|
|
|
|
|
// Set a default image
|
|
|
|
const img = html`<img crossOrigin="anonymous">`
|
|
|
|
img.onload = () => {
|
|
console.log("helloo")
|
|
send_source(img, img.width, img.height)
|
|
}
|
|
img.src = "$(default_url)"
|
|
console.log(img)
|
|
</script>
|
|
</span>
|
|
""" |> HTML
|
|
end
|
|
|
|
|
|
# ╔═╡ 9529bc40-e93c-11ea-2587-3186e0978476
|
|
@bind raw_camera_data camera_input(;max_size=2000)
|
|
|
|
# ╔═╡ 832ebd1a-e93c-11ea-1d18-d784f3184ebe
|
|
|
|
function process_raw_camera_data(raw_camera_data)
|
|
# the raw image data is a long byte array, we need to transform it into something
|
|
# more "Julian" - something with more _structure_.
|
|
|
|
# The encoding of the raw byte stream is:
|
|
# every 4 bytes is a single pixel
|
|
# every pixel has 4 values: Red, Green, Blue, Alpha
|
|
# (we ignore alpha for this notebook)
|
|
|
|
# So to get the red values for each pixel, we take every 4th value, starting at
|
|
# the 1st:
|
|
reds_flat = UInt8.(raw_camera_data["data"][1:4:end])
|
|
greens_flat = UInt8.(raw_camera_data["data"][2:4:end])
|
|
blues_flat = UInt8.(raw_camera_data["data"][3:4:end])
|
|
|
|
# but these are still 1-dimensional arrays, nicknamed 'flat' arrays
|
|
# We will 'reshape' this into 2D arrays:
|
|
|
|
width = raw_camera_data["width"]
|
|
height = raw_camera_data["height"]
|
|
|
|
# shuffle and flip to get it in the right shape
|
|
reds = reshape(reds_flat, (width, height))' / 255.0
|
|
greens = reshape(greens_flat, (width, height))' / 255.0
|
|
blues = reshape(blues_flat, (width, height))' / 255.0
|
|
|
|
# we have our 2D array for each color
|
|
# Let's create a single 2D array, where each value contains the R, G and B value of
|
|
# that pixel
|
|
|
|
RGB.(reds, greens, blues)
|
|
end
|
|
|
|
# ╔═╡ 9a843af8-e93c-11ea-311b-1bc6d5b58492
|
|
grant = decimate(process_raw_camera_data(raw_camera_data), 2)
|
|
|
|
# ╔═╡ 6aa73286-ede7-11ea-232b-63e052222ecd
|
|
[
|
|
grant grant[:,end:-1:1]
|
|
grant[end:-1:1,:] grant[end:-1:1,end:-1:1]
|
|
]
|
|
|
|
# ╔═╡ Cell order:
|
|
# ╟─a50b5f48-e8d5-11ea-1f05-a3741b5d15ba
|
|
# ╟─8a6fed4c-e94b-11ea-1113-d56f56fb293b
|
|
# ╟─dc53f316-e8c8-11ea-150f-1374dbce114a
|
|
# ╟─c3f43d66-e94b-11ea-02bd-23cfeb878ff1
|
|
# ╟─c6c77738-e94b-11ea-22f5-1dce3dbcc3ca
|
|
# ╟─cf80793a-e94b-11ea-0120-f7913ae06f22
|
|
# ╟─d1638d96-e94b-11ea-2ff4-910e399f864d
|
|
# ╟─0117246a-e94c-11ea-1a76-c981ce8e725d
|
|
# ╟─27060098-e8c9-11ea-2fe0-03b39b1ddc32
|
|
# ╟─4fc58814-e94b-11ea-339b-cb714a63f9b6
|
|
# ╟─f067d3b8-e8c8-11ea-20cb-474709ffa99a
|
|
# ╠═37c1d012-ebc9-11ea-2dfe-8b86bb78f283
|
|
# ╟─a0a97214-e8d2-11ea-0f46-0bfaf016ab6d
|
|
# ╟─1697a756-e93d-11ea-0b6e-c9c78d527993
|
|
# ╟─af28faca-ebb7-11ea-130d-0f94bf9bd836
|
|
# ╠═9529bc40-e93c-11ea-2587-3186e0978476
|
|
# ╟─ee1d1596-e94a-11ea-0fb4-cd05f62471d3
|
|
# ╠═6aa73286-ede7-11ea-232b-63e052222ecd
|
|
# ╠═9a843af8-e93c-11ea-311b-1bc6d5b58492
|
|
# ╟─8ab9a978-e8c9-11ea-2476-f1ef4ba1b619
|
|
# ╟─38c54bfc-e8cb-11ea-3d52-0f02452f8ba1
|
|
# ╟─983f8270-e8c9-11ea-29d2-adeccb5a7ffc
|
|
# ╟─2fcaef88-e8ca-11ea-23f7-29c48580f43c
|
|
# ╟─7636c4b0-e8d1-11ea-2051-757a850a9d30
|
|
# ╟─bca22176-e8ca-11ea-2004-ebeb103116b5
|
|
# ╟─0ad91f1e-e8d2-11ea-2c18-93f66c906a8b
|
|
# ╠═de373816-ec79-11ea-2772-ebdca52246ac
|
|
# ╠═552129ae-ebca-11ea-1fa1-3f9fa00a2601
|
|
# ╠═54c1ba3c-e8d2-11ea-3564-bdaca8563738
|
|
# ╠═6e0fefb6-e8d4-11ea-1f9b-e7a3db40df39
|
|
# ╠═9c359212-ec79-11ea-2d7e-0124dad5f127
|
|
# ╠═7703b032-ebca-11ea-3074-0b80a077078e
|
|
# ╠═7eff3522-ebca-11ea-1a65-59e66a4e72ab
|
|
# ╠═c9cd6c04-ebca-11ea-0990-5fa19ff7ed97
|
|
# ╟─0d873d9c-e93b-11ea-2425-1bd79677fb97
|
|
# ╠═6b09354a-ebb9-11ea-2d5a-3b75c5ae7aa9
|
|
# ╟─2d6c434e-e93b-11ea-2678-3b9db4975089
|
|
# ╠═2b14e93e-e93b-11ea-25f1-5f565f80e778
|
|
# ╟─0bdc6058-e8d5-11ea-1889-3f706cea7a1f
|
|
# ╠═e61db924-ebca-11ea-2f79-f9f1c121b7f5
|
|
# ╠═ef60fcc4-ebca-11ea-3f69-155afffe8ea8
|
|
# ╠═fac550ec-ebca-11ea-337a-dbc16848c617
|
|
# ╟─42aa8cfe-e8d5-11ea-3cb9-c365b98e7a8c
|
|
# ╠═4eea5710-e8d5-11ea-3978-af66ee2a137e
|
|
# ╟─57b3a0c2-e8d5-11ea-15aa-8da4549f849b
|
|
# ╠═03a7c0fc-ebba-11ea-1c71-79d750c97b16
|
|
# ╟─e6fd68fa-e8d8-11ea-3dc4-274caceda222
|
|
# ╠═63a1d282-e8d5-11ea-0bba-b9cdd32a218b
|
|
# ╟─fc5e1af0-e8d8-11ea-1077-07216ff96d29
|
|
# ╟─c79dd836-e8e8-11ea-029d-57be9899979a
|
|
# ╠═ae260168-e932-11ea-38fd-4f2c6f43e21c
|
|
# ╠═47d1bc04-ebcb-11ea-3643-d1ba8dea57c8
|
|
# ╠═72400458-ebcb-11ea-26b6-678ae1de8e23
|
|
# ╟─f57ea7c2-e932-11ea-0d52-4112187bcb38
|
|
# ╠═740ed2e2-e933-11ea-236c-f3c3f09d0f8b
|
|
# ╟─6128a5ba-e93b-11ea-03f5-f170c7b90b25
|
|
# ╠═78eafe4e-e933-11ea-3539-c13feb894ef6
|
|
# ╟─bf3f9050-e933-11ea-0df7-e5dcff6bb3ee
|
|
# ╟─212e1f12-e934-11ea-2f35-51c7a6c8dff1
|
|
# ╠═117a98c0-e936-11ea-3aac-8f66337cea68
|
|
# ╟─8004d076-e93b-11ea-29cc-a1bfcc75e87f
|
|
# ╠═3ac63296-e936-11ea-2144-f94bdbd60eaf
|
|
# ╠═3e3f841a-e936-11ea-0a81-1b95fe0faa83
|
|
# ╟─5978db50-e936-11ea-3145-059a51be2281
|
|
# ╠═21638b14-ebcc-11ea-1761-bbd2f4306a96
|
|
# ╟─70cb0e36-e936-11ea-3ade-49fde77cb696
|
|
# ╠═b3ea975e-e936-11ea-067d-81339575a3cb
|
|
# ╟─918a0762-e93b-11ea-1115-71dbfdb03f27
|
|
# ╠═daabe66c-e937-11ea-3bc3-d77f2bce406c
|
|
# ╟─095ced62-e938-11ea-1169-939dc7136fd0
|
|
# ╠═31f3605a-e938-11ea-3a6d-29a185bbee31
|
|
# ╠═2744a556-e94f-11ea-2434-d53c24e59285
|
|
# ╟─98412a36-e93b-11ea-1954-f1c105c6ed4a
|
|
# ╠═3c32efde-e938-11ea-1ae4-5d88290f5311
|
|
# ╟─4b26e4e6-e938-11ea-2635-6d4fc15e13b7
|
|
# ╠═41fa85c0-e939-11ea-1ad8-79805a2083bb
|
|
# ╟─c12e0928-e93b-11ea-0922-2b590a99ee89
|
|
# ╟─ff5dc538-e938-11ea-058f-693d6b016640
|
|
# ╠═fbe11200-e938-11ea-12e9-6125c1b56b25
|
|
# ╟─fa24f4a8-e93b-11ea-06bd-25c9672166d6
|
|
# ╠═15ce202e-e939-11ea-2387-93be0ec4cf1f
|
|
# ╠═cd5721d0-ede6-11ea-0918-1992c69bccc6
|
|
# ╟─bf2167a4-e93d-11ea-03b2-cdd24b459ba9
|
|
# ╟─5e688928-e939-11ea-0e16-fbc80af390ab
|
|
# ╟─58184d88-e939-11ea-2fc8-73b3476ebe92
|
|
# ╟─2dd09f16-e93a-11ea-2cdc-13f558e3391d
|
|
# ╟─df1b7996-e93b-11ea-1a3a-81b4ec520679
|
|
# ╟─b8daeea0-ec79-11ea-34b5-3f13e8a56a42
|
|
# ╟─bf1bb2c8-ec79-11ea-0671-3ffb34828f3c
|
|
# ╟─69e3aa82-e93c-11ea-23fe-c1103d989cba
|
|
# ╟─739c3bb6-e93c-11ea-127b-efb6a8ab9379
|
|
# ╟─832ebd1a-e93c-11ea-1d18-d784f3184ebe
|