mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-14 19:27:05 -04:00
Add rendered frame fidelity scoring
This commit is contained in:
3 files changed
+52
No files matched your search
@@ -0,0 +1,47 @@
|
||||
//! Deterministic rendered-frame comparison helpers for the fidelity corpus.
|
||||
|
||||
use effectcraft_raster::Image;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct FrameScore {
|
||||
pub compared_pixels: usize,
|
||||
pub mean_absolute_error: f64,
|
||||
pub max_error: f32,
|
||||
}
|
||||
|
||||
/// Compare two premultiplied rendered frames. A size mismatch is reported as an error instead of
|
||||
/// silently producing a misleading score.
|
||||
pub fn compare_frames(actual: &Image, reference: &Image) -> Result<FrameScore, String> {
|
||||
if actual.width != reference.width || actual.height != reference.height {
|
||||
return Err(format!("frame size mismatch: {}x{} vs {}x{}", actual.width, actual.height, reference.width, reference.height));
|
||||
}
|
||||
let mut sum = 0.0f64;
|
||||
let mut max = 0.0f32;
|
||||
for (a, b) in actual.data.iter().zip(&reference.data) {
|
||||
for (&x, &y) in a.iter().zip(b) {
|
||||
let error = (x - y).abs();
|
||||
sum += f64::from(error);
|
||||
max = max.max(error);
|
||||
}
|
||||
}
|
||||
let compared_pixels = actual.data.len();
|
||||
let samples = compared_pixels.saturating_mul(4).max(1);
|
||||
Ok(FrameScore { compared_pixels, mean_absolute_error: sum / samples as f64, max_error: max })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn reports_pixel_error_and_rejects_size_mismatch() {
|
||||
let mut actual = Image::filled(2, 1, [0.0, 0.0, 0.0, 1.0]);
|
||||
let reference = Image::filled(2, 1, [0.0, 0.0, 0.0, 1.0]);
|
||||
actual.data[1][0] = 0.5;
|
||||
let score = compare_frames(&actual, &reference).expect("same size");
|
||||
assert_eq!(score.compared_pixels, 2);
|
||||
assert!((score.mean_absolute_error - 0.0625).abs() < f64::EPSILON);
|
||||
assert_eq!(score.max_error, 0.5);
|
||||
assert!(compare_frames(&actual, &Image::new(1, 1)).is_err());
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ mod color2;
|
||||
mod color3;
|
||||
mod color_fx;
|
||||
pub mod controls;
|
||||
pub mod fidelity;
|
||||
mod distort;
|
||||
mod distort2;
|
||||
mod distort3;
|
||||
|
||||
@@ -52,6 +52,10 @@ the 168 live AE samples.
|
||||
|
||||
## Still unmeasured
|
||||
|
||||
Rendered frame comparisons now have a deterministic `effectcraft_effects::fidelity::compare_frames`
|
||||
helper. Corpus runners can use it with locally generated host/reference frames and fail on either a
|
||||
mean or maximum channel error without committing proprietary renders.
|
||||
|
||||
Mixed interpolation sides, non-unit durations, automatic/continuous Bezier, spatial speeds and paths,
|
||||
time remapping, expressions, actual rendered motion and other effects need separate corpus cases.
|
||||
The initial probe makes no claim about those features.
|
||||
Reference in new issue
Block a user