diff options
Diffstat (limited to 'evc/src')
-rw-r--r-- | evc/src/bin/decode.rs | 41 | ||||
-rw-r--r-- | evc/src/bin/encode.rs | 4 | ||||
-rw-r--r-- | evc/src/block.rs | 40 | ||||
-rw-r--r-- | evc/src/codec/decode.rs | 8 | ||||
-rw-r--r-- | evc/src/codec/encode.rs | 44 | ||||
-rw-r--r-- | evc/src/debug.rs | 12 | ||||
-rw-r--r-- | evc/src/format/ser.rs | 23 | ||||
-rw-r--r-- | evc/src/helpers/vector.rs | 26 | ||||
-rw-r--r-- | evc/src/refsampler.rs | 43 | ||||
-rw-r--r-- | evc/src/view.rs | 31 |
10 files changed, 229 insertions, 43 deletions
diff --git a/evc/src/bin/decode.rs b/evc/src/bin/decode.rs index 36b1f80..9be1a16 100644 --- a/evc/src/bin/decode.rs +++ b/evc/src/bin/decode.rs @@ -4,9 +4,12 @@ use clap::Parser; use evc::{ block::Block, codec::decode::decode_block, - format::{header::Header, ser::Source}, + format::{ + header::Header, + ser::{map_scalar8, Source}, + }, frame::Frame, - helpers::pixel::Pixel, + helpers::{matrix::Mat2, pixel::Pixel, vector::Vec2}, view::View, }; use log::info; @@ -64,14 +67,32 @@ fn draw_debug(block: &Block, mut target: View<&mut Frame>) { } Block::Reference { translation } => { target.draw_box(Pixel::BLUE); - target - .frame - .draw_line(target.center(), target.center() + *translation, Pixel::RED) + target.frame.draw_line( + target.center().into(), + (target.center() + *translation).into(), + Pixel::RED, + ) + } + Block::AdvancedReference(r) => { + let mat = Mat2 { + a: map_scalar8(r.transform.a), + b: map_scalar8(r.transform.b), + c: map_scalar8(r.transform.c), + d: map_scalar8(r.transform.d), + }; + let translation = Vec2 { + x: map_scalar8(r.translation.x), + y: map_scalar8(r.translation.y), + }; + let tl = mat.transform(target.offset.into()) + translation; + let tr = mat.transform((target.offset + target.size.x_only()).into()) + translation; + let bl = mat.transform((target.offset + target.size.y_only()).into()) + translation; + let br = mat.transform((target.offset + target.size).into()) + translation; + target.frame.draw_line(tl, tr, Pixel::MAGENTA); + target.frame.draw_line(tr, br, Pixel::MAGENTA); + target.frame.draw_line(br, bl, Pixel::MAGENTA); + target.frame.draw_line(bl, tl, Pixel::MAGENTA); + target.draw_box(Pixel::CYAN); } - Block::AdvancedReference { - translation: _, - transform: _, - value_scale: _, - } => (), // TODO } } diff --git a/evc/src/bin/encode.rs b/evc/src/bin/encode.rs index e5ffa41..20da7b6 100644 --- a/evc/src/bin/encode.rs +++ b/evc/src/bin/encode.rs @@ -20,7 +20,7 @@ pub struct EncodeArgs { #[arg(short = 'H', long)] height: usize, - #[arg(short, long)] + #[arg(short, long, default_value = "advanced")] mode: EncodeMode, #[arg(short, long, default_value = "8")] @@ -41,7 +41,7 @@ fn main() -> anyhow::Result<()> { let config = EncodeConfig { mode: evc::codec::encode::EncodeMode::Advanced, - ref_thres: 50.0, + ref_thres: 500.0, max_diff_area: 10_000, min_block_size: 8, max_threads: args.jobs, diff --git a/evc/src/block.rs b/evc/src/block.rs index 0a7ace3..24691e8 100644 --- a/evc/src/block.rs +++ b/evc/src/block.rs @@ -10,14 +10,15 @@ use crate::{ pub enum Block { Literal(Vec<Pixel>), Split(Box<[Block; 2]>), - Reference { - translation: Vec2<isize>, - }, - AdvancedReference { - translation: Vec2<i8>, - transform: Mat2<i8>, - value_scale: i8, - }, + Reference { translation: Vec2<isize> }, + AdvancedReference(AdvancedReference), +} + +#[derive(Clone, Debug)] +pub struct AdvancedReference { + pub translation: Vec2<i8>, + pub transform: Mat2<i8>, + pub value_scale: i8, } impl Block { @@ -36,11 +37,11 @@ impl Block { sink.put(2u8)?; sink.put(Small(*translation))?; } - Block::AdvancedReference { + Block::AdvancedReference(AdvancedReference { translation, transform, value_scale, - } => { + }) => { sink.put(3u8)?; sink.put((*translation, *transform, *value_scale))?; } @@ -71,11 +72,11 @@ impl Block { 2 => Block::Reference { translation: source.get::<Small<Vec2<isize>>>()?.0, }, - 3 => Block::AdvancedReference { + 3 => Block::AdvancedReference(AdvancedReference { translation: source.get()?, transform: source.get()?, value_scale: source.get()?, - }, + }), x => bail!("corrupt block type ({})", x), }) } @@ -86,3 +87,18 @@ impl Block { matches!(self, Block::Literal(..)) } } + +impl Default for AdvancedReference { + fn default() -> Self { + Self { + translation: Vec2 { x: 0, y: 0 }, + transform: Mat2 { + a: 4, + b: 0, + c: 0, + d: 4, + }, + value_scale: 4, // so 1 + } + } +} diff --git a/evc/src/codec/decode.rs b/evc/src/codec/decode.rs index 2da320f..b7ab8c7 100644 --- a/evc/src/codec/decode.rs +++ b/evc/src/codec/decode.rs @@ -1,4 +1,4 @@ -use crate::{block::Block, frame::Frame, view::View}; +use crate::{block::Block, frame::Frame, refsampler::Sampler, view::View}; pub fn decode_block(block: &Block, mut target: View<&mut Frame>, prev: View<&Frame>) { match &block { @@ -10,10 +10,6 @@ pub fn decode_block(block: &Block, mut target: View<&mut Frame>, prev: View<&Fra decode_block(b, bt, bp); } Block::Reference { translation } => target.copy_from(&prev.offset(*translation)), - Block::AdvancedReference { - translation: _, - transform: _, - value_scale: _, - } => todo!(), + Block::AdvancedReference(r) => target.copy_from_sampler(&Sampler::from_refblock(prev, r)), } } diff --git a/evc/src/codec/encode.rs b/evc/src/codec/encode.rs index 5ce0b16..5ffee4b 100644 --- a/evc/src/codec/encode.rs +++ b/evc/src/codec/encode.rs @@ -1,10 +1,12 @@ use crate::{ - block::Block, + block::{AdvancedReference, Block}, frame::Frame, helpers::{pixel::Pixel, threading::both_par, vector::Vec2}, + refsampler::Sampler, view::View, }; use clap::ValueEnum; +use log::{debug, trace}; #[derive(Debug, Clone)] pub struct EncodeConfig { @@ -22,7 +24,6 @@ pub enum EncodeMode { Advanced, } - pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfig) -> Block { let (diff, refblock) = if view.area() > config.max_diff_area { ( @@ -47,7 +48,7 @@ pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfi for x in OFFSETS { for y in OFFSETS { let translation = Vec2 { x: *x, y: *y }; - let diff = View::diff(&view, &prev.offset(translation)); // / view.area() as f64; + let diff = View::diff(&view, &prev.offset(translation)); if diff < best_diff { best_translation = translation; best_diff = diff; @@ -62,7 +63,42 @@ pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfi ) } EncodeMode::Advanced => { - todo!() + let mut params = AdvancedReference::default(); + let sampler = Sampler::from_refblock(prev.clone(), ¶ms); + let mut diff = View::diff_sampler(&view, &sampler); + + loop { + pub fn pk<F: FnMut(&mut AdvancedReference) -> ()>( + view: &View<&Frame>, + prev: &View<&Frame>, + diff: &mut f64, + params: &mut AdvancedReference, + mut f: F, + ) { + let mut p = params.clone(); + f(&mut p); + let d = View::diff_sampler(view, &Sampler::from_refblock(prev.clone(), &p)); + trace!("best={diff} try={d}"); + if d < *diff { + *diff = d; + *params = p; + } + } + + let (mut d, mut p) = (diff, params.clone()); + pk(&view, &prev, &mut d, &mut p, |p| p.translation.x += 2); + pk(&view, &prev, &mut d, &mut p, |p| p.translation.x -= 2); + pk(&view, &prev, &mut d, &mut p, |p| p.translation.y += 2); + pk(&view, &prev, &mut d, &mut p, |p| p.translation.y -= 2); + debug!("{diff} -> {d}"); + + if d >= diff { + break (diff, Block::AdvancedReference(params)); + } + + diff = d; + params = p; + } } } }; diff --git a/evc/src/debug.rs b/evc/src/debug.rs index fb2b53d..06dd507 100644 --- a/evc/src/debug.rs +++ b/evc/src/debug.rs @@ -16,7 +16,7 @@ impl View<&mut Frame> { } impl Frame { - pub fn draw_line(&mut self, start: Vec2<isize>, end: Vec2<isize>, color: Pixel) { + pub fn draw_line(&mut self, start: Vec2<f32>, end: Vec2<f32>, color: Pixel) { let (sx, sy) = (start.x as f32, start.y as f32); let (ex, ey) = (end.x as f32, end.y as f32); let (dx, dy) = (ex - sx, ey - sy); @@ -43,4 +43,14 @@ impl Pixel { pub const RED: Pixel = Pixel { r: 255, g: 0, b: 0 }; pub const GREEN: Pixel = Pixel { r: 0, g: 255, b: 0 }; pub const BLUE: Pixel = Pixel { r: 0, g: 0, b: 255 }; + pub const MAGENTA: Pixel = Pixel { + r: 255, + g: 0, + b: 255, + }; + pub const CYAN: Pixel = Pixel { + r: 0, + g: 255, + b: 255, + }; } diff --git a/evc/src/format/ser.rs b/evc/src/format/ser.rs index 731a7a3..817cafe 100644 --- a/evc/src/format/ser.rs +++ b/evc/src/format/ser.rs @@ -246,6 +246,29 @@ impl Ser for Small<Vec2<isize>> { } } +pub fn map_scalar8(v: i8) -> f32 { + match v { + 0 => 0.0, + x if x > 0 => 2f32.powf((x as f32).abs() / 2.0 - 2.0), + x => -2f32.powf((-x as f32).abs() / 2.0 - 2.0), + } +} +// const SCALAR8: [f32; 256] = gen_scalar8_lookup(); +// const fn gen_scalar8_lookup() -> [f32; 256] { +// let mut a = [0.0; 256]; +// let mut i = 0usize; +// while i < 256 { +// a[i as usize] = if i == 0 { +// 0.0 +// } else { +// let x = i as i8 as f32; +// x.signum() * 2f32.powf(x.abs() / 2.0 - 2.0) +// }; +// i += 1; +// } +// a +// } + #[cfg(test)] mod test { use super::{Ser, Sink}; diff --git a/evc/src/helpers/vector.rs b/evc/src/helpers/vector.rs index 4daa849..12243e4 100644 --- a/evc/src/helpers/vector.rs +++ b/evc/src/helpers/vector.rs @@ -24,6 +24,32 @@ impl<T: std::ops::Div<Output = T> + Copy> Vec2<T> { } } +impl Vec2<isize> { + pub fn x_only(&self) -> Self { + Self { x: self.x, y: 0 } + } + pub fn y_only(&self) -> Self { + Self { x: self.x, y: 0 } + } +} + +impl Into<Vec2<f32>> for Vec2<isize> { + fn into(self) -> Vec2<f32> { + Vec2 { + x: self.x as f32, + y: self.y as f32, + } + } +} +impl From<(isize, isize)> for Vec2<f32> { + fn from((x, y): (isize, isize)) -> Self { + Vec2 { + x: x as f32, + y: y as f32, + } + } +} + impl<T: std::ops::Add> std::ops::Add for Vec2<T> { type Output = Vec2<T::Output>; #[inline] diff --git a/evc/src/refsampler.rs b/evc/src/refsampler.rs index b27ceae..ad02332 100644 --- a/evc/src/refsampler.rs +++ b/evc/src/refsampler.rs @@ -1,22 +1,49 @@ use crate::{ + block::AdvancedReference, + format::ser::map_scalar8, frame::Frame, helpers::{matrix::Mat2, pixel::Pixel, vector::Vec2}, + view::View, }; +#[derive(Debug, Clone)] pub struct Sampler<'a> { - frame: &'a Frame, + pub view: View<&'a Frame>, - translation: Vec2<f32>, - transform: Mat2<f32>, + pub translation: Vec2<f32>, + pub transform: Mat2<f32>, - value_scale: f32, + pub value_scale: f32, } -impl Sampler<'_> { +impl<'a> Sampler<'a> { #[inline] pub fn sample(&self, p: Vec2<f32>) -> Pixel { - self.frame - .sample(self.translation + self.transform.transform(p)) - .scale(self.value_scale) + self.view + .sample(self.translation + p) // self.transform.transform(p)) + // .scale(self.value_scale) + } + pub fn from_refblock( + view: View<&'a Frame>, + AdvancedReference { + translation, + transform, + value_scale, + }: &AdvancedReference, + ) -> Self { + Self { + transform: Mat2 { + a: map_scalar8(transform.a), + b: map_scalar8(transform.b), + c: map_scalar8(transform.c), + d: map_scalar8(transform.d), + }, + translation: Vec2 { + x: map_scalar8(translation.x), + y: map_scalar8(translation.y), + }, + value_scale: map_scalar8(*value_scale), + view, + } } } diff --git a/evc/src/view.rs b/evc/src/view.rs index 3843128..5868680 100644 --- a/evc/src/view.rs +++ b/evc/src/view.rs @@ -1,9 +1,11 @@ use crate::{ frame::Frame, helpers::{pixel::Pixel, vector::Vec2}, + refsampler::Sampler, }; use std::ops::{Index, IndexMut}; +#[derive(Debug, Clone)] pub struct View<T> { pub frame: T, pub offset: Vec2<isize>, @@ -140,6 +142,22 @@ impl<T: Index<Vec2<isize>, Output = Pixel>> View<&T> { } acc as f64 } + pub fn diff_sampler(va: &Self, vb: &Sampler<'_>) -> f64 { + assert_eq!(va.size, vb.view.size); + let mut acc = 0; + for x in 0..va.size.x { + for y in 0..va.size.y { + let a = va[(x, y)]; + let b = vb.sample(Vec2 { + x: x as f32, + y: y as f32, + }); + acc += Pixel::distance(a, b); + } + } + acc as f64 + } + pub fn pixels(&self) -> Vec<Pixel> { let mut v = vec![]; for x in 0..self.size.x { @@ -158,6 +176,14 @@ impl View<&mut Frame> { } } } + pub fn copy_from_sampler(&mut self, other: &Sampler) { + for x in 0..self.size.x { + for y in 0..self.size.y { + self[(x, y)] = other.sample((x, y).into()); + } + } + } + pub fn set_pixels(&mut self, pixels: &Vec<Pixel>) { for x in 0..self.size.x { for y in 0..self.size.y { @@ -166,6 +192,11 @@ impl View<&mut Frame> { } } } +impl View<&Frame> { + pub fn sample(&self, p: Vec2<f32>) -> Pixel { + self.frame.sample(p + self.offset.into()) + } +} impl<T: Index<Vec2<isize>, Output = Pixel>> Index<Vec2<isize>> for View<&T> { type Output = Pixel; |