diff --git a/src/bin/dctfilename.rs b/src/bin/dctfilename.rs index 43392fe..2c59bb7 100644 --- a/src/bin/dctfilename.rs +++ b/src/bin/dctfilename.rs @@ -18,7 +18,7 @@ impl Cfg{ fn main() { //Init all descriptors: - let desc = DCT; + let desc = DCT::new(); let args: Vec = env::args().collect(); //dbg!(args); diff --git a/src/descriptors.rs b/src/descriptors.rs index 1ecb029..b7f419f 100644 --- a/src/descriptors.rs +++ b/src/descriptors.rs @@ -45,14 +45,76 @@ impl Descriptor for Median { } } -pub struct 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], +} + + +/// Interprets a 64-element array as an 8x8 matrix +/// returns a nicely printable 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"); + } + output.push('\n'); + } + output +} + + +// Define S such that if (Q < 50), then S = 5000/Q, else S = 200 – 2*Q. +// The output quantization matrix Ts[i,j] at each location of row i and column j is such that +// Ts[i,j] = floor((S * Tb[i,j] + 50) / 100) + + +impl DCT { + pub fn new() -> DCT { + let base_quantization_matrix: [u8; 64] = [ + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 6, 10, 103, 77, + 24, 35, 55, 64, 8, 10, 113, 92, + 49, 64, 78, 8, 10, 12, 12, 101, + 72, 92, 95, 9, 11, 10, 103, 99, + ]; + DCT { quantization_matrix: base_quantization_matrix } + } + pub fn quantization_matrix(&self, quality: u8) -> [u8; 64] { + let mut quantization_matrix = self.quantization_matrix.clone(); + let scalar: f32 = match quality { + 1..=49 => 5000.0/quality as f32, + 50..=100 => 200.0 - 2.0*quality as f32, + _ => 1.0 //TODO: error + }; + for i in 0..64 { + quantization_matrix[i] = ((scalar * self.quantization_matrix[i] as f32 + 50.0) / 100.0).floor() as u8; + if quantization_matrix[i] == 0 { + quantization_matrix[i] = 1; + } + } + quantization_matrix + } +} 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)); let mut dct_values: [f64; 64] = [0.0; 64]; let mut reconstructed: [u8; 64] = [0; 64]; let img = self.resize(img); - let _ = img.save("resize.png").expect("Error saving file"); + img.save("resize.png").expect("Error saving file"); for u in 0..8 { for v in 0..8 { let k = (v*8)+u; @@ -79,6 +141,17 @@ impl Descriptor for DCT { //println!{"{}", dct_values[k]} } } + println!("DCT-coefficients:\n {}", print_matrix(dct_values)); + // Quantization: + for i in 0..64 { + dct_values[i] = (dct_values[i] / qmatrix[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; + } + println!("DCT-coefficients, de-quantized:\n {}", print_matrix(dct_values)); for k in 0..64 { let x = (k%8) as f64; let y = (k/8) as f64; @@ -106,6 +179,7 @@ impl Descriptor for DCT { //println!("Reconstructed pixel: {}", sum); reconstructed[k] = std::cmp::min(255_u8, sum as u8); } + //println!("{}", print_matrix(reconstructed)); save_buffer( "reconstructed.png", &reconstructed,