| -rw-r--r-- | Cargo.lock | 13 | ||||
| -rw-r--r-- | Cargo.toml | 3 | ||||
| -rw-r--r-- | src/diffusion/riemerasma.rs | 4 | ||||
| -rw-r--r-- | src/dumb.rs | 51 | ||||
| -rw-r--r-- | src/lib.rs | 26 | ||||
| -rw-r--r-- | src/main.rs | 3 | ||||
| -rw-r--r-- | tests/test.rs | 5 |
7 files changed, 71 insertions, 34 deletions
@@ -130,18 +130,18 @@ checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "lower" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b2b73ad1a9f69f5e3b6ede21f28b2a5aead191ccb9e8b8156f766c73696c9" +checksum = "2fd0c6f0db6ca73f3b9fe78e6da8a879b9682974c2da089008309f7c2acc958d" dependencies = [ "lower-macros", ] [[package]] name = "lower-macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff64bae8cfa89c8871e4b07d27629aa000978b341b98ba5fc1a0a55e2a79a53" +checksum = "383823c24b2a094a6a9de418eba3b60bf8186b688e74e4a20ba5321dfae04fba" dependencies = [ "proc-macro2", "quote", @@ -250,7 +250,6 @@ dependencies = [ "fimg", "hinted", "lower", - "lower-macros", "mattr 0.0.3", "rand", ] @@ -263,9 +262,9 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "syn" -version = "2.0.96" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -12,8 +12,7 @@ fimg = { version = "0.4.43", git = "https://github.com/bend-n/fimg", default-fea "scale", ] } hinted = "0.0.2" -lower = "0.1.3" -lower-macros = "0.1.0" +lower = "0.1.4" mattr = "0.0.3" rand = "0.8.5" diff --git a/src/diffusion/riemerasma.rs b/src/diffusion/riemerasma.rs index 279acf5..0068cc0 100644 --- a/src/diffusion/riemerasma.rs +++ b/src/diffusion/riemerasma.rs @@ -40,7 +40,7 @@ impl<T, const N: usize> Ring<T, N> { } } -pub fn riemerasma(image: Image<&[f32], 4>, palette: &[[f32; 4]]) -> Image<Box<[f32]>, 4> { +pub fn riemerasma(image: Image<&[f32], 4>, palette: pal<'_, 4>) -> Image<Box<[f32]>, 4> { let mut image = Image::build(image.width(), image.height()).buf(image.buffer().to_vec().into_boxed_slice()); #[rustfmt::skip] @@ -71,7 +71,7 @@ pub fn riemerasma(image: Image<&[f32], 4>, palette: &[[f32; 4]]) -> Image<Box<[f &mut (i32, i32), &mut Ring<[f32; 4], 16>, &(), - &[[f32; 4]], + pal<4>, &mut Image<Box<[f32]>, 4>, ), ) { diff --git a/src/dumb.rs b/src/dumb.rs index da5e64d..8391042 100644 --- a/src/dumb.rs +++ b/src/dumb.rs @@ -1,4 +1,5 @@ use atools::prelude::*; +use lower::algebraic::math; pub trait Closest<const N: usize> { fn closest(&self, color: [f32; N]) -> (f32, [f32; N], u32); fn best(&self, color: [f32; N]) -> [f32; N] { @@ -10,42 +11,54 @@ pub trait Closest<const N: usize> { fn space(&self) -> f32; } +#[inline(always)] fn euclidean_distance<const N: usize>(f: [f32; N], with: [f32; N]) -> f32 { - f.asub(with) - .map(|x| std::intrinsics::fmul_algebraic(x, x)) - .sum() + math! { + f.asub(with) + .map(|x| x*x) + .into_iter() + .fold(0.0, |acc, x| acc + x) + } } -#[no_mangle] -fn closeer(x: [f32; 4], p: &[[f32; 4]]) -> [f32; 4] { - p.best(x) +#[inline(always)] +fn minwby<T: Copy, U: PartialOrd>(max: T, x: impl Iterator<Item = T>, extractor: fn(T) -> U) -> T { + x.fold(max, |acc, x| { + if extractor(acc) > extractor(x) { + x + } else { + acc + } + }) } -impl<const N: usize> Closest<N> for &[[f32; N]] { +impl<'a, const N: usize> Closest<N> for super::pal<'a, N> { /// o(nn) - #[inline] fn closest(&self, color: [f32; N]) -> (f32, [f32; N], u32) { - (0..) - .zip(*self) - .map(|(i, &x)| (euclidean_distance(x, color), x, i)) - .min_by(|x, y| x.0.total_cmp(&y.0)) - .unwrap() + minwby( + (f32::MAX, [0.0; N], 0), + (0..) + .zip(&**self) + .map(|(i, &x)| (euclidean_distance(x, color), x, i)), + |x| x.0, + ) } /// o(nn) + #[cold] fn space(&self) -> f32 { + math! { self.iter() .enumerate() .map(|(i, &x)| { - self.iter() + minwby(f32::MAX, self.iter() .enumerate() .filter(|&(j, _)| j != i) - .map(|(_, &y)| euclidean_distance(y, x)) - .min_by(|a, b| a.total_cmp(b)) - .unwrap() - .sqrt() + .map(|(_, &y)| euclidean_distance(y, x)), + std::convert::identity).sqrt() }) - .fold(0.0, |x, y| std::intrinsics::fadd_algebraic(x, y)) + .fold(0.0, |x, y| x + y) / self.len() as f32 + } } } @@ -21,13 +21,37 @@ iter_map_windows )] #![allow(non_camel_case_types)] -type pal<'palette, const N: usize> = &'palette [[f32; N]]; +#[derive(Copy, Clone)] +pub struct pal<'palette, const N: usize> { + inner: &'palette [[f32; N]], +} +impl<'a, const N: usize> From<&'a [[f32; N]]> for pal<'a, N> { + fn from(value: &'a [[f32; N]]) -> Self { + assert!(value.len() != 0); + assert!(value.len() < u32::MAX as usize); + pal { inner: value } + } +} +impl<'a, const N: usize> AsRef<[[f32; N]]> for pal<'a, N> { + fn as_ref(&self) -> &[[f32; N]] { + &*self + } +} +impl<'a, const N: usize> Deref for pal<'a, N> { + type Target = [[f32; N]]; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} type out<'palette, P> = IndexedImage<Box<[u32]>, P>; pub mod diffusion; pub mod ordered; pub mod dumb; +use std::ops::Deref; + use atools::prelude::*; use dumb::Closest; use fimg::{indexed::IndexedImage, Image}; diff --git a/src/main.rs b/src/main.rs index 73387d8..ea3c666 100644 --- a/src/main.rs +++ b/src/main.rs @@ -87,7 +87,8 @@ fn reemap() { let now = Instant::now(); let x = remapper::diffusion::sierra::sierra::<255, 4>( // fimg::Image::<&[u8], 4>::make::<256, 256>().as_ref(), - i, &pal, + i, + pal.into(), ) .to() .to_u8(); diff --git a/tests/test.rs b/tests/test.rs index 049fe05..1b6510c 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,15 +1,16 @@ use fimg::{indexed::IndexedImage, Image}; +use remapper::pal; fn test( k: &'static str, - f: for<'a> fn(Image<&[f32], 4>, &'a [[f32; 4]]) -> IndexedImage<Box<[u32]>, &'a [[f32; 4]]>, + f: for<'a, 'b> fn(Image<&'b [f32], 4>, pal<'a, 4>) -> IndexedImage<Box<[u32]>, pal<'a, 4>>, ) { let pal = fimg::Image::<Box<[f32]>, 4>::from(fimg::Image::open("tdata/endesga.png").as_ref()); let pal = pal.flatten(); // let d = f(fimg::Image::open("tdata/small_cat.png").to_f32().as_ref(), &pal).to().to_u8().show(); let d = f( fimg::Image::open("tdata/small_cat.png").to_f32().as_ref(), - &pal, + pal.into(), ) .into_raw_parts() .0 |