///|
/// Additional spatial statistics for crop, quality, and scene detection.
pub(all) struct SpatialStats {
center : Rgba
corners : Array[Rgba]
quadrant_luma : Array[Int]
opaque_bounds : GifRect?
variance_milli : Int
} derive(Debug)
///|
pub fn SpatialStats::center(self : SpatialStats) -> Rgba {
self.center
}
///|
pub fn SpatialStats::corners(self : SpatialStats) -> ArrayView[Rgba] {
self.corners[:]
}
///|
pub fn SpatialStats::quadrant_luma(self : SpatialStats) -> ArrayView[Int] {
self.quadrant_luma[:]
}
///|
pub fn SpatialStats::opaque_bounds(self : SpatialStats) -> GifRect? {
self.opaque_bounds
}
///|
pub fn SpatialStats::variance_milli(self : SpatialStats) -> Int {
self.variance_milli
}
///|
/// Calculate center, corner, quadrant, and luma variance in one scan.
pub fn Canvas::spatial_stats(self : Canvas) -> SpatialStats {
let center = if self.width == 0 || self.height == 0 {
rgba(0, 0, 0, 0)
} else {
self.pixels[self.width / 2 + self.height / 2 * self.width]
}
let corners : Array[Rgba] = []
if self.width > 0 && self.height > 0 {
corners.push(self.pixels[0])
corners.push(self.pixels[self.width - 1])
corners.push(self.pixels[(self.height - 1) * self.width])
corners.push(self.pixels[self.width * self.height - 1])
}
let totals = Array::make(4, 0)
let counts = Array::make(4, 0)
let mut total = 0
let mut total_squared = 0
for y in 0.. Int {
let stats = self.spatial_stats()
let values = stats.quadrant_luma()
let mut selected = 0
for i in 1.. values[selected] {
selected = i
}
}
selected
}
///|
/// Compare two images by structural statistics before running a full diff.
pub fn spatial_similarity(left : Canvas, right : Canvas) -> Int {
let a = left.spatial_stats()
let b = right.spatial_stats()
let mut difference = a.center().distance(b.center())
let left_quadrants = a.quadrant_luma()
let right_quadrants = b.quadrant_luma()
for i in 0..<4 {
difference += (left_quadrants[i] - right_quadrants[i]).abs()
}
let value = 1000 - difference * 1000 / 2000
if value < 0 {
0
} else {
value
}
}