///|
/// Perceptual-style quality metrics for export verification.
pub(all) struct AnimationQuality {
compared_frames : Int
mean_error : Int
maximum_error : Int
differing_frames : Int
mean_psnr_milli : Int
} derive(Debug)
///|
pub fn AnimationQuality::compared_frames(self : AnimationQuality) -> Int {
self.compared_frames
}
///|
pub fn AnimationQuality::mean_error(self : AnimationQuality) -> Int {
self.mean_error
}
///|
pub fn AnimationQuality::maximum_error(self : AnimationQuality) -> Int {
self.maximum_error
}
///|
pub fn AnimationQuality::differing_frames(self : AnimationQuality) -> Int {
self.differing_frames
}
///|
pub fn AnimationQuality::mean_psnr(self : AnimationQuality) -> Int {
self.mean_psnr_milli
}
///|
/// Compare matching frame positions using existing deterministic metrics.
pub fn compare_animation_quality(
left : Animation,
right : Animation,
) -> AnimationQuality {
let count = if left.frame_count() < right.frame_count() {
left.frame_count()
} else {
right.frame_count()
}
let mut total_error = 0
let mut maximum = 0
let mut different = 0
let mut total_psnr = 0
for i in 0.. maximum {
maximum = metrics.maximum_error()
}
if metrics.differing_pixels() > 0 {
different += 1
}
total_psnr += metrics.psnr_milli()
}
AnimationQuality::{
compared_frames: count,
mean_error: if count == 0 {
0
} else {
total_error / count
},
maximum_error: maximum,
differing_frames: different,
mean_psnr_milli: if count == 0 {
0
} else {
total_psnr / count
},
}
}
///|
/// Compare decoded output against source animation shape and colors.
pub fn encoded_quality(
source : Animation,
encoded : Bytes,
) -> AnimationQuality? {
match decode_checked(encoded) {
None => None
Some(decoded) => Some(compare_animation_quality(source, decoded))
}
}
///|
/// Return true when every compared frame meets a mean error budget.
pub fn AnimationQuality::within_error(
self : AnimationQuality,
maximum_mean_error : Int,
) -> Bool {
self.compared_frames() > 0 && self.mean_error() <= maximum_mean_error
}
///|
/// Return a compact score where 1000 means exact frame equality.
pub fn AnimationQuality::score(self : AnimationQuality) -> Int {
if self.compared_frames() == 0 {
0
} else {
let score = 1000 - self.mean_error() * 1000 / 195075
if score < 0 {
0
} else {
score
}
}
}