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.median(rust_image, blur_factor, blur_factor);
|
||||
module.spiegel(rust_image, blur_factor).then((pi) => {
|
||||
module.putImageData(canvas, ctx, pi);
|
||||
document.getElementById("msg").remove();
|
||||
});
|
||||
|
||||
module.spiegel(rust_image, blur_factor);
|
||||
module.putImageData(canvas, ctx, rust_image);
|
||||
const msg = document.getElementById("msg");
|
||||
if (msg) {
|
||||
msg.remove();
|
||||
}
|
||||
}
|
||||
|
||||
function setUpCanvas() {
|
||||
|
|
|
|||
30
webclient/Cargo.lock
generated
30
webclient/Cargo.lock
generated
|
|
@ -383,6 +383,7 @@ checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
|||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
|
|
@ -405,12 +406,34 @@ version = "0.3.30"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "futures-io"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.30"
|
||||
|
|
@ -429,11 +452,16 @@ version = "0.3.30"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1654,6 +1682,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"console_error_panic_hook",
|
||||
"futures",
|
||||
"hex",
|
||||
"image 0.24.9",
|
||||
"imageproc 0.23.0",
|
||||
|
|
@ -1661,7 +1690,6 @@ dependencies = [
|
|||
"photon-rs",
|
||||
"reqwest-wasm",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ anyhow = "1.0"
|
|||
photon-rs = { version = "0.3.2", default-features = false }
|
||||
console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||
wasm-bindgen = "0.2.78"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
# wasm-bindgen-futures = "0.4"
|
||||
reqwest-wasm = "0.11"
|
||||
futures = "0.3"
|
||||
|
||||
[lib]
|
||||
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::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 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);
|
||||
}
|
||||
|
||||
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]
|
||||
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 height = photon_image.get_height();
|
||||
|
||||
if width == 0 || height == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
let rs_image = RgbaImage::from_vec(width, height, raw_pixels).unwrap();
|
||||
|
||||
// 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);
|
||||
let mut filtered =
|
||||
imageproc::filter::median_filter(&rs_image, median_kernelsize, median_kernelsize);
|
||||
let out = block_on(apply_samples_to_image(&mut filtered));
|
||||
|
||||
println!("applying samples");
|
||||
let out = apply_samples_to_image(quantized).await.into_raw();
|
||||
|
||||
PhotonImage::new(out, width, height)
|
||||
*photon_image = PhotonImage::new(out.into_raw(), width, height);
|
||||
}
|
||||
|
||||
async fn apply_samples_to_image(mut src: RgbImage) -> RgbImage {
|
||||
let mut imgbuf = RgbImage::new(src.width(), src.height());
|
||||
async fn apply_samples_to_image(src: &mut RgbaImage) -> RgbaImage {
|
||||
log("applying");
|
||||
let mut imgbuf = RgbaImage::new(src.width(), src.height());
|
||||
unsafe {
|
||||
for y in 0..src.height() {
|
||||
for x in 0..src.width() {
|
||||
let pixel = &src.unsafe_get_pixel(x, y);
|
||||
if imgbuf.unsafe_get_pixel(x, y).channels() == [0, 0, 0] {
|
||||
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
|
||||
}
|
||||
|
||||
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]);
|
||||
log(&format!("get {}", rgb));
|
||||
|
||||
let bytes = reqwest_wasm::get(format!("/api/color/{}", rgb))
|
||||
.await?
|
||||
|
|
@ -100,7 +122,7 @@ async fn get_image(pixel: &Rgb<u8>) -> anyhow::Result<RgbImage, Error> {
|
|||
.with_guessed_format()
|
||||
.unwrap()
|
||||
.decode()?
|
||||
.as_rgb8()
|
||||
.as_rgba8()
|
||||
.unwrap()
|
||||
.clone())
|
||||
|
||||
|
|
@ -108,14 +130,14 @@ async fn get_image(pixel: &Rgb<u8>) -> anyhow::Result<RgbImage, Error> {
|
|||
}
|
||||
|
||||
fn fill(
|
||||
src: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
|
||||
sample: RgbImage,
|
||||
dest: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
|
||||
color: &Rgb<u8>,
|
||||
src: &mut RgbaImage,
|
||||
sample: RgbaImage,
|
||||
dest: &mut RgbaImage,
|
||||
color: &Rgba<u8>,
|
||||
px: u32,
|
||||
py: u32,
|
||||
) {
|
||||
if color.channels() == [0, 0, 0] {
|
||||
if color.channels() == [0, 0, 0, 0] {
|
||||
return;
|
||||
}
|
||||
let height = sample.height();
|
||||
|
|
@ -141,7 +163,7 @@ fn fill(
|
|||
yy -= height;
|
||||
}
|
||||
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 {
|
||||
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 p2 = p2.channels();
|
||||
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
|
||||
}
|
||||
|
||||
fn get_closest<'a>(
|
||||
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 {
|
||||
fn get_distance(r: u8, g: u8, b: u8, c2: &Rgba<u8>) -> f32 {
|
||||
let red_dif = r as f32 - c2.channels()[0] as f32;
|
||||
let green_dif = g as f32 - c2.channels()[1] 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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue