diff --git a/src/bin/dctfilename.rs b/src/bin/dctfilename.rs index 21a4ce4..ef9f440 100644 --- a/src/bin/dctfilename.rs +++ b/src/bin/dctfilename.rs @@ -19,10 +19,9 @@ impl Cfg{ fn main() { //Init all descriptors: - let desc = DCT::new(); + let desc = DCT::new().with_quality(50); let args: Vec = env::args().collect(); - //dbg!(args); let cfg = Cfg::load(&args) .expect("Error loading config"); diff --git a/src/descriptors/dct.rs b/src/descriptors/dct.rs index de0d91f..a285a78 100644 --- a/src/descriptors/dct.rs +++ b/src/descriptors/dct.rs @@ -2,14 +2,9 @@ use image::{save_buffer, GenericImageView}; use std::f64::consts::{PI, SQRT_2}; use crate::descriptors::{Descriptor, print_matrix, DCT}; -/// A struct representing a Discrete Cosine Transform descriptor -/// Transforms an image into an 8x8 grayscale version, and transforms it -/// into the frequency domain -// pub struct DCT { -// quantization_matrix: [u8; 64], -// } impl DCT { + /// Returns a new DCT instance with a calculated DCT matrix. pub fn new() -> DCT { let base_quantization_matrix: [u8; 64] = [ 16, 11, 10, 16, 24, 40, 51, 61, @@ -23,8 +18,10 @@ impl DCT { ]; DCT { quantization_matrix: base_quantization_matrix } } - pub fn quantization_matrix(&self, quality: u8) -> [u8; 64] { - let mut quantization_matrix = self.quantization_matrix.clone(); + + // Builds DCT with given quality value + pub fn with_quality(mut self, quality: u8) -> Self { + let mut quantization_matrix: [u8; 64] = [0; 64]; let scalar: f32 = match quality { 1..=49 => 5000.0/quality as f32, 50..=100 => 200.0 - 2.0*quality as f32, @@ -36,54 +33,14 @@ impl DCT { quantization_matrix[i] = 1; } } - quantization_matrix + self.quantization_matrix = quantization_matrix; + self } - /// TODO - // pub fn dct(&self, img: image::DynamicImage) -> [f64; 64] { - // } - - pub fn idct(&self, dct_values: [f64; 64]) -> [u8; 64] { - let mut reconstructed: [u8; 64] = [0; 64]; - for k in 0..64 { - let x = (k%8) as f64; - let y = (k/8) as f64; - let mut sum = 0.0; - for u in 0..8 { - for v in 0..8 { - let mut alpha = 1.0; - if u == 0 { - alpha = alpha / SQRT_2 - } - if v == 0 { - alpha = alpha / SQRT_2 - } - let uv = (v*8)+u; - let v = v as f64; - let u = u as f64; - sum += - alpha * - dct_values[uv] * - ((2.0 * x + 1.0) * u * PI / 16.0).cos() * - ((2.0 * y + 1.0) * v * PI / 16.0).cos() - } - } - sum = 127.0 + (0.25 * sum).round(); - reconstructed[k] = std::cmp::min(255_u8, sum as u8); - } - reconstructed - } -} - -impl Descriptor for DCT { - fn describe(&self, img: image::DynamicImage) -> u64 { - let quality: u8 = 15; - let qmatrix = self.quantization_matrix(quality); - - println!("Base quantization matrix:\n{}", print_matrix(self.quantization_matrix)); - println!("Q-{} quantization matrix:\n{}", quality, print_matrix(qmatrix)); + pub fn dct(&self, img: image::DynamicImage) -> [f64; 64] { + //let qmatrix = self.quantization_matrix(self.quality); + //println!("Q-{} quantization matrix:\n{}", self.quality, print_matrix(qmatrix)); let mut dct_values: [f64; 64] = [0.0; 64]; - let img = self.resize(img); img.save("resize.png").expect("Error saving file"); for u in 0..8 { for v in 0..8 { @@ -111,19 +68,64 @@ impl Descriptor for DCT { //println!{"{}", dct_values[k]} } } + dct_values + } + + pub fn idct(&self, dct_values: [f64; 64]) -> [u8; 64] { + let mut reconstructed: [u8; 64] = [0; 64]; + for k in 0..64 { + let x = (k%8) as f64; + let y = (k/8) as f64; + let mut sum = 0.0; + for u in 0..8 { + for v in 0..8 { + let mut alpha = 1.0; + if u == 0 { + alpha = alpha / SQRT_2 + } + if v == 0 { + alpha = alpha / SQRT_2 + } + let uv = (v*8)+u; + let v = v as f64; + let u = u as f64; + sum += + alpha * + dct_values[uv] * + ((2.0 * x + 1.0) * u * PI / 16.0).cos() * + ((2.0 * y + 1.0) * v * PI / 16.0).cos(); + } + } + sum = 127.0 + (0.25 * sum).round(); + reconstructed[k] = std::cmp::min(255_u8, sum as u8); + } + reconstructed + } +} + +impl Descriptor for DCT { + fn describe(&self, img: image::DynamicImage) -> u64 { + let img = self.resize(img); + let mut dct_values = self.dct(img); println!("DCT-coefficients:\n {}", print_matrix(dct_values)); + // Quantization: + println!("Using quantization matrix:\n{}", print_matrix(self.quantization_matrix)); for i in 0..64 { - dct_values[i] = (dct_values[i] / qmatrix[i] as f64).round(); + dct_values[i] = (dct_values[i] / self.quantization_matrix[i] as f64).round(); } println!("DCT-coefficients, quantized:\n {}", print_matrix(dct_values)); + // De-quantization: for i in 0..64 { - dct_values[i] = dct_values[i] * qmatrix[i] as f64; + dct_values[i] = dct_values[i] * self.quantization_matrix[i] as f64; } println!("DCT-coefficients, de-quantized:\n {}", print_matrix(dct_values)); + + // Reconstruction original pixel values: let reconstructed = self.idct(dct_values); println!("Reconstructed pixel values:\n{}", print_matrix(reconstructed)); + save_buffer( "reconstructed.png", &reconstructed, @@ -131,6 +133,8 @@ impl Descriptor for DCT { 8, image::ColorType::L8 ).expect("Error saving buffer"); + + // Calculating descriptor from dct values: let mut mask: u64 = 0; for dct in dct_values { if dct > 0.0 { diff --git a/src/descriptors/mod.rs b/src/descriptors/mod.rs index 16e70f8..0c54c9d 100644 --- a/src/descriptors/mod.rs +++ b/src/descriptors/mod.rs @@ -13,22 +13,25 @@ pub trait Descriptor { /// Interprets a 64-element array as an 8x8 matrix /// returns a nicely printable string -fn print_matrix(array: [T; 64]) -> String { +fn print_matrix(array: [T; 64]) -> String { let mut output = String::new(); for x in 0..8 { for y in 0..8 { - output.push_str(&array[x*8+y].to_string()); - output.push_str(",\t"); + let element = format!("{:.2}", &array[x*8+y]); + let element = format!("{:8}\t", element); + output.push_str(&element); } output.push('\n'); } output } +/// A struct representing a Discrete Cosine Transform descriptor +/// Transforms an image into an 8x8 grayscale version, and transforms it +/// into the frequency domain pub struct DCT { - quantization_matrix: [u8; 64], + quantization_matrix: [u8; 64] } - pub mod dct; // fn median64(values: &[T]) -> T {