use crate::image::Image;
pub fn mse<const CHANNELS: usize>(
image1: &Image<f32, CHANNELS>,
image2: &Image<f32, CHANNELS>,
) -> f32 {
assert_eq!(image1.size(), image2.size());
let diff = &image1.data - &image2.data;
diff.mapv(|x| x.powi(2)).sum() / (image1.data.len() as f32)
}
pub fn psnr<const CHANNELS: usize>(
image1: &Image<f32, CHANNELS>,
image2: &Image<f32, CHANNELS>,
max_value: f32,
) -> f32 {
assert_eq!(image1.size(), image2.size());
let mse = mse(image1, image2);
if mse == 0f32 {
return f32::INFINITY;
}
20f32 * (max_value / mse.sqrt().log10())
}
#[cfg(test)]
mod tests {
use crate::image::{Image, ImageSize};
use anyhow::Result;
#[test]
fn test_equal() -> Result<()> {
let image1 = Image::<_, 1>::new(
ImageSize {
width: 2,
height: 3,
},
vec![0f32, 1f32, 2f32, 3f32, 4f32, 5f32],
)?;
let image2 = Image::<_, 1>::new(
ImageSize {
width: 2,
height: 3,
},
vec![0f32, 1f32, 2f32, 3f32, 4f32, 5f32],
)?;
let mse = crate::metrics::mse(&image1, &image2);
assert_eq!(mse, 0f32);
Ok(())
}
#[test]
fn test_not_equal() -> Result<()> {
let image1 = Image::<_, 1>::new(
ImageSize {
width: 2,
height: 2,
},
vec![0f32, 1f32, 2f32, 3f32],
)?;
let image2 = Image::<_, 1>::new(
ImageSize {
width: 2,
height: 2,
},
vec![0f32, 3f32, 2f32, 3f32],
)?;
let mse = crate::metrics::mse(&image1, &image2);
assert_eq!(mse, 1.0);
Ok(())
}
#[test]
fn test_psnr() -> Result<()> {
let image1 = Image::<_, 3>::new(
ImageSize {
width: 1,
height: 2,
},
vec![0f32, 1f32, 2f32, 3f32, 4f32, 5f32],
)?;
let image2 = Image::<_, 3>::new(
ImageSize {
width: 1,
height: 2,
},
vec![1f32, 3f32, 2f32, 4f32, 5f32, 6f32],
)?;
let psnr = crate::metrics::psnr(&image1, &image2, 1.0);
assert_eq!(psnr, 320.15698);
Ok(())
}
}