1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-05-23 10:50:18 +02:00

Bonus exercise for camera

This commit is contained in:
sakex 2023-08-03 04:42:18 +02:00
parent 449ac4d302
commit 360b43ef37
3 changed files with 88 additions and 1 deletions

View File

@ -44,5 +44,5 @@ We will reuse our different implementations. So do not erase them when going fro
3. Create an X-ray effect. This is done by mapping colors to their opposite, for instance `0<->255`, `100<->155`. Beware of illumination.
4. You can play with the function, for instance you can implement greyscale, or add random noise.
5. In the `setup` function create a dropdown (`<select>`) that will change which transformation to apply to the image.
6. Blur only the background. This can be done by figuring out only the pixels that didn't change between multiple frames.
6. (BONUS) Track moving objects. This can be done by figuring out only the pixels that didn't change between multiple frames. For instance, you could compute the standard deviation of the pixel and black out below a threshold.
While this can be achieved without touching Javascript, I recommend editing it.

View File

@ -82,4 +82,89 @@ pub fn edit_bitmap(
};
Ok(())
}
```
6. Track moving objects. This can be done by figuring out only the pixels that didn't change between multiple frames. For instance, you could compute the standard deviation of the pixel and black out below a threshold.
While this can be achieved without touching Javascript, I recommend editing it.
```rust
extern crate console_error_panic_hook;
use js_sys::Uint8ClampedArray;
use std::collections::VecDeque;
use tokio::sync::mpsc::{channel, Receiver, Sender};
use wasm_bindgen::{prelude::*, Clamped};
use wasm_bindgen_futures::spawn_local;
use web_sys::ImageData;
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
#[wasm_bindgen(js_namespace = console)]
pub fn log(s: &str);
}
#[wasm_bindgen]
pub struct FrameSender {
sdr: Sender<Uint8ClampedArray>,
}
#[wasm_bindgen]
impl FrameSender {
pub fn send(&self, data: Uint8ClampedArray) -> Result<(), JsValue> {
self.sdr.try_send(data).map_err(|e| e.to_string().into())
}
}
async fn frame_processor(
mut image_data: Receiver<Uint8ClampedArray>,
canvas_ctx: web_sys::CanvasRenderingContext2d,
) {
let mut deque: VecDeque<Vec<u8>> = VecDeque::new();
let mut current_data;
while let Some(image_data) = image_data.recv().await {
deque.push_back(image_data.to_vec());
if deque.len() < 10 {
continue;
}
let first = deque.pop_front().unwrap();
for (idx, v) in first.into_iter().enumerate() {
let pixels: Vec<f32> = deque
.iter()
.map(|image| image[idx] as f32)
.chain(Some(v as f32))
.collect();
let mean = pixels.iter().fold(0.0, |a, b| a + *b) / pixels.len() as f32;
let variance = pixels.iter().fold(0.0, |a, b| a + (b - mean).powi(2))
/ pixels.len() as f32;
if variance.sqrt() < 8.0 && idx % 4 != 3 {
image_data.set_index(idx as u32, 0);
}
}
current_data = image_data.to_vec();
canvas_ctx
.put_image_data(
&ImageData::new_with_u8_clamped_array(Clamped(&current_data), 400)
.unwrap(),
0.0,
0.0,
)
.unwrap();
}
}
#[wasm_bindgen]
pub fn setup(
canvas_ctx: web_sys::CanvasRenderingContext2d,
) -> Result<FrameSender, JsValue> {
console_error_panic_hook::set_once();
let (sdr, rcv) = channel(2);
let sender = FrameSender { sdr };
spawn_local(async move {
frame_processor(rcv, canvas_ctx).await;
});
Ok(sender)
}
```

View File

@ -25,6 +25,8 @@ features = [
'CssStyleDeclaration',
'Document',
'Element',
'ImageData',
'CanvasRenderingContext2d',
'HtmlSelectElement',
'HtmlElement',
'Node',