aboutsummaryrefslogtreecommitdiff
path: root/evc/src
diff options
context:
space:
mode:
Diffstat (limited to 'evc/src')
-rw-r--r--evc/src/bin/decode.rs41
-rw-r--r--evc/src/bin/encode.rs4
-rw-r--r--evc/src/block.rs40
-rw-r--r--evc/src/codec/decode.rs8
-rw-r--r--evc/src/codec/encode.rs44
-rw-r--r--evc/src/debug.rs12
-rw-r--r--evc/src/format/ser.rs23
-rw-r--r--evc/src/helpers/vector.rs26
-rw-r--r--evc/src/refsampler.rs43
-rw-r--r--evc/src/view.rs31
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(), &params);
+ 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;