Skip to content

Commit

Permalink
Merge pull request #406 from Ogeon/conversion_matrix
Browse files Browse the repository at this point in the history
Add conversion matrix and `Convert{Once}` traits
  • Loading branch information
Ogeon authored Aug 1, 2024
2 parents 7971660 + b907852 commit 0a69512
Show file tree
Hide file tree
Showing 13 changed files with 746 additions and 309 deletions.
23 changes: 20 additions & 3 deletions benchmarks/benches/cie.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::path::Path;
use codspeed_criterion_compat::{black_box, criterion_group, criterion_main, Criterion};
use palette::{
color_difference::{Ciede2000, DeltaE, ImprovedDeltaE},
convert::FromColorUnclamped,
convert::{Convert, FromColorUnclamped},
};
use palette::{Lab, Lch, Xyz, Yxy};

Expand All @@ -24,7 +24,9 @@ use data_color_mine::{load_data, ColorMine};

fn cie_conversion(c: &mut Criterion) {
let mut group = c.benchmark_group("Cie family");
let mut colormine: Vec<ColorMine<f32>> = load_data(Some(Path::new("../integration_tests/tests/convert/data_color_mine.csv")));
let mut colormine: Vec<ColorMine<f32>> = load_data(Some(Path::new(
"../integration_tests/tests/convert/data_color_mine.csv",
)));
colormine.truncate(colormine.len() - colormine.len() % 8);
assert_eq!(
colormine.len() % 8,
Expand Down Expand Up @@ -57,6 +59,8 @@ fn cie_conversion(c: &mut Criterion) {
.map(|x| Lch::from_color_unclamped(x.xyz))
.collect();

let rgb_to_xyz_matrix = Xyz::matrix_from_rgb();

group.bench_with_input("xyz to lab", &colormine, |b, colormine| {
b.iter(|| {
for c in colormine {
Expand Down Expand Up @@ -96,6 +100,17 @@ fn cie_conversion(c: &mut Criterion) {
})
},
);
group.bench_with_input(
"linsrgb to xyz - Matrix3",
&(&colormine, rgb_to_xyz_matrix),
|b, &(colormine, matrix)| {
b.iter(|| {
for c in colormine {
black_box(matrix.convert(c.linear_rgb));
}
})
},
);
group.bench_with_input("yxy to xyz", &colormine, |b, colormine| {
b.iter(|| {
for c in colormine {
Expand Down Expand Up @@ -123,7 +138,9 @@ fn cie_conversion(c: &mut Criterion) {

fn cie_delta_e(c: &mut Criterion) {
let mut group = c.benchmark_group("Cie delta E");
let colormine: Vec<ColorMine<f32>> = load_data(Some(Path::new("../integration_tests/tests/convert/data_color_mine.csv")));
let colormine: Vec<ColorMine<f32>> = load_data(Some(Path::new(
"../integration_tests/tests/convert/data_color_mine.csv",
)));

let lab: Vec<Lab> = colormine
.iter()
Expand Down
27 changes: 4 additions & 23 deletions benchmarks/benches/matrix.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,17 @@
use codspeed_criterion_compat::{black_box, criterion_group, criterion_main, Criterion};

use palette::encoding;
use palette::matrix::{
matrix_inverse, multiply_3x3, multiply_rgb_to_xyz, multiply_xyz, multiply_xyz_to_rgb,
rgb_to_xyz_matrix,
};
use palette::white_point::{WhitePoint, D65};
use palette::{LinSrgb, Xyz};
use palette::matrix::{matrix_inverse, multiply_3x3, rgb_to_xyz_matrix};

fn matrix(c: &mut Criterion) {
let mut group = c.benchmark_group("Matrix functions");

let inp1 = [0.1, 0.2, 0.3, 0.3, 0.2, 0.1, 0.2, 0.1, 0.3];
let inp2 = Xyz::new(0.4, 0.6, 0.8);
let inp3 = [1.0f32, 2.0, 3.0, 3.0, 2.0, 1.0, 2.0, 1.0, 3.0];
let inp4 = [4.0, 5.0, 6.0, 6.0, 5.0, 4.0, 4.0, 6.0, 5.0];
let inp1 = [1.0f32, 2.0, 3.0, 3.0, 2.0, 1.0, 2.0, 1.0, 3.0];
let inp2 = [4.0, 5.0, 6.0, 6.0, 5.0, 4.0, 4.0, 6.0, 5.0];
let inverse: [f32; 9] = [3.0, 0.0, 2.0, 2.0, 0.0, -2.0, 0.0, 1.0, 1.0];
let color = LinSrgb::new(0.2f32, 0.8, 0.4);
let mat3 = rgb_to_xyz_matrix::<encoding::Srgb, f32>();
let wp: Xyz<D65, f32> = D65::get_xyz().with_white_point();

group.bench_function("multiply_xyz", |b| {
b.iter(|| multiply_xyz::<_>(black_box(inp1), black_box(inp2)))
});
group.bench_function("multiply_xyz_to_rgb", |b| {
b.iter(|| multiply_xyz_to_rgb::<encoding::Srgb, _, _>(black_box(inp1), black_box(wp)))
});
group.bench_function("multiply_rgb_to_xyz", |b| {
b.iter(|| multiply_rgb_to_xyz(black_box(mat3), black_box(color)))
});
group.bench_function("multiply_3x3", |b| {
b.iter(|| multiply_3x3(black_box(inp3), black_box(inp4)))
b.iter(|| multiply_3x3(black_box(inp1), black_box(inp2)))
});
group.bench_with_input("matrix_inverse", &inverse, |b, inverse| {
b.iter(|| matrix_inverse(*inverse))
Expand Down
46 changes: 43 additions & 3 deletions benchmarks/benches/rgb.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use std::path::Path;

use codspeed_criterion_compat::{black_box, criterion_group, criterion_main, Criterion};
use palette::convert::FromColorUnclamped;
use palette::encoding;
use palette::{
convert::{Convert, FromColorUnclamped},
white_point::D65,
Xyz,
};
use palette::{encoding, lms::BradfordLms};
use palette::{Hsl, Hsv, Hwb, IntoColor, LinSrgb, Srgb};

type SrgbHsv = Hsv<encoding::Srgb>;
Expand Down Expand Up @@ -41,7 +45,9 @@ use data_color_mine::{load_data, ColorMine};

fn rgb_conversion(c: &mut Criterion) {
let mut group = c.benchmark_group("Rgb family");
let mut colormine: Vec<ColorMine<f32>> = load_data(Some(Path::new("../integration_tests/tests/convert/data_color_mine.csv")));
let mut colormine: Vec<ColorMine<f32>> = load_data(Some(Path::new(
"../integration_tests/tests/convert/data_color_mine.csv",
)));
colormine.truncate(colormine.len() - colormine.len() % 8);
assert_eq!(
colormine.len() % 8,
Expand Down Expand Up @@ -74,6 +80,11 @@ fn rgb_conversion(c: &mut Criterion) {
let linear_hsv: Vec<LinHsv> = colormine.iter().map(|x| x.hsv.into_color()).collect();
let linear_hsl: Vec<LinHsl> = colormine.iter().map(|x| x.hsl.into_color()).collect();
let linear_hwb: Vec<LinHwb> = colormine.iter().map(|x| x.hwb.into_color()).collect();
let bradford_lms: Vec<BradfordLms<D65, _>> =
colormine.iter().map(|x| x.xyz.into_color()).collect();

let xyz_to_rgb_matrix = LinSrgb::matrix_from_xyz();
let lms_to_rgb_matrix = Xyz::matrix_from_lms().then(LinSrgb::matrix_from_xyz());

group.bench_with_input("rgb to linsrgb", &colormine, |b, colormine| {
b.iter(|| {
Expand Down Expand Up @@ -175,6 +186,35 @@ fn rgb_conversion(c: &mut Criterion) {
})
},
);
group.bench_with_input(
"xyz to linsrgb - Matrix3",
&(&colormine, xyz_to_rgb_matrix),
|b, &(colormine, matrix)| {
b.iter(|| {
for c in colormine {
black_box(matrix.convert(c.xyz));
}
})
},
);
group.bench_with_input("lms to linsrgb", &bradford_lms, |b, bradford_lms| {
b.iter(|| {
for &c in bradford_lms {
black_box(LinSrgb::from_color_unclamped(c));
}
})
});
group.bench_with_input(
"lms to linsrgb - Matrix3",
&(&bradford_lms, lms_to_rgb_matrix),
|b, &(bradford_lms, matrix)| {
b.iter(|| {
for &c in bradford_lms {
black_box(matrix.convert(c));
}
})
},
);
group.bench_with_input("hsl to rgb", &colormine, |b, colormine| {
b.iter(|| {
for c in colormine {
Expand Down
88 changes: 10 additions & 78 deletions palette/src/cam16/full.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use crate::{
angle::RealAngle,
bool_mask::{HasBoolMask, LazySelect},
bool_mask::HasBoolMask,
convert::Convert,
hues::Cam16Hue,
num::{Abs, Arithmetics, FromScalar, PartialCmp, Powf, Real, Signum, Sqrt, Trigonometry, Zero},
num::{FromScalar, Zero},
Alpha, GetHue, Xyz,
};

use super::{
BakedParameters, Cam16FromUnclamped, Cam16IntoUnclamped, Cam16Jch, Cam16Jmh, Cam16Jsh,
Cam16Qch, Cam16Qmh, Cam16Qsh, FromCam16Unclamped, IntoCam16Unclamped, WhitePointParameter,
BakedParameters, Cam16FromUnclamped, Cam16IntoUnclamped, IntoCam16Unclamped,
WhitePointParameter,
};

/// CIE CAM16 with an alpha component.
Expand Down Expand Up @@ -353,87 +353,19 @@ impl<T, A> Alpha<Cam16<T>, A> {
}
}

impl<WpParam, T> Cam16FromUnclamped<WpParam, Xyz<WpParam::StaticWp, T>> for Cam16<T>
impl<WpParam, T, C> Cam16FromUnclamped<WpParam, C> for Cam16<T>
where
T: FromScalar,
WpParam: WhitePointParameter<T::Scalar>,
T: Real
+ FromScalar
+ Arithmetics
+ Powf
+ Sqrt
+ Abs
+ Signum
+ Trigonometry
+ RealAngle
+ Clone,
T::Scalar: Clone,
BakedParameters<WpParam, T::Scalar>: Convert<C, Self>,
{
type Scalar = T::Scalar;

fn cam16_from_unclamped(
color: Xyz<WpParam::StaticWp, T>,
parameters: BakedParameters<WpParam, Self::Scalar>,
) -> Self {
super::math::xyz_to_cam16(color.with_white_point(), parameters.inner)
fn cam16_from_unclamped(color: C, parameters: BakedParameters<WpParam, Self::Scalar>) -> Self {
parameters.convert(color)
}
}

macro_rules! impl_from_cam16_partial {
($($name: ident),+) => {
$(
impl<WpParam, T> Cam16FromUnclamped<WpParam, $name<T>> for Cam16<T>
where
WpParam: WhitePointParameter<T>,
T: Real + FromScalar + Zero + Arithmetics + Sqrt + PartialCmp + Clone,
T::Mask: LazySelect<T> + Clone,
T::Scalar: Clone
{
type Scalar = T::Scalar;

fn cam16_from_unclamped(
cam16: $name<T>,
parameters: crate::cam16::BakedParameters<WpParam, Self::Scalar>,
) -> Self {
let (
luminance,
chromaticity,
hue,
) = cam16.into_dynamic();

let (lightness, brightness) = luminance.into_cam16(parameters.clone());
let (chroma, colorfulness, saturation) =
chromaticity.into_cam16(lightness.clone(), parameters);

Cam16 {
lightness,
chroma,
hue,
brightness,
colorfulness,
saturation,
}
}
}

impl<WpParam, T> FromCam16Unclamped<WpParam, $name<T>> for Cam16<T>
where
Self: Cam16FromUnclamped<WpParam, $name<T>>,
{
type Scalar = <Self as Cam16FromUnclamped<WpParam, $name<T>>>::Scalar;

fn from_cam16_unclamped(
cam16: $name<T>,
parameters: crate::cam16::BakedParameters<WpParam, Self::Scalar>,
) -> Self {
Self::cam16_from_unclamped(cam16, parameters)
}
}
)+
};
}

impl_from_cam16_partial!(Cam16Jmh, Cam16Jch, Cam16Jsh, Cam16Qmh, Cam16Qch, Cam16Qsh);

impl<T> GetHue for Cam16<T>
where
T: Clone,
Expand Down
Loading

0 comments on commit 0a69512

Please sign in to comment.