//! Descriptors that can be used to describe an image. //! If two images are (almost) the same, their descriptions will be the same. use image::GenericImageView; pub trait Descriptor { /// Print the name of the descriptor, fn info(&self) -> String; fn resize(&self, img: &image::DynamicImage) -> image::DynamicImage { img.grayscale().thumbnail_exact(8, 8) } fn describe(&self, img: &image::DynamicImage) -> u64; fn distance(&self, a: u64, b: u64) -> u64 { (a^b).count_ones().into() } } /// 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 { 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] } pub mod dct; fn median64(values: &[T]) -> T { let mut sorted_values = values.to_vec(); sorted_values.sort(); let len = sorted_values.len(); sorted_values[len/2] } pub struct Median; impl Descriptor for Median { fn info(&self) -> String { "median".to_string() } fn describe(&self, img: &image::DynamicImage) -> u64 { let img = self.resize(img); let mut values: [u8; 64] = [0; 64]; let mut i: usize = 0; for (_, _, pix) in img.pixels() { values[i] = pix[0]; i = i+1; } let median = median64(&values); let mut mask: u64 = 0; img.save("debug.png").unwrap(); for (_, _, pix) in img.pixels() { if pix[0] > median { mask += 1; } mask = mask << 1; } mask } } pub fn get_all_descriptors() -> Vec> { let mut descriptors: Vec> = Vec::with_capacity(2); descriptors.push(Box::new(DCT::new())); //descriptors.push(Box::new(Median)); descriptors }