fixed some bugs
This commit is contained in:
parent
40ebe619f5
commit
fea1db9377
4 changed files with 106 additions and 68 deletions
|
|
@ -23,10 +23,13 @@ import("../../webclient/pkg").then((module) => {
|
||||||
|
|
||||||
// module.gaussian_blur(rust_image, blur_factor);
|
// module.gaussian_blur(rust_image, blur_factor);
|
||||||
// module.median(rust_image, blur_factor, blur_factor);
|
// module.median(rust_image, blur_factor, blur_factor);
|
||||||
module.spiegel(rust_image, blur_factor).then((pi) => {
|
|
||||||
module.putImageData(canvas, ctx, pi);
|
module.spiegel(rust_image, blur_factor);
|
||||||
document.getElementById("msg").remove();
|
module.putImageData(canvas, ctx, rust_image);
|
||||||
});
|
const msg = document.getElementById("msg");
|
||||||
|
if (msg) {
|
||||||
|
msg.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUpCanvas() {
|
function setUpCanvas() {
|
||||||
|
|
|
||||||
30
webclient/Cargo.lock
generated
30
webclient/Cargo.lock
generated
|
|
@ -383,6 +383,7 @@ checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
|
|
@ -405,12 +406,34 @@ version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.55",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
|
|
@ -429,11 +452,16 @@ version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"futures-macro",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
|
"memchr",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1654,6 +1682,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
|
"futures",
|
||||||
"hex",
|
"hex",
|
||||||
"image 0.24.9",
|
"image 0.24.9",
|
||||||
"imageproc 0.23.0",
|
"imageproc 0.23.0",
|
||||||
|
|
@ -1661,7 +1690,6 @@ dependencies = [
|
||||||
"photon-rs",
|
"photon-rs",
|
||||||
"reqwest-wasm",
|
"reqwest-wasm",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,9 @@ anyhow = "1.0"
|
||||||
photon-rs = { version = "0.3.2", default-features = false }
|
photon-rs = { version = "0.3.2", default-features = false }
|
||||||
console_error_panic_hook = { version = "0.1.7", optional = true }
|
console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||||
wasm-bindgen = "0.2.78"
|
wasm-bindgen = "0.2.78"
|
||||||
wasm-bindgen-futures = "0.4"
|
# wasm-bindgen-futures = "0.4"
|
||||||
reqwest-wasm = "0.11"
|
reqwest-wasm = "0.11"
|
||||||
|
futures = "0.3"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
|
use anyhow::Error;
|
||||||
|
use futures::executor::block_on;
|
||||||
|
use image::io::Reader as ImageReader;
|
||||||
|
use image::{GenericImageView, ImageBuffer, Pixel, Rgb, RgbImage, Rgba, RgbaImage};
|
||||||
|
use photon_rs::PhotonImage;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use anyhow::Error;
|
|
||||||
use image::io::Reader as ImageReader;
|
|
||||||
use image::{GenericImageView, ImageBuffer, Pixel, Rgb, RgbImage, RgbaImage};
|
|
||||||
use photon_rs::PhotonImage;
|
|
||||||
mod quantizer;
|
mod quantizer;
|
||||||
mod samples;
|
mod samples;
|
||||||
|
|
||||||
|
|
@ -34,51 +34,54 @@ pub fn median(photon_image: &mut PhotonImage, x_radius: u32, y_radius: u32) {
|
||||||
*photon_image = PhotonImage::new(filtered, width, height);
|
*photon_image = PhotonImage::new(filtered, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn determine_colors(image: &PhotonImage) -> HashSet<String> {
|
|
||||||
let mut unique_colors = HashSet::new();
|
|
||||||
let pixels = image.get_raw_pixels();
|
|
||||||
for pix in (0..pixels.len()).step_by(4) {
|
|
||||||
// assume rgba<u8>
|
|
||||||
let mut hex = String::new();
|
|
||||||
hex.push_str(&format!("{:X}", pixels[pix]));
|
|
||||||
hex.push_str(&format!("{:X}", pixels[pix + 1]));
|
|
||||||
hex.push_str(&format!("{:X}", pixels[pix + 2]));
|
|
||||||
|
|
||||||
unique_colors.insert(hex);
|
|
||||||
}
|
|
||||||
unique_colors
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub async fn spiegel(photon_image: PhotonImage, median_kernelsize: u32) -> PhotonImage {
|
pub fn spiegel(photon_image: &mut PhotonImage, median_kernelsize: u32) {
|
||||||
|
// let width = photon_image.get_width();
|
||||||
|
// let height = photon_image.get_height();
|
||||||
|
|
||||||
|
// let raw_pixels = photon_image.get_raw_pixels().to_vec(); //argh!, slice should work but doesn't
|
||||||
|
// let rs_image = RgbImage::from_vec(width, height, raw_pixels).unwrap();
|
||||||
|
|
||||||
|
// // // // println!("applying gaussian blur filter");
|
||||||
|
// // let gauss = imageproc::filter::gaussian_blur_f32(rs_image, 4.0);
|
||||||
|
// // // println!("applying median filter");
|
||||||
|
// let median = imageproc::filter::median_filter(&rs_image, median_kernelsize, median_kernelsize)
|
||||||
|
// .into_raw();
|
||||||
|
// // // println!("applying color quantization filter");
|
||||||
|
// // // let quantized = quantizer::quantize(&median, 256);
|
||||||
|
|
||||||
|
// // // println!("applying samples");
|
||||||
|
// // let out = block_on(apply_samples_to_image(&mut median));
|
||||||
|
|
||||||
|
// *photon_image = PhotonImage::new(median, width, height);
|
||||||
|
//
|
||||||
let width = photon_image.get_width();
|
let width = photon_image.get_width();
|
||||||
let height = photon_image.get_height();
|
let height = photon_image.get_height();
|
||||||
|
|
||||||
let raw_pixels = photon_image.get_raw_pixels().to_vec(); //argh!, slice should work but doesn't
|
if width == 0 || height == 0 {
|
||||||
let rs_image = RgbImage::from_vec(width, height, raw_pixels).unwrap();
|
return;
|
||||||
|
|
||||||
// println!("applying gaussian blur filter");
|
|
||||||
// let gauss = imageproc::filter::gaussian_blur_f32(&src, 4.0);
|
|
||||||
println!("applying median filter");
|
|
||||||
let median = imageproc::filter::median_filter(&rs_image, median_kernelsize, median_kernelsize);
|
|
||||||
println!("applying color quantization filter");
|
|
||||||
let quantized = quantizer::quantize(&median, 256);
|
|
||||||
|
|
||||||
println!("applying samples");
|
|
||||||
let out = apply_samples_to_image(quantized).await.into_raw();
|
|
||||||
|
|
||||||
PhotonImage::new(out, width, height)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn apply_samples_to_image(mut src: RgbImage) -> RgbImage {
|
let raw_pixels = photon_image.get_raw_pixels().to_vec(); //argh!, slice should work but doesn't
|
||||||
let mut imgbuf = RgbImage::new(src.width(), src.height());
|
let rs_image = RgbaImage::from_vec(width, height, raw_pixels).unwrap();
|
||||||
|
|
||||||
|
let mut filtered =
|
||||||
|
imageproc::filter::median_filter(&rs_image, median_kernelsize, median_kernelsize);
|
||||||
|
let out = block_on(apply_samples_to_image(&mut filtered));
|
||||||
|
|
||||||
|
*photon_image = PhotonImage::new(out.into_raw(), width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn apply_samples_to_image(src: &mut RgbaImage) -> RgbaImage {
|
||||||
|
log("applying");
|
||||||
|
let mut imgbuf = RgbaImage::new(src.width(), src.height());
|
||||||
unsafe {
|
unsafe {
|
||||||
for y in 0..src.height() {
|
for y in 0..src.height() {
|
||||||
for x in 0..src.width() {
|
for x in 0..src.width() {
|
||||||
let pixel = &src.unsafe_get_pixel(x, y);
|
let pixel = &src.unsafe_get_pixel(x, y);
|
||||||
if imgbuf.unsafe_get_pixel(x, y).channels() == [0, 0, 0] {
|
if imgbuf.unsafe_get_pixel(x, y).channels() == [0, 0, 0] {
|
||||||
if let Ok(sample) = get_image(pixel).await {
|
if let Ok(sample) = get_image(pixel).await {
|
||||||
fill(&mut src, sample, &mut imgbuf, pixel, x, y);
|
fill(src, sample, &mut imgbuf, pixel, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -87,8 +90,27 @@ async fn apply_samples_to_image(mut src: RgbImage) -> RgbImage {
|
||||||
imgbuf
|
imgbuf
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_image(pixel: &Rgb<u8>) -> anyhow::Result<RgbImage, Error> {
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
// Use `js_namespace` here to bind `console.log(..)` instead of just
|
||||||
|
// `log(..)`
|
||||||
|
#[wasm_bindgen(js_namespace = console)]
|
||||||
|
fn log(s: &str);
|
||||||
|
|
||||||
|
// The `console.log` is quite polymorphic, so we can bind it with multiple
|
||||||
|
// signatures. Note that we need to use `js_name` to ensure we always call
|
||||||
|
// `log` in JS.
|
||||||
|
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||||
|
fn log_u32(a: u32);
|
||||||
|
|
||||||
|
// Multiple arguments too!
|
||||||
|
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||||
|
fn log_many(a: &str, b: &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_image(pixel: &Rgba<u8>) -> anyhow::Result<RgbaImage, Error> {
|
||||||
let rgb = format!("{:02X?}{:02X?}{:02X?}", pixel[0], pixel[1], pixel[2]);
|
let rgb = format!("{:02X?}{:02X?}{:02X?}", pixel[0], pixel[1], pixel[2]);
|
||||||
|
log(&format!("get {}", rgb));
|
||||||
|
|
||||||
let bytes = reqwest_wasm::get(format!("/api/color/{}", rgb))
|
let bytes = reqwest_wasm::get(format!("/api/color/{}", rgb))
|
||||||
.await?
|
.await?
|
||||||
|
|
@ -100,7 +122,7 @@ async fn get_image(pixel: &Rgb<u8>) -> anyhow::Result<RgbImage, Error> {
|
||||||
.with_guessed_format()
|
.with_guessed_format()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.decode()?
|
.decode()?
|
||||||
.as_rgb8()
|
.as_rgba8()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone())
|
.clone())
|
||||||
|
|
||||||
|
|
@ -108,14 +130,14 @@ async fn get_image(pixel: &Rgb<u8>) -> anyhow::Result<RgbImage, Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill(
|
fn fill(
|
||||||
src: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
|
src: &mut RgbaImage,
|
||||||
sample: RgbImage,
|
sample: RgbaImage,
|
||||||
dest: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
|
dest: &mut RgbaImage,
|
||||||
color: &Rgb<u8>,
|
color: &Rgba<u8>,
|
||||||
px: u32,
|
px: u32,
|
||||||
py: u32,
|
py: u32,
|
||||||
) {
|
) {
|
||||||
if color.channels() == [0, 0, 0] {
|
if color.channels() == [0, 0, 0, 0] {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let height = sample.height();
|
let height = sample.height();
|
||||||
|
|
@ -141,7 +163,7 @@ fn fill(
|
||||||
yy -= height;
|
yy -= height;
|
||||||
}
|
}
|
||||||
dest.put_pixel(x, y, *sample.get_pixel(xx, yy));
|
dest.put_pixel(x, y, *sample.get_pixel(xx, yy));
|
||||||
src.put_pixel(x, y, Rgb([0, 0, 0]));
|
src.put_pixel(x, y, Rgba([0, 0, 0, 0]));
|
||||||
if x > 1 {
|
if x > 1 {
|
||||||
points.push(Point::new(x - 1, y));
|
points.push(Point::new(x - 1, y));
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +185,7 @@ fn fill(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_same(p1: &Rgb<u8>, p2: &Rgb<u8>) -> bool {
|
fn is_same(p1: &Rgba<u8>, p2: &Rgba<u8>) -> bool {
|
||||||
let p1 = p1.channels();
|
let p1 = p1.channels();
|
||||||
let p2 = p2.channels();
|
let p2 = p2.channels();
|
||||||
i16::abs(p1[0] as i16 - p2[0] as i16) < 4
|
i16::abs(p1[0] as i16 - p2[0] as i16) < 4
|
||||||
|
|
@ -171,27 +193,11 @@ fn is_same(p1: &Rgb<u8>, p2: &Rgb<u8>) -> bool {
|
||||||
&& i16::abs(p1[2] as i16 - p2[2] as i16) < 4
|
&& i16::abs(p1[2] as i16 - p2[2] as i16) < 4
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_closest<'a>(
|
fn get_distance(r: u8, g: u8, b: u8, c2: &Rgba<u8>) -> f32 {
|
||||||
color_samples: &'a Vec<ColorSample>,
|
|
||||||
pixel: &Rgb<u8>,
|
|
||||||
) -> Option<&'a ColorSample> {
|
|
||||||
let mut closest = None;
|
|
||||||
let mut min_diff: f32 = 4294967295.0; //0xFFFFFFFF
|
|
||||||
for sample in color_samples {
|
|
||||||
let diff = get_distance(sample.r, sample.g, sample.b, pixel);
|
|
||||||
if diff < min_diff {
|
|
||||||
closest = Some(sample);
|
|
||||||
min_diff = diff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closest
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_distance(r: u8, g: u8, b: u8, c2: &Rgb<u8>) -> f32 {
|
|
||||||
let red_dif = r as f32 - c2.channels()[0] as f32;
|
let red_dif = r as f32 - c2.channels()[0] as f32;
|
||||||
let green_dif = g as f32 - c2.channels()[1] as f32;
|
let green_dif = g as f32 - c2.channels()[1] as f32;
|
||||||
let blue_dif = b as f32 - c2.channels()[2] as f32;
|
let blue_dif = b as f32 - c2.channels()[2] as f32;
|
||||||
|
// ignore alpha channel
|
||||||
return f32::sqrt(red_dif * red_dif + green_dif * green_dif + blue_dif * blue_dif);
|
return f32::sqrt(red_dif * red_dif + green_dif * green_dif + blue_dif * blue_dif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue