ff_filter/effects/
lens_profile.rs1#[derive(Debug, Clone, Copy, PartialEq)]
11pub enum LensProfile {
12 GoproHero9Wide,
14 GoproHero11Linear,
16 Iphone14ProMain,
18 DjiMini3ProWide,
20 Custom {
22 k1: f32,
24 k2: f32,
26 scale: f32,
29 },
30}
31
32impl LensProfile {
33 pub fn coefficients(&self) -> (f32, f32, f32) {
35 match self {
36 Self::GoproHero9Wide => (-0.21, 0.05, 1.05),
37 Self::GoproHero11Linear => (-0.04, 0.01, 1.01),
38 Self::Iphone14ProMain => (-0.03, 0.00, 1.01),
39 Self::DjiMini3ProWide => (-0.16, 0.03, 1.03),
40 Self::Custom { k1, k2, scale } => (*k1, *k2, *scale),
41 }
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn gopro_hero9_wide_should_have_expected_coefficients() {
51 let (k1, k2, scale) = LensProfile::GoproHero9Wide.coefficients();
52 assert!((k1 - (-0.21_f32)).abs() < f32::EPSILON);
53 assert!((k2 - 0.05_f32).abs() < f32::EPSILON);
54 assert!((scale - 1.05_f32).abs() < f32::EPSILON);
55 }
56
57 #[test]
58 fn iphone14_pro_main_should_have_expected_coefficients() {
59 let (k1, k2, scale) = LensProfile::Iphone14ProMain.coefficients();
60 assert!((k1 - (-0.03_f32)).abs() < f32::EPSILON);
61 assert!((k2 - 0.00_f32).abs() < f32::EPSILON);
62 assert!((scale - 1.01_f32).abs() < f32::EPSILON);
63 }
64
65 #[test]
66 fn custom_should_return_supplied_values() {
67 let (k1, k2, scale) = LensProfile::Custom {
68 k1: -0.1,
69 k2: 0.02,
70 scale: 1.02,
71 }
72 .coefficients();
73 assert!((k1 - (-0.1_f32)).abs() < f32::EPSILON);
74 assert!((k2 - 0.02_f32).abs() < f32::EPSILON);
75 assert!((scale - 1.02_f32).abs() < f32::EPSILON);
76 }
77
78 #[test]
79 fn custom_identity_should_return_zero_k1_k2_and_unit_scale() {
80 let (k1, k2, scale) = LensProfile::Custom {
81 k1: 0.0,
82 k2: 0.0,
83 scale: 1.0,
84 }
85 .coefficients();
86 assert!((k1 - 0.0_f32).abs() < f32::EPSILON);
87 assert!((k2 - 0.0_f32).abs() < f32::EPSILON);
88 assert!((scale - 1.0_f32).abs() < f32::EPSILON);
89 }
90}