//! Calibration for [`wai::jpegai_pipeline::efn_filter`] — the EFE luma-aided adaptive //! nonlinear chroma post-filter. Runs on the reference fixture (luma `y`, input chroma //! `c_in`, the 8 Q15 tile weights, luma min/max) and compares the filtered plane to the //! reference output `c_want`. Float arithmetic ⇒ machine-precision match expected. //! //! env: WAI_JPEGAI_EFN_FIXTURE = efn_fixture.json //! { y:[f64], c_in:[f64], c_want:[f64], weights_q15:[i64], luma_min_q, luma_max_q } #![cfg(feature = "neural_int")] use wai::jpegai_pipeline::efn_filter; #[test] fn efn_filter_matches_reference() { let path = match std::env::var("WAI_JPEGAI_EFN_FIXTURE") { Ok(p) if std::path::Path::new(&p).exists() => p, _ => { eprintln!("skip: set WAI_JPEGAI_EFN_FIXTURE to efn_fixture.json"); return; } }; let v: serde_json::Value = serde_json::from_slice(&std::fs::read(&path).unwrap()).unwrap(); let f32v = |k: &str| v[k].as_array().unwrap().iter().map(|x| x.as_f64().unwrap() as f32).collect::>(); let y = f32v("y"); let c_in = f32v("c_in"); let c_want = f32v("c_want"); let weights: Vec = v["weights_q15"].as_array().unwrap().iter().map(|x| x.as_i64().unwrap()).collect(); let (lmin, lmax) = (v["luma_min_q"].as_i64().unwrap(), v["luma_max_q"].as_i64().unwrap()); let got = efn_filter(&y, &c_in, &weights, lmin, lmax); assert_eq!(got.len(), c_want.len(), "output size mismatch"); let mut maxd = 0f32; let mut mse = 0f64; for i in 0..got.len() { let d = (got[i] - c_want[i]).abs(); maxd = maxd.max(d); mse += (d as f64) * (d as f64); } mse /= got.len() as f64; let sig: f64 = c_want.iter().map(|&x| (x as f64) * (x as f64)).sum::() / got.len() as f64; let snr = if mse > 0.0 { 10.0 * (sig / mse).log10() } else { f64::INFINITY }; eprintln!("efn_filter vs reference: max|Δ| = {maxd:.6} SNR = {snr:.2} dB"); assert!(maxd < 1e-2, "EFN filter diverged from the reference (max|Δ| = {maxd})"); }