pub fn adaptation_matrix<T, I, O, M>(
input_wp: Option<Xyz<I, T>>,
output_wp: Option<Xyz<O, T>>,
) -> Matrix3<Xyz<I, T>, Xyz<O, T>>where
T: Zero + Arithmetics + Clone,
I: WhitePoint<T> + HasXyzMeta<XyzMeta = I>,
O: WhitePoint<T> + HasXyzMeta<XyzMeta = O>,
M: XyzToLms<T> + LmsToXyz<T>,
Xyz<I, T>: IntoColorUnclamped<Lms<WithLmsMatrix<I, M>, T>>,
Xyz<O, T>: IntoColorUnclamped<Lms<WithLmsMatrix<O, M>, T>>,Expand description
Construct a one-step chromatic adaptation matrix.
The matrix uses the von Kries method to fully adapt a color from an input
white point to an output white point, using a provided LMS matrix. See the
chromatic_adaptation module for more details.
§Static White Points
The input_wp and output_wp parameters represent the color “white” for
the input and output colors, respectively. Passing None will make it use
I and O to calculate the white points:
use palette::{
chromatic_adaptation::adaptation_matrix,
lms::matrix::Bradford,
convert::Convert,
white_point::{A, C},
Xyz,
};
use approx::assert_relative_eq;
// Adapts from white point A to white point C:
let matrix = adaptation_matrix::<f32, A, C, Bradford>(None, None);
// Explicit types added for illustration.
let input: Xyz<A> = Xyz::new(0.315756, 0.162732, 0.015905);
let output: Xyz<C> = matrix.convert(input);
let expected = Xyz::new(0.257963, 0.139776, 0.058825);
assert_relative_eq!(output, expected, epsilon = 0.0001);§Dynamic White Points
It’s also possible to use arbitrary colors as white points, as long as they are brighter than black. This can be useful for white balancing a photo, where we may want to use the same static white point for both the input and the output:
use palette::{
chromatic_adaptation::adaptation_matrix,
lms::matrix::Bradford,
convert::{FromColorUnclampedMut, Convert},
Srgb, Xyz,
};
use approx::assert_relative_eq;
fn simple_white_balance(image: &mut [Srgb<f32>]) {
// Temporarily convert to Xyz:
let mut image = <[Xyz<_, f32>]>::from_color_unclamped_mut(image);
// Find the average Xyz color:
let sum = image.iter().fold(Xyz::new(0.0, 0.0, 0.0), |sum, &c| sum + c);
let average = sum / image.len() as f32;
// Considering the average color to be "white", this matrix adapts from the
// average to default sRGB white, D65:
let matrix = adaptation_matrix::<_, _, _, Bradford>(Some(average), None);
for pixel in &mut *image {
*pixel = matrix.convert(*pixel);
}
}
// Minimal test case. This one pixel becomes gray after white balancing:
let mut image = [Srgb::new(0.8, 0.3, 0.9)];
simple_white_balance(&mut image);
let expected = Srgb::new(0.524706, 0.524706, 0.524706);
assert_relative_eq!(image[0], expected, epsilon = 0.00001);See also Wikipedia - Von Kries transform.