From fa97ecc7428966e1b60705080f4a5986a1b94310 Mon Sep 17 00:00:00 2001 From: Drew Short Date: Thu, 22 Aug 2019 23:04:10 -0500 Subject: [PATCH] Code cleanup and addressing usize vs u32 issues --- Cargo.toml | 18 ++--- src/cache.rs | 7 +- src/hash/ahash.rs | 11 ++- src/hash/dhash.rs | 15 ++-- src/hash/phash.rs | 16 ++-- src/lib.rs | 185 +++++++++++++++++++++++++++++----------------- 6 files changed, 156 insertions(+), 96 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 05b89bb..6b78203 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pihash" -version = "0.4.1" +version = "0.5.0" 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/" @@ -20,14 +20,14 @@ default = [] bench = [] [dependencies] -libc = "0.2.36" -rustc-serialize = "0.3.22" +libc = "0.2.62" +rustc-serialize = "0.3.24" dft = "0.5.5" -image = "0.18.0" -num = "0.1.42" -docopt = "0.8.3" -serde = "1.0" -serde_derive = "1.0" -flate2 = "1.0.1" +image = "0.22.1" +num = "0.2.0" +docopt = "1.1.0" +serde = "1.0.99" +serde_derive = "1.0.99" +flate2 = "1.0.11" sha1 = "0.6.0" diff --git a/src/cache.rs b/src/cache.rs index 7134c2f..7617e34 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -167,10 +167,11 @@ impl<'a> Cache<'a> { // println!("Saving: {}", cache_path_str); match create_dir_all(cache_dir_str) { Ok(_) => { - match File::create(Path::new(&cache_path_str)) { + let file_path = Path::new(&cache_path_str); + match File::create(file_path) { Ok(mut file) => { // Save the file into the cache - match image.save(&mut file, image::ImageFormat::PNG) { + match image.save(file_path) { Ok(_) => {} Err(e) => { println!("Error: {}", e); @@ -364,7 +365,7 @@ fn test_get_file_hash() { match hash { Ok(v) => { println!("Hash: {}", v); - assert!(v == "4beb6f2d852b75a313863916a1803ebad13a3196"); + assert_eq!(v, String::from("4beb6f2d852b75a313863916a1803ebad13a3196")); } Err(e) => { println!("Error: {:?}", e); diff --git a/src/hash/ahash.rs b/src/hash/ahash.rs index 1a045f4..a5a4800 100644 --- a/src/hash/ahash.rs +++ b/src/hash/ahash.rs @@ -5,12 +5,15 @@ extern crate image; -use cache::Cache; -use self::image::GenericImage; use std::path::Path; + +use cache::Cache; + use super::{HashType, PerceptualHash, Precision, PreparedImage}; use super::prepare_image; +use self::image::{GenericImage, GenericImageView}; + pub struct AHash<'a> { prepared_image: Box>, } @@ -39,7 +42,7 @@ impl<'a> PerceptualHash for AHash<'a> { // calculating the average pixel value let mut total = 0u64; for (_, _, pixel) in image.pixels() { - total += pixel.data[0] as u64; + total += pixel.0[0] as u64; } let mean = total / (height * width) as u64; // println!("Mean for {} is {}", prepared_image.orig_path, mean); @@ -47,7 +50,7 @@ impl<'a> PerceptualHash for AHash<'a> { // Calculating a hash based on the mean let mut hash = 0u64; for (_, _, pixel) in image.pixels() { - if pixel.data[0] as u64 >= mean { + if pixel.0[0] as u64 >= mean { hash |= 1; // println!("Pixel {} is >= {} therefore {:b}", pixel_sum, mean, hash); } else { diff --git a/src/hash/dhash.rs b/src/hash/dhash.rs index 0ac2529..4e486b8 100644 --- a/src/hash/dhash.rs +++ b/src/hash/dhash.rs @@ -4,12 +4,15 @@ // This file may not be copied, modified, or distributed except according to those terms. extern crate image; -use cache::Cache; -use self::image::GenericImage; use std::path::Path; + +use cache::Cache; + use super::{HashType, PerceptualHash, Precision, PreparedImage}; use super::prepare_image; +use self::image::{GenericImage, GenericImageView}; + pub struct DHash<'a> { prepared_image: Box>, } @@ -35,18 +38,18 @@ impl<'a> PerceptualHash for DHash<'a> { Some(ref image) => { let (_, _, first_pixel) = image.pixels().nth(0).unwrap(); let (_, _, last_pixel) = image.pixels().last().unwrap(); - let first_pixel_value = first_pixel.data[0] as u64; - let last_pixel_value = last_pixel.data[0] as u64; + let first_pixel_value = first_pixel.0[0] as u64; + let last_pixel_value = last_pixel.0[0] as u64; // Calculate the dhash let mut previous_pixel_value = 0u64; let mut hash = 0u64; for (x, y, pixel) in image.pixels() { if x == 0 && y == 0 { - previous_pixel_value = pixel.data[0] as u64; + previous_pixel_value = pixel.0[0] as u64; continue; } - let pixel_val = pixel.data[0] as u64; + let pixel_val = pixel.0[0] as u64; if pixel_val >= previous_pixel_value { hash |= 1; } else { diff --git a/src/hash/phash.rs b/src/hash/phash.rs index 2f3202d..24d338f 100644 --- a/src/hash/phash.rs +++ b/src/hash/phash.rs @@ -4,15 +4,18 @@ // This file may not be copied, modified, or distributed except according to those terms. extern crate image; -use cache::Cache; -use self::image::{GenericImage, DynamicImage}; use std::path::Path; + +use cache::Cache; + use super::{HashType, PerceptualHash, Precision, PreparedImage}; use super::dft; use super::dft::Transform; use super::image::Pixel; use super::prepare_image; +use self::image::{DynamicImage, GenericImage, GenericImageView}; + pub struct PHash<'a> { prepared_image: Box>, } @@ -37,8 +40,7 @@ impl<'a> PerceptualHash for PHash<'a> { match self.prepared_image.image { Some(ref image) => { // Get the image data into a vector to perform the DFT on. - let width = image.width() as usize; - let height = image.height() as usize; + let (width, height) = image.dimensions(); // Get 2d data to 2d FFT/DFT // Either from the cache or calculate it @@ -98,13 +100,13 @@ impl<'a> PerceptualHash for PHash<'a> { } } -fn create_data_matrix(width: usize, - height: usize, +fn create_data_matrix(width: u32, + height: u32, image: &DynamicImage) -> Vec> { let mut data_matrix: Vec> = Vec::new(); // Preparing the results - for x in 0..width { + for x in 0..width as usize { data_matrix.push(Vec::new()); for y in 0..height { let pos_x = x as u32; diff --git a/src/lib.rs b/src/lib.rs index d0b028c..63a2d78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,18 +6,20 @@ // Enable nightly features for extra testing behind the bench feature #![cfg_attr(feature = "bench", feature(test))] +extern crate image; extern crate libc; extern crate rustc_serialize; #[cfg(feature = "bench")] extern crate test; -pub mod hash; -pub mod cache; - -use std::path::Path; use std::ffi::CStr; +use std::path::Path; + use cache::Cache; +pub mod hash; +pub mod cache; + #[repr(C)] pub struct PIHash<'a> { cache: Option>, @@ -174,11 +176,11 @@ pub extern "C" fn ext_get_phash(lib: &PIHash, path_char: *const libc::c_char) -> pub struct PIHashes { ahash: libc::uint64_t, dhash: libc::uint64_t, - phash: libc::uint64_t + phash: libc::uint64_t, } #[no_mangle] -pub extern "C" fn ext_get_phashes(lib: &PIHash, path_char: *const libc::c_char) -> * mut PIHashes { +pub extern "C" fn ext_get_phashes(lib: &PIHash, path_char: *const libc::c_char) -> *mut PIHashes { unsafe { let path_str = CStr::from_ptr(path_char); let image_path = match path_str.to_str() { @@ -195,7 +197,7 @@ pub extern "C" fn ext_get_phashes(lib: &PIHash, path_char: *const libc::c_char) Box::into_raw(Box::new(PIHashes { ahash: phashes.ahash, dhash: phashes.dhash, - phash: phashes.phash + phash: phashes.phash, })) } } @@ -222,11 +224,12 @@ fn to_hex_string(bytes: &[u8]) -> String { // #[cfg(test)] mod tests { - use std::fs; use std::path::Path; - use hash; + use cache; + use hash; + use super::PIHash; #[cfg(feature = "bench")] use super::test::Bencher; @@ -302,10 +305,14 @@ mod tests { let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR)); // Sample_01 tests - let sample_01_images: [&Path; 3] = [&Path::new("./test_images/sample_01_large.jpg"), - &Path::new("./test_images/sample_01_medium.jpg"), - &Path::new("./test_images/sample_01_small.jpg")]; - let sample_01_hashes: [u64; 3] = [7065306774709811078, 7065306774709811078, 7065306774172940166]; + let sample_01_images: [&Path; 3] = [ + &Path::new("./test_images/sample_01_large.jpg"), + &Path::new("./test_images/sample_01_medium.jpg"), + &Path::new("./test_images/sample_01_small.jpg")]; + let sample_01_hashes: [u64; 3] = [ + 857051991849750, + 857051991849750, + 857051991849750]; test_imageset_hash(hash::HashType::AHash, hash::Precision::Medium, 1u64, @@ -314,10 +321,14 @@ mod tests { &lib); // Sample_02 tests - let sample_02_images: [&Path; 3] = [&Path::new("./test_images/sample_02_large.jpg"), - &Path::new("./test_images/sample_02_medium.jpg"), - &Path::new("./test_images/sample_02_small.jpg")]; - let sample_02_hashes: [u64; 3] = [18446744068986765312, 18446744069246812160, 18446744073541779456]; + let sample_02_images: [&Path; 3] = [ + &Path::new("./test_images/sample_02_large.jpg"), + &Path::new("./test_images/sample_02_medium.jpg"), + &Path::new("./test_images/sample_02_small.jpg")]; + let sample_02_hashes: [u64; 3] = [ + 18446744073441116160, + 18446744073441116160, + 18446744073441116160]; test_imageset_hash(hash::HashType::AHash, hash::Precision::Medium, 3u64, @@ -326,10 +337,14 @@ mod tests { &lib); // Sample_03 tests - let sample_03_images: [&Path; 3] = [&Path::new("./test_images/sample_03_large.jpg"), - &Path::new("./test_images/sample_03_medium.jpg"), - &Path::new("./test_images/sample_03_small.jpg")]; - let sample_03_hashes: [u64; 3] = [108649334536274430, 126663733045756414, 108649334536274430]; + let sample_03_images: [&Path; 3] = [ + &Path::new("./test_images/sample_03_large.jpg"), + &Path::new("./test_images/sample_03_medium.jpg"), + &Path::new("./test_images/sample_03_small.jpg")]; + let sample_03_hashes: [u64; 3] = [ + 135670932300497406, + 135670932300497406, + 135670932300497406]; test_imageset_hash(hash::HashType::AHash, hash::Precision::Medium, 1u64, @@ -338,10 +353,14 @@ mod tests { &lib); // Sample_04 tests - let sample_04_images: [&Path; 3] = [&Path::new("./test_images/sample_04_large.jpg"), - &Path::new("./test_images/sample_04_medium.jpg"), - &Path::new("./test_images/sample_04_small.jpg")]; - let sample_04_hashes: [u64; 3] = [18446460933225054208, 18446460933225054208, 18446460933225054208]; + let sample_04_images: [&Path; 3] = [ + &Path::new("./test_images/sample_04_large.jpg"), + &Path::new("./test_images/sample_04_medium.jpg"), + &Path::new("./test_images/sample_04_small.jpg")]; + let sample_04_hashes: [u64; 3] = [ + 18446460933225054208, + 18446460933225054208, + 18446460933225054208]; test_imageset_hash(hash::HashType::AHash, hash::Precision::Medium, 0u64, @@ -359,10 +378,14 @@ mod tests { let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR)); // Sample_01 tests - let sample_01_images: [&Path; 3] = [&Path::new("./test_images/sample_01_large.jpg"), - &Path::new("./test_images/sample_01_medium.jpg"), - &Path::new("./test_images/sample_01_small.jpg")]; - let sample_01_hashes: [u64; 3] = [18131474507607572478, 18131474507607572478, 18131474507607572478]; + let sample_01_images: [&Path; 3] = [ + &Path::new("./test_images/sample_01_large.jpg"), + &Path::new("./test_images/sample_01_medium.jpg"), + &Path::new("./test_images/sample_01_small.jpg")]; + let sample_01_hashes: [u64; 3] = [ + 3404580580803739582, + 3404580580803739582, + 3404580580803739582]; test_imageset_hash(hash::HashType::DHash, hash::Precision::Medium, 0u64, @@ -371,10 +394,14 @@ mod tests { &lib); // Sample_02 tests - let sample_02_images: [&Path; 3] = [&Path::new("./test_images/sample_02_large.jpg"), - &Path::new("./test_images/sample_02_medium.jpg"), - &Path::new("./test_images/sample_02_small.jpg")]; - let sample_02_hashes: [u64; 3] = [10088065226894213121, 10088065226894213121, 10088065226894213121]; + let sample_02_images: [&Path; 3] = [ + &Path::new("./test_images/sample_02_large.jpg"), + &Path::new("./test_images/sample_02_medium.jpg"), + &Path::new("./test_images/sample_02_small.jpg")]; + let sample_02_hashes: [u64; 3] = [ + 14726771606135242753, + 14726771606135242753, + 14726771606135242753]; test_imageset_hash(hash::HashType::DHash, hash::Precision::Medium, 0u64, @@ -383,10 +410,14 @@ mod tests { &lib); // Sample_03 tests - let sample_03_images: [&Path; 3] = [&Path::new("./test_images/sample_03_large.jpg"), - &Path::new("./test_images/sample_03_medium.jpg"), - &Path::new("./test_images/sample_03_small.jpg")]; - let sample_03_hashes: [u64; 3] = [144115181601817086, 144115181601817086, 144115181601817086]; + let sample_03_images: [&Path; 3] = [ + &Path::new("./test_images/sample_03_large.jpg"), + &Path::new("./test_images/sample_03_medium.jpg"), + &Path::new("./test_images/sample_03_small.jpg")]; + let sample_03_hashes: [u64; 3] = [ + 144115181601817086, + 144115181601817086, + 144115181601817086]; test_imageset_hash(hash::HashType::DHash, hash::Precision::Medium, 0u64, @@ -395,10 +426,14 @@ mod tests { &lib); // Sample_04 tests - let sample_04_images: [&Path; 3] = [&Path::new("./test_images/sample_04_large.jpg"), - &Path::new("./test_images/sample_04_medium.jpg"), - &Path::new("./test_images/sample_04_small.jpg")]; - let sample_04_hashes: [u64; 3] = [18374262326015557633, 18374262326015557633, 18374262326283993089]; + let sample_04_images: [&Path; 3] = [ + &Path::new("./test_images/sample_04_large.jpg"), + &Path::new("./test_images/sample_04_medium.jpg"), + &Path::new("./test_images/sample_04_small.jpg")]; + let sample_04_hashes: [u64; 3] = [ + 18374262188442386433, + 18374262188442386433, + 18374262188442386433]; test_imageset_hash(hash::HashType::DHash, hash::Precision::Medium, 1u64, @@ -416,10 +451,14 @@ mod tests { let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR)); // Sample_01 tests - let sample_01_images: [&Path; 3] = [&Path::new("./test_images/sample_01_large.jpg"), - &Path::new("./test_images/sample_01_medium.jpg"), - &Path::new("./test_images/sample_01_small.jpg")]; - let sample_01_hashes: [u64; 3] = [72410537899606272, 72410537899606272, 72410537899606400]; + let sample_01_images: [&Path; 3] = [ + &Path::new("./test_images/sample_01_large.jpg"), + &Path::new("./test_images/sample_01_medium.jpg"), + &Path::new("./test_images/sample_01_small.jpg")]; + let sample_01_hashes: [u64; 3] = [ + 72357778504597504, + 72357778504597504, + 72357778504597504]; test_imageset_hash(hash::HashType::PHash, hash::Precision::Medium, 1u64, @@ -428,10 +467,14 @@ mod tests { &lib); // Sample_02 tests - let sample_02_images: [&Path; 3] = [&Path::new("./test_images/sample_02_large.jpg"), - &Path::new("./test_images/sample_02_medium.jpg"), - &Path::new("./test_images/sample_02_small.jpg")]; - let sample_02_hashes: [u64; 3] = [5620563253458370560, 5620562703702556672, 5620562703702556672]; + let sample_02_images: [&Path; 3] = [ + &Path::new("./test_images/sample_02_large.jpg"), + &Path::new("./test_images/sample_02_medium.jpg"), + &Path::new("./test_images/sample_02_small.jpg")]; + let sample_02_hashes: [u64; 3] = [ + 5332332327550844928, + 5332332327550844928, + 5332332327550844928]; test_imageset_hash(hash::HashType::PHash, hash::Precision::Medium, 1u64, @@ -440,10 +483,14 @@ mod tests { &lib); // Sample_03 tests - let sample_03_images: [&Path; 3] = [&Path::new("./test_images/sample_03_large.jpg"), - &Path::new("./test_images/sample_03_medium.jpg"), - &Path::new("./test_images/sample_03_small.jpg")]; - let sample_03_hashes: [u64; 3] = [6926536226895822848, 6926536226895822848, 6926536226895822848]; + let sample_03_images: [&Path; 3] = [ + &Path::new("./test_images/sample_03_large.jpg"), + &Path::new("./test_images/sample_03_medium.jpg"), + &Path::new("./test_images/sample_03_small.jpg")]; + let sample_03_hashes: [u64; 3] = [ + 6917529027641081856, + 6917529027641081856, + 6917529027641081856]; test_imageset_hash(hash::HashType::PHash, hash::Precision::Medium, 0u64, @@ -452,10 +499,14 @@ mod tests { &lib); // Sample_04 tests - let sample_04_images: [&Path; 3] = [&Path::new("./test_images/sample_04_large.jpg"), - &Path::new("./test_images/sample_04_medium.jpg"), - &Path::new("./test_images/sample_04_small.jpg")]; - let sample_04_hashes: [u64; 3] = [11430286023502856200, 10997940459275288576, 11142055647351144448]; + let sample_04_images: [&Path; 3] = [ + &Path::new("./test_images/sample_04_large.jpg"), + &Path::new("./test_images/sample_04_medium.jpg"), + &Path::new("./test_images/sample_04_small.jpg")]; + let sample_04_hashes: [u64; 3] = [ + 10997931646002397184, + 10997931646002397184, + 10997931646002397184]; test_imageset_hash(hash::HashType::PHash, hash::Precision::Medium, 3u64, @@ -480,11 +531,11 @@ mod tests { &hash::HashType::PHash); bench.iter(|| { - // Sample_01 Bench - lib.get_perceptual_hash(&Path::new("./test_images/sample_01_large.jpg"), - &hash::Precision::Medium, - &hash::HashType::PHash); - }) + // Sample_01 Bench + lib.get_perceptual_hash(&Path::new("./test_images/sample_01_large.jpg"), + &hash::Precision::Medium, + &hash::HashType::PHash); + }) } #[cfg(feature = "bench")] @@ -494,10 +545,10 @@ mod tests { let lib = PIHash::new(None); bench.iter(|| { - // Sample_01 Bench - lib.get_perceptual_hash(&Path::new("./test_images/sample_01_large.jpg"), - &hash::Precision::Medium, - &hash::HashType::PHash); - }) + // Sample_01 Bench + lib.get_perceptual_hash(&Path::new("./test_images/sample_01_large.jpg"), + &hash::Precision::Medium, + &hash::HashType::PHash); + }) } }