Compare commits
2 commits
b239c47e63
...
3302928cb7
Author | SHA1 | Date | |
---|---|---|---|
saji | 3302928cb7 | ||
saji | 25ac7d584b |
|
@ -1,15 +1,27 @@
|
||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||||
|
use image::{ImageReader, RgbImage};
|
||||||
fn fibonacci(n: u64) -> u64 {
|
use pi_frame_server::dither::{DitherMethod, DitheredImage, Palette};
|
||||||
match n {
|
|
||||||
0 => 1,
|
|
||||||
1 => 1,
|
|
||||||
n => fibonacci(n-1) + fibonacci(n-2),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn criterion_benchmark(c: &mut Criterion) {
|
fn criterion_benchmark(c: &mut Criterion) {
|
||||||
c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20))));
|
let sample_file = "sample_0.tiff";
|
||||||
|
let image: RgbImage = ImageReader::open(format!("samples/{sample_file}"))
|
||||||
|
.expect("file exists")
|
||||||
|
.decode()
|
||||||
|
.expect("file is valid")
|
||||||
|
.into_rgb8();
|
||||||
|
|
||||||
|
c.bench_with_input(BenchmarkId::new("dither", "sample_0"), &image, |b, i| {
|
||||||
|
b.iter(|| {
|
||||||
|
let mut method = DitherMethod::Atkinson.get_ditherer();
|
||||||
|
let mut result = DitheredImage::new(
|
||||||
|
image.width(),
|
||||||
|
image.height(),
|
||||||
|
Palette::Default.value().to_vec(),
|
||||||
|
);
|
||||||
|
|
||||||
|
method.dither(i, &mut result);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_group!(benches, criterion_benchmark);
|
criterion_group!(benches, criterion_benchmark);
|
||||||
|
|
|
@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use image::Rgb as imgRgb;
|
use image::Rgb as imgRgb;
|
||||||
use palette::color_difference::Ciede2000;
|
use palette::color_difference::{Ciede2000, HyAb};
|
||||||
use palette::{cast::FromComponents, IntoColor, Lab, Srgb};
|
use palette::{cast::FromComponents, IntoColor, Lab, Srgb};
|
||||||
|
|
||||||
/// Palette used on the display; pixels can be one of these colors.
|
/// 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.
|
/// Find the closest approximate palette color to the given sRGB value.
|
||||||
/// This uses euclidian distance in linear space.
|
/// 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
|
let (nearest, _, color_diff) = palette
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, p_color)| {
|
.map(|(idx, p_color)| {
|
||||||
let c: Lab = Lab::from_color(*p_color);
|
(idx, input_color.difference(*p_color), input_color - *p_color)
|
||||||
(idx, input_color.difference(c), input_color - c)
|
|
||||||
})
|
})
|
||||||
.min_by(|(_, a, _), (_, b, _)| a.total_cmp(b))
|
.min_by(|(_, a, _), (_, b, _)| a.total_cmp(b))
|
||||||
.expect("Should always find a color");
|
.expect("Should always find a color");
|
||||||
|
@ -150,12 +149,13 @@ pub struct NearestNeighbor();
|
||||||
|
|
||||||
impl Ditherer for NearestNeighbor {
|
impl Ditherer for NearestNeighbor {
|
||||||
fn dither(&mut self, img: &RgbImage, output: &mut DitheredImage) {
|
fn dither(&mut self, img: &RgbImage, output: &mut DitheredImage) {
|
||||||
|
|
||||||
// sRGB view into the given image. zero copy!
|
// sRGB view into the given image. zero copy!
|
||||||
let srgb = <&[Srgb<u8>]>::from_components(&**img);
|
let srgb = <&[Srgb<u8>]>::from_components(&**img);
|
||||||
|
|
||||||
|
let lab_palette: Vec<Lab> = output.palette.iter().map(|c| Lab::from_color(*c)).collect();
|
||||||
|
|
||||||
for (idx, pix) in output.buf.iter_mut().enumerate() {
|
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;
|
*pix = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,13 +267,14 @@ impl<'a> Ditherer for ErrorDiffusion<'a> {
|
||||||
for pix in srgb {
|
for pix in srgb {
|
||||||
temp_img.push(pix.into_format().into_color());
|
temp_img.push(pix.into_format().into_color());
|
||||||
}
|
}
|
||||||
|
let lab_palette: Vec<Lab> = output.palette.iter().map(|c| Lab::from_color(*c)).collect();
|
||||||
|
|
||||||
// TODO: rework this to make more sense.
|
// TODO: rework this to make more sense.
|
||||||
for y in 0..ysize {
|
for y in 0..ysize {
|
||||||
for x in 0..xsize {
|
for x in 0..xsize {
|
||||||
let index = coord_to_idx(x, y, xsize);
|
let index = coord_to_idx(x, y, xsize);
|
||||||
let curr_pix = temp_img[index];
|
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.
|
// set the color in the output buffer.
|
||||||
*output
|
*output
|
||||||
.buf
|
.buf
|
||||||
|
|
Loading…
Reference in a new issue