From 3302928cb7b4e608e74eddba19241bccbfd0ecc3 Mon Sep 17 00:00:00 2001 From: saji Date: Wed, 31 Jul 2024 00:09:44 -0500 Subject: [PATCH] optimize palette L*A*B* conversion, revert HyAb HyAb makes the image look worse for higher contrast images. We can look into adding quality control knobs in the future. --- src/dither.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/dither.rs b/src/dither.rs index d4a17b6..d192cc3 100644 --- a/src/dither.rs +++ b/src/dither.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use tracing::instrument; use image::Rgb as imgRgb; -use palette::color_difference::Ciede2000; +use palette::color_difference::{Ciede2000, HyAb}; use palette::{cast::FromComponents, IntoColor, Lab, Srgb}; /// Palette used on the display; pixels can be one of these colors. @@ -133,13 +133,12 @@ pub trait Ditherer { /// Find the closest approximate palette color to the given sRGB value. /// This uses euclidian distance in linear space. -fn nearest_neighbor(input_color: Lab, palette: &[Srgb]) -> (u8, Lab) { +fn nearest_neighbor(input_color: Lab, palette: &[Lab]) -> (u8, Lab) { let (nearest, _, color_diff) = palette .iter() .enumerate() .map(|(idx, p_color)| { - let c: Lab = Lab::from_color(*p_color); - (idx, input_color.difference(c), input_color - c) + (idx, input_color.difference(*p_color), input_color - *p_color) }) .min_by(|(_, a, _), (_, b, _)| a.total_cmp(b)) .expect("Should always find a color"); @@ -150,12 +149,13 @@ pub struct NearestNeighbor(); impl Ditherer for NearestNeighbor { fn dither(&mut self, img: &RgbImage, output: &mut DitheredImage) { - // sRGB view into the given image. zero copy! let srgb = <&[Srgb]>::from_components(&**img); + let lab_palette: Vec = output.palette.iter().map(|c| Lab::from_color(*c)).collect(); + for (idx, pix) in output.buf.iter_mut().enumerate() { - let (n, _) = nearest_neighbor(srgb[idx].into_format().into_color(), &output.palette); + let (n, _) = nearest_neighbor(srgb[idx].into_format().into_color(), &lab_palette); *pix = n; } } @@ -267,13 +267,14 @@ impl<'a> Ditherer for ErrorDiffusion<'a> { for pix in srgb { temp_img.push(pix.into_format().into_color()); } + let lab_palette: Vec = output.palette.iter().map(|c| Lab::from_color(*c)).collect(); // TODO: rework this to make more sense. for y in 0..ysize { for x in 0..xsize { let index = coord_to_idx(x, y, xsize); let curr_pix = temp_img[index]; - let (nearest, err) = nearest_neighbor(curr_pix, &output.palette); + let (nearest, err) = nearest_neighbor(curr_pix, &lab_palette); // set the color in the output buffer. *output .buf