///|
/// Deterministic image-quality metrics for comparing two RGBA images.
///
/// `mse` and `psnr` compare all four stored channels (R, G, B and A) with
/// equal weight. `luma_mse` and `ssim` use the integer Rec.601 luma
/// `floor((299R + 587G + 114B) / 1000)` and ignore alpha. All metrics require
/// equal image dimensions and abort on malformed backing buffers. Empty,
/// equal-sized images are supported: MSE is zero and SSIM is one.
///|
/// Checks the shape and backing-buffer invariants shared by all metrics.
fn metric_pixel_count(a : Image, b : Image) -> Int {
if a.width != b.width || a.height != b.height {
abort("image metrics require equal dimensions")
}
let expected = checked_buffer_len(a.width, a.height)
if a.data.length() != expected || b.data.length() != expected {
abort("image metrics require valid RGBA backing buffers")
}
expected / 4
}
///|
/// Mean squared error over all RGBA channels. The result is in channel-value
/// squared units, in the range `[0, 65025]` for valid 8-bit images.
pub fn Image::mse(self : Image, other : Image) -> Double {
let n = metric_pixel_count(self, other)
if n == 0 {
return 0.0
}
let mut sum = 0L
for p in 0.. Double {
let error = self.mse(other)
if error == 0.0 {
return @double.infinity
}
10.0 * @math.log10(65025.0 / error)
}
///|
/// Mean squared error over Rec.601 luma only. Alpha is intentionally ignored.
pub fn Image::luma_mse(self : Image, other : Image) -> Double {
let n = metric_pixel_count(self, other)
if n == 0 {
return 0.0
}
let mut sum = 0L
for p in 0.. Double {
let n = metric_pixel_count(self, other)
if n == 0 {
return 1.0
}
let mut sum_a = 0L
let mut sum_b = 0L
let mut sum_aa = 0L
let mut sum_bb = 0L
let mut sum_ab = 0L
for p in 0.. 1.0 {
1.0
} else {
value
}
}