From d25bd4db8eb137f83dc4e7e79efb320174e8a4f1 Mon Sep 17 00:00:00 2001 From: Drew Short Date: Thu, 17 Sep 2015 22:13:58 -0500 Subject: [PATCH] Ported AHash to the new style for hashes. Set git to ignore sublime-workspace files --- .gitignore | 3 ++ Cargo.toml | 2 +- src/hash.rs | 103 +++++++++++++++++++++++++++++++++------------------- src/lib.rs | 7 ++-- 4 files changed, 74 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index 12c2467..4993fa1 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ Cargo.lock # Cache Directory .hash_cache/ + +# Ignore sublime workspace files +*.sublime-workspace diff --git a/Cargo.toml b/Cargo.toml index a777e72..6b48640 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pihash" -version = "0.1.0" +version = "0.1.1" authors = ["Drew Short "] description = "A simple library for generating perceptual hashes for images and comparing images based on their perceptual hashes." repository = "https://github.com/warricksothr/Perceptual-Image-Hashing/" diff --git a/src/hash.rs b/src/hash.rs index e4f0c39..649e545 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -20,14 +20,19 @@ use self::complex::*; use cache; // Used to get ranges for the precision of rounding floats +// Can round to 1 significant factor of precision const FLOAT_PRECISION_MAX_1: f64 = f64::MAX / 10_f64; const FLOAT_PRECISION_MIN_1: f64 = f64::MIN / 10_f64; +// Can round to 2 significant factors of precision const FLOAT_PRECISION_MAX_2: f64 = f64::MAX / 100_f64; const FLOAT_PRECISION_MIN_2: f64 = f64::MIN / 100_f64; +// Can round to 3 significant factors of precision const FLOAT_PRECISION_MAX_3: f64 = f64::MAX / 1000_f64; const FLOAT_PRECISION_MIN_3: f64 = f64::MIN / 1000_f64; +// Can round to 4 significant factors of precision const FLOAT_PRECISION_MAX_4: f64 = f64::MAX / 10000_f64; const FLOAT_PRECISION_MIN_4: f64 = f64::MIN / 10000_f64; +// Can round to 5 significant factors of precision const FLOAT_PRECISION_MAX_5: f64 = f64::MAX / 100000_f64; const FLOAT_PRECISION_MIN_5: f64 = f64::MIN / 100000_f64; @@ -51,6 +56,10 @@ pub struct PerceptualHashes<'a> { /** * All the supported precision types + * + * Low aims for 32 bit precision + * Medium aims for 64 bit precision + * High aims for 128 bit precision */ pub enum Precision { Low, @@ -58,6 +67,9 @@ pub enum Precision { High, } +/* + * Get the size of the required image + */ impl Precision { fn get_size(&self) -> u32 { match *self { @@ -122,7 +134,7 @@ pub fn get_perceptual_hashes<'a>(path: &'a Path, precision: &Precision) -> Perce // phash uses a DFT, so it needs an image 4 times larger to work with for // the same precision of hash. That said, this hash is much more accurate. let phash_prepared_image = prepare_image(path, &HashType::Phash, &precision); - let ahash = get_ahash(&prepared_image); + let ahash = AHash::new(&path, &precision).get_hash(); let dhash = get_dhash(&prepared_image); let phash = get_phash(&phash_prepared_image); PerceptualHashes { orig_path: &*image_path, ahash: ahash, dhash: dhash, phash: phash } @@ -147,49 +159,66 @@ pub fn calculate_hamming_distance(hash1: u64, hash2: u64) -> u64 { hamming } -/** - * Calculate the ahash of the provided prepared image. - * - * # Arguments - * - * * 'prepared_image' - The already prepared image for perceptual processing. - * - * # Returns - * - * A u64 representing the value of the hash - */ -pub fn get_ahash(prepared_image: &PreparedImage) -> u64 { - let (width, height) = prepared_image.image.dimensions(); +pub trait PerceptualHash { + fn get_hash(&self) -> u64; +} - // calculating the average pixel value - let mut total = 0u64; - for pixel in prepared_image.image.pixels() { - let channels = pixel.channels(); - //println!("Pixel is: {}", channels[0]); - total += channels[0] as u64; +pub struct AHash<'a> { + prepared_image: Box>, +} + +impl<'a> AHash<'a> { + pub fn new(path: &'a Path, precision: &Precision) -> Self { + AHash { prepared_image: Box::new(prepare_image(&path, &HashType::Ahash, &precision)) } } - let mean = total / (width*height) as u64; - //println!("Mean for {} is {}", prepared_image.orig_path, mean); +} - // Calculating a hash based on the mean - let mut hash = 0u64; - for pixel in prepared_image.image.pixels() { - let channels = pixel.channels(); - let pixel_sum = channels[0] as u64; - if pixel_sum >= mean { - hash |= 1; - //println!("Pixel {} is >= {} therefore {:b}", pixel_sum, mean, hash); - } else { - hash |= 0; - //println!("Pixel {} is < {} therefore {:b}", pixel_sum, mean, hash); +impl<'a> PerceptualHash for AHash<'a> { + /** + * Calculate the ahash of the provided prepared image. + * + * # Arguments + * + * * 'prepared_image' - The already prepared image for perceptual processing. + * + * # Returns + * + * A u64 representing the value of the hash + */ + fn get_hash(&self) -> u64 { + let (width, height) = self.prepared_image.image.dimensions(); + + // calculating the average pixel value + let mut total = 0u64; + for pixel in self.prepared_image.image.pixels() { + let channels = pixel.channels(); + //println!("Pixel is: {}", channels[0]); + total += channels[0] as u64; } - hash <<= 1; - } - //println!("Hash for {} is {}", prepared_image.orig_path, hash); + let mean = total / (width*height) as u64; + //println!("Mean for {} is {}", prepared_image.orig_path, mean); + + // Calculating a hash based on the mean + let mut hash = 0u64; + for pixel in self.prepared_image.image.pixels() { + let channels = pixel.channels(); + let pixel_sum = channels[0] as u64; + if pixel_sum >= mean { + hash |= 1; + //println!("Pixel {} is >= {} therefore {:b}", pixel_sum, mean, hash); + } else { + hash |= 0; + //println!("Pixel {} is < {} therefore {:b}", pixel_sum, mean, hash); + } + hash <<= 1; + } + //println!("Hash for {} is {}", prepared_image.orig_path, hash); - hash + hash + } } + /** * Calculate the dhash of the provided prepared image * diff --git a/src/lib.rs b/src/lib.rs index ad61e09..4d6c05e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,11 +3,12 @@ // Licensed under the MIT license. // This file may not be copied, modified, or distributed except according to those terms. -use std::path::Path; - mod hash; mod cache; +use std::path::Path; +use hash::PerceptualHash; + /** * Prepare the library for work. * @@ -25,7 +26,7 @@ pub fn get_phashes(path: &Path) -> hash::PerceptualHashes { } pub fn get_ahash(path: &Path) -> u64 { - hash::get_ahash(&hash::prepare_image(path, &hash::HashType::Ahash, &hash::Precision::Medium)) + hash::AHash::new(&path, &hash::Precision::Medium).get_hash() } pub fn get_dhash(path: &Path) -> u64 {