diff --git a/.gitignore b/.gitignore index c575e89..78db5a8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,9 +9,10 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk -/img - +# images *.bmp +*.png +*.jpg # frave data format *.frv diff --git a/img/decomposition.gif b/img/decomposition.gif new file mode 100644 index 0000000..a52b4ac Binary files /dev/null and b/img/decomposition.gif differ diff --git a/src/commands.rs b/src/commands.rs index 6456f9d..1b29b2e 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -13,7 +13,7 @@ pub fn encode(path: PathBuf, var: Variant, output: String) { let mut enc = FractalImage::new_from_img(img.into_luma8(), var); enc.find_coef(); - // enc.quantizate(&get_quantization_matrix()); + enc.quantizate(&get_quantization_matrix()); let (coef, contexts) = enc.ans_encode(); let compressed = Frv::new(enc.height, enc.width, contexts, var, coef); let mut f = File::create(output).unwrap_or_else(|e| panic!("Failed to encode frv image: {e}")); @@ -27,7 +27,7 @@ pub fn decode(path: PathBuf, output: String) { let frv_img: Frv = bincode::deserialize_from(img).unwrap(); let mut dec = FractalImage::new_from_frv(&frv_img); dec.ans_decode(frv_img.data, frv_img.ans_contexts); - // dec.unquantizate(&get_quantization_matrix()); + dec.unquantizate(&get_quantization_matrix()); dec.find_val(); dec.image.save(output).unwrap_or_else(|e| { panic!("Failed to decode frv image: {e}"); diff --git a/src/compression/decoder.rs b/src/compression/decoder.rs index b69dbb3..ce7ce5d 100644 --- a/src/compression/decoder.rs +++ b/src/compression/decoder.rs @@ -1,12 +1,14 @@ use std::collections::HashMap; +use itertools::Itertools; use rans::b64_decoder::B64RansDecoderMulti; use rans::RansDecoderMulti; use crate::compression::ans::{self, AnsContext}; use crate::fractal::image::FractalImage; -use crate::utils::bitwise; -use crate::utils::coordinate::Coord; +use crate::utils::{self, Coord}; + +use super::encoder::Encoder; pub trait Decoder { /// Entropy decoding step of decoder procedure. @@ -35,7 +37,7 @@ impl Decoder for FractalImage { .iter() .enumerate() .map(|(i, coefficient)| { - let layer = bitwise::get_prev_power_two(i + 1).trailing_zeros(); + let layer = utils::get_prev_power_two(i + 1).trailing_zeros(); (*coefficient).map(|s| s * quantization_matrix[layer as usize]) }) .collect::>>(); @@ -66,16 +68,19 @@ impl Decoder for FractalImage { } fn ans_decode(&mut self, compressed_coef: Vec, ans_contexts: Vec) { - let mut coef = vec![]; - let depth = self.depth; + self.find_coef(); + let length = self.coef.iter().filter(|x| x.is_some()).count(); + let mut coef = self.coef.clone(); + let depth = utils::get_prev_power_two(length).trailing_zeros() + 1; let scale_bits = u32::try_from(depth - 1).unwrap(); let mut decoder: B64RansDecoderMulti<3> = B64RansDecoderMulti::new(compressed_coef); let ctxs = ans_contexts; let layers = vec![ - 0..(1 << (depth - 2)), - (1 << (depth - 2))..(1 << (depth - 1)), - (1 << (depth - 1))..(1 << depth), + 0..1 << (depth - 2), + 1 << (depth - 2)..1 << (depth - 1), + 1 << (depth - 1)..length, ]; + let mut last = 0; for (i, layer) in layers.iter().enumerate() { let mut cum_freqs = ans::cum_sum(&ctxs[2 - i].freq); let cum_freq_to_symbols = ans::freqs_to_dec_symbols(&cum_freqs, &ctxs[2 - i].freq); @@ -93,9 +98,15 @@ impl Decoder for FractalImage { let symbol = symbol_map[&cum_freq_decoded]; decoder.advance_step_at(i, &cum_freq_to_symbols[&cum_freq_decoded], scale_bits); decoder.renorm_at(i); - coef.push(Some(symbol)); + last = insert_after_none_starting_from(symbol, last, &mut coef); } } self.coef = coef; } } + +fn insert_after_none_starting_from(element: i32, i: usize, vec: &mut Vec>) -> usize { + let ind = (i..vec.len()).find(|j| vec[*j].is_some()).unwrap(); + vec[ind] = Some(element); + ind + 1 +} diff --git a/src/compression/encoder.rs b/src/compression/encoder.rs index 02a7ff9..e184583 100644 --- a/src/compression/encoder.rs +++ b/src/compression/encoder.rs @@ -7,8 +7,7 @@ use rans::RansEncoderMulti; use crate::compression::ans::{self, AnsContext}; use crate::fractal::image::FractalImage; -use crate::utils::bitwise; -use crate::utils::coordinate::Coord; +use crate::utils::{self, Coord}; fn try_apply(first: Option, second: Option, operation: fn(T, T) -> T) -> Option { match (first, second) { @@ -55,7 +54,7 @@ impl Encoder for FractalImage { ); self.coef[1] = try_apply(rt, lt, |r, l| (r - l) / 2); self.coef[0] = try_apply(rt, lt, |r, l| (r + l) / 2); - dbg!(self.coef.iter().filter(|x| x.is_some()).count()); + // dbg!(self.coef.iter().filter(|x| x.is_some()).count()); } fn fn_cf(&mut self, cn: Coord, ps: usize, dp: usize) -> Option { @@ -78,24 +77,24 @@ impl Encoder for FractalImage { .iter() .enumerate() .map(|(i, coefficient)| { - let layer = bitwise::get_prev_power_two(i + 1).trailing_zeros(); + let layer = utils::get_prev_power_two(i + 1).trailing_zeros(); (*coefficient).map(|s| s / quantization_matrix[layer as usize]) }) .collect::>>(); } fn ans_encode(&self) -> (Vec, Vec) { - dbg!(&self.coef); - let layer1 = &self.coef[1 << (self.depth - 1)..]; - let layer2 = &self.coef[1 << (self.depth - 2)..1 << (self.depth - 1)]; - let layer3 = &self.coef[..1 << (self.depth - 2)]; + let valid_coef = &self.coef.clone().into_iter().flatten().collect::>(); + let true_depth = utils::get_prev_power_two(valid_coef.len()).trailing_zeros() + 1; + let layer1 = &valid_coef[1 << (true_depth - 1)..]; + let layer2 = &valid_coef[1 << (true_depth - 2)..1 << (true_depth - 1)]; + let layer3 = &valid_coef[..1 << (true_depth - 2)]; - let mut encoder: B64RansEncoderMulti<3> = B64RansEncoderMulti::new(1 << self.depth); + let mut encoder: B64RansEncoderMulti<3> = B64RansEncoderMulti::new(valid_coef.len()); let mut contexts: Vec = vec![]; for (i, layer) in [layer1, layer2, layer3].into_iter().enumerate() { - let some_layer = layer.iter().flatten(); - let counter = some_layer.clone().counts(); + let counter = layer.clone().into_iter().counts(); let freq = counter .values() .map(|e| u32::try_from(*e).unwrap()) @@ -103,7 +102,7 @@ impl Encoder for FractalImage { let symbols = counter.keys().map(|e| **e).collect::>(); let cdf = ans::cum_sum(&freq); - let symbol_map = ans::freqs_to_enc_symbols(&cdf, &freq, self.depth); + let symbol_map = ans::freqs_to_enc_symbols(&cdf, &freq, true_depth as usize); let cdf_map = counter .clone() @@ -111,7 +110,8 @@ impl Encoder for FractalImage { .zip(cdf.clone()) .collect::>(); - some_layer + layer + .iter() .rev() .for_each(|s| encoder.put_at(i, &symbol_map[&cdf_map[s]])); diff --git a/src/fractal/image.rs b/src/fractal/image.rs index a6b637c..5632539 100644 --- a/src/fractal/image.rs +++ b/src/fractal/image.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::compression::ans::AnsContext; use crate::fractal::variants::Variant; -use crate::utils::coordinate::Coord; +use crate::utils::Coord; #[derive(Serialize, Deserialize)] pub struct Frv { @@ -99,7 +99,7 @@ impl FractalImage { .find(|&(_i, rw, rh)| img_w as i32 <= rw && img_h as i32 <= rh) .unwrap() .0 - - 1 + -1 } fn find_center(depth: usize, variant: [Coord; 30]) -> Coord { @@ -124,7 +124,7 @@ impl FractalImage { #[inline] pub fn set_pixel(&mut self, x: i32, y: i32, v: i32) { - let (x, y) = (u32::try_from(x).unwrap(), u32::try_from(y).unwrap()); + let (x, y) = (x as u32, y as u32); let gray = v.clamp(0, 255) as u8; if x < self.width && y < self.height { self.image.put_pixel(x, y, image::Luma([gray])); @@ -140,6 +140,6 @@ pub fn get_quantization_matrix_soft() -> Vec { #[must_use] pub fn get_quantization_matrix() -> Vec { vec![ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 9, 2, + 1, 1, 1,1,1,1,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, 10, 10, 10, 10, 10, 16, 9, 2, ] } diff --git a/src/fractal/variants.rs b/src/fractal/variants.rs index 2264db9..dca861a 100644 --- a/src/fractal/variants.rs +++ b/src/fractal/variants.rs @@ -1,4 +1,4 @@ -use crate::utils::coordinate::Coord; +use crate::utils::Coord; use clap::ValueEnum; use serde::{Deserialize, Serialize}; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..d822c48 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,28 @@ +use std::ops; + +#[derive(Clone, Copy, Debug)] +pub struct Coord { + pub x: i32, + pub y: i32, +} + +impl ops::Add for Coord { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + Self { + x: self.x + rhs.x, + y: self.y + rhs.y, + } + } +} + +pub const fn get_prev_power_two(x: usize) -> usize { + let mut num = x; + num |= num >> 1; + num |= num >> 2; + num |= num >> 4; + num |= num >> 8; + num |= num >> 16; + + num ^ (num >> 1) +} diff --git a/src/utils/bitwise.rs b/src/utils/bitwise.rs deleted file mode 100644 index 5eb2864..0000000 --- a/src/utils/bitwise.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub const fn get_prev_power_two(x: usize) -> usize { - let mut num = x; - num |= num >> 1; - num |= num >> 2; - num |= num >> 4; - num |= num >> 8; - num |= num >> 16; - - num ^ (num >> 1) -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs deleted file mode 100644 index d7fae66..0000000 --- a/src/utils/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod bitwise; -pub mod coordinate; diff --git a/src/utils/coordinate.rs b/utils.rs similarity index 100% rename from src/utils/coordinate.rs rename to utils.rs