#[derive(Clone, Copy, Default)]
pub struct Var {
sum: i64,
sum_sq: u64,
}
impl Var {
#[inline]
fn add(self, o: Var) -> Var {
Var {
sum: self.sum + o.sum,
sum_sq: self.sum_sq + o.sum_sq,
}
}
#[inline]
fn variance(self, log2_count: u32) -> i64 {
let mean_sq = ((self.sum * self.sum) as u64) >> log2_count;
let centred = self.sum_sq.saturating_sub(mean_sq);
(256u64.wrapping_mul(centred) >> log2_count) as i64
}
}
#[derive(Clone)]
pub struct VarTree {
level: [Vec<Var>; 4],
}
const LOG2_COUNT: [u32; 4] = [6, 8, 10, 12];
impl VarTree {
#[inline]
fn grid(level: usize) -> usize {
8 >> level
}
pub fn build(
src: &[u16],
s_stride: usize,
refp: Option<(&[u16], usize)>,
x0: usize,
y0: usize,
w: usize,
h: usize,
) -> VarTree {
let mut leaves = vec![Var::default(); 64]; for by in 0..8 {
for bx in 0..8 {
let (mut sum, mut sum_sq) = (0i64, 0u64);
for iy in 0..8 {
let sy = (y0 + by * 8 + iy).min(h - 1);
for ix in 0..8 {
let sx = (x0 + bx * 8 + ix).min(w - 1);
let s = src[sy * s_stride + sx] as i64;
let d = match refp {
Some((rp, rs)) => rp[sy * rs + sx] as i64,
None => 0,
};
let v = s - d;
sum += v;
sum_sq += (v * v) as u64;
}
}
leaves[by * 8 + bx] = Var { sum, sum_sq };
}
}
let mut level: [Vec<Var>; 4] = [leaves, Vec::new(), Vec::new(), Vec::new()];
for l in 1..4 {
let g = Self::grid(l);
let cg = Self::grid(l - 1);
let mut nodes = vec![Var::default(); g * g];
for r in 0..g {
for c in 0..g {
let (r2, c2) = (r * 2, c * 2);
let tl = level[l - 1][r2 * cg + c2];
let tr = level[l - 1][r2 * cg + c2 + 1];
let bl = level[l - 1][(r2 + 1) * cg + c2];
let br = level[l - 1][(r2 + 1) * cg + c2 + 1];
nodes[r * g + c] = tl.add(tr).add(bl).add(br);
}
}
level[l] = nodes;
}
VarTree { level }
}
#[inline]
pub fn variance(&self, level: usize, r: usize, c: usize) -> i64 {
self.level[level][r * Self::grid(level) + c].variance(LOG2_COUNT[level])
}
#[inline]
fn children(&self, level: usize, r: usize, c: usize) -> [Var; 4] {
let cl = level - 1;
let cg = Self::grid(cl);
let (r2, c2) = (r * 2, c * 2);
[
self.level[cl][r2 * cg + c2],
self.level[cl][r2 * cg + c2 + 1],
self.level[cl][(r2 + 1) * cg + c2],
self.level[cl][(r2 + 1) * cg + c2 + 1],
]
}
#[inline]
pub fn horz_variance(&self, level: usize, r: usize, c: usize) -> (i64, i64) {
let ch = self.children(level, r, c);
let lc = LOG2_COUNT[level] - 1; (ch[0].add(ch[1]).variance(lc), ch[2].add(ch[3]).variance(lc))
}
#[inline]
pub fn vert_variance(&self, level: usize, r: usize, c: usize) -> (i64, i64) {
let ch = self.children(level, r, c);
let lc = LOG2_COUNT[level] - 1;
(ch[0].add(ch[2]).variance(lc), ch[1].add(ch[3]).variance(lc))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn brute(src: &[u16], stride: usize, x0: usize, y0: usize, sz: usize) -> i64 {
let (mut sum, mut sum_sq, n) = (0i64, 0u64, (sz * sz) as u64);
for y in 0..sz {
for x in 0..sz {
let v = src[(y0 + y) * stride + x0 + x] as i64;
sum += v;
sum_sq += (v * v) as u64;
}
}
let log2 = n.trailing_zeros();
let mean_sq = ((sum * sum) as u64) >> log2;
(256u64.wrapping_mul(sum_sq.saturating_sub(mean_sq)) >> log2) as i64
}
#[test]
fn variance_matches_bruteforce_all_levels() {
let (w, h) = (64usize, 64usize);
let mut src = vec![0u16; w * h];
for y in 0..h {
for x in 0..w {
src[y * w + x] =
((x * 3 + y * 5) as u16 & 0xff) ^ (((x / 4 + y / 4) as u16 * 17) & 0x3f);
}
}
let vt = VarTree::build(&src, w, None, 0, 0, w, h);
for (level, sz) in [(3usize, 64usize), (2, 32), (1, 16), (0, 8)] {
let g = 8 >> level;
for r in 0..g {
for c in 0..g {
let got = vt.variance(level, r, c);
let want = brute(&src, w, c * sz, r * sz, sz);
assert_eq!(
got, want,
"variance mismatch level={} r={} c={}",
level, r, c
);
}
}
}
}
#[test]
fn residual_variance_is_zero_when_ref_equals_src() {
let (w, h) = (64usize, 64usize);
let mut src = vec![0u16; w * h];
for (i, p) in src.iter_mut().enumerate() {
*p = (i as u16 * 7) & 0xff;
}
let refp = src.clone();
let vt = VarTree::build(&src, w, Some((&refp, w)), 0, 0, w, h);
for level in 0..4 {
let g = 8 >> level;
for r in 0..g {
for c in 0..g {
assert_eq!(vt.variance(level, r, c), 0);
}
}
}
}
#[test]
fn edge_clamp_fills_full_sb() {
let (w, h) = (20usize, 12usize);
let mut src = vec![0u16; w * h];
for (i, p) in src.iter_mut().enumerate() {
*p = (i as u16) & 0xff;
}
let vt = VarTree::build(&src, w, None, 0, 0, w, h);
let v = vt.variance(0, 7, 7); assert_eq!(v, 0);
}
}