Browse Source

Code cleanup and addressing usize vs u32 issues

master
Drew Short 5 years ago
parent
commit
fa97ecc742
  1. 18
      Cargo.toml
  2. 7
      src/cache.rs
  3. 11
      src/hash/ahash.rs
  4. 15
      src/hash/dhash.rs
  5. 16
      src/hash/phash.rs
  6. 185
      src/lib.rs

18
Cargo.toml

@ -1,6 +1,6 @@
[package] [package]
name = "pihash" name = "pihash"
version = "0.4.1"
version = "0.5.0"
authors = ["Drew Short <warrick@sothr.com>"] authors = ["Drew Short <warrick@sothr.com>"]
description = "A simple library for generating perceptual hashes for images and comparing images based on their perceptual hashes." 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/" repository = "https://github.com/warricksothr/Perceptual-Image-Hashing/"
@ -20,14 +20,14 @@ default = []
bench = [] bench = []
[dependencies] [dependencies]
libc = "0.2.36"
rustc-serialize = "0.3.22"
libc = "0.2.62"
rustc-serialize = "0.3.24"
dft = "0.5.5" 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" sha1 = "0.6.0"

7
src/cache.rs

@ -167,10 +167,11 @@ impl<'a> Cache<'a> {
// println!("Saving: {}", cache_path_str); // println!("Saving: {}", cache_path_str);
match create_dir_all(cache_dir_str) { match create_dir_all(cache_dir_str) {
Ok(_) => { 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) => { Ok(mut file) => {
// Save the file into the cache // Save the file into the cache
match image.save(&mut file, image::ImageFormat::PNG) {
match image.save(file_path) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
println!("Error: {}", e); println!("Error: {}", e);
@ -364,7 +365,7 @@ fn test_get_file_hash() {
match hash { match hash {
Ok(v) => { Ok(v) => {
println!("Hash: {}", v); println!("Hash: {}", v);
assert!(v == "4beb6f2d852b75a313863916a1803ebad13a3196");
assert_eq!(v, String::from("4beb6f2d852b75a313863916a1803ebad13a3196"));
} }
Err(e) => { Err(e) => {
println!("Error: {:?}", e); println!("Error: {:?}", e);

11
src/hash/ahash.rs

@ -5,12 +5,15 @@
extern crate image; extern crate image;
use cache::Cache;
use self::image::GenericImage;
use std::path::Path; use std::path::Path;
use cache::Cache;
use super::{HashType, PerceptualHash, Precision, PreparedImage}; use super::{HashType, PerceptualHash, Precision, PreparedImage};
use super::prepare_image; use super::prepare_image;
use self::image::{GenericImage, GenericImageView};
pub struct AHash<'a> { pub struct AHash<'a> {
prepared_image: Box<PreparedImage<'a>>, prepared_image: Box<PreparedImage<'a>>,
} }
@ -39,7 +42,7 @@ impl<'a> PerceptualHash for AHash<'a> {
// calculating the average pixel value // calculating the average pixel value
let mut total = 0u64; let mut total = 0u64;
for (_, _, pixel) in image.pixels() { for (_, _, pixel) in image.pixels() {
total += pixel.data[0] as u64;
total += pixel.0[0] as u64;
} }
let mean = total / (height * width) as u64; let mean = total / (height * width) as u64;
// println!("Mean for {} is {}", prepared_image.orig_path, mean); // 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 // Calculating a hash based on the mean
let mut hash = 0u64; let mut hash = 0u64;
for (_, _, pixel) in image.pixels() { for (_, _, pixel) in image.pixels() {
if pixel.data[0] as u64 >= mean {
if pixel.0[0] as u64 >= mean {
hash |= 1; hash |= 1;
// println!("Pixel {} is >= {} therefore {:b}", pixel_sum, mean, hash); // println!("Pixel {} is >= {} therefore {:b}", pixel_sum, mean, hash);
} else { } else {

15
src/hash/dhash.rs

@ -4,12 +4,15 @@
// This file may not be copied, modified, or distributed except according to those terms. // This file may not be copied, modified, or distributed except according to those terms.
extern crate image; extern crate image;
use cache::Cache;
use self::image::GenericImage;
use std::path::Path; use std::path::Path;
use cache::Cache;
use super::{HashType, PerceptualHash, Precision, PreparedImage}; use super::{HashType, PerceptualHash, Precision, PreparedImage};
use super::prepare_image; use super::prepare_image;
use self::image::{GenericImage, GenericImageView};
pub struct DHash<'a> { pub struct DHash<'a> {
prepared_image: Box<PreparedImage<'a>>, prepared_image: Box<PreparedImage<'a>>,
} }
@ -35,18 +38,18 @@ impl<'a> PerceptualHash for DHash<'a> {
Some(ref image) => { Some(ref image) => {
let (_, _, first_pixel) = image.pixels().nth(0).unwrap(); let (_, _, first_pixel) = image.pixels().nth(0).unwrap();
let (_, _, last_pixel) = image.pixels().last().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 // Calculate the dhash
let mut previous_pixel_value = 0u64; let mut previous_pixel_value = 0u64;
let mut hash = 0u64; let mut hash = 0u64;
for (x, y, pixel) in image.pixels() { for (x, y, pixel) in image.pixels() {
if x == 0 && y == 0 { if x == 0 && y == 0 {
previous_pixel_value = pixel.data[0] as u64;
previous_pixel_value = pixel.0[0] as u64;
continue; continue;
} }
let pixel_val = pixel.data[0] as u64;
let pixel_val = pixel.0[0] as u64;
if pixel_val >= previous_pixel_value { if pixel_val >= previous_pixel_value {
hash |= 1; hash |= 1;
} else { } else {

16
src/hash/phash.rs

@ -4,15 +4,18 @@
// This file may not be copied, modified, or distributed except according to those terms. // This file may not be copied, modified, or distributed except according to those terms.
extern crate image; extern crate image;
use cache::Cache;
use self::image::{GenericImage, DynamicImage};
use std::path::Path; use std::path::Path;
use cache::Cache;
use super::{HashType, PerceptualHash, Precision, PreparedImage}; use super::{HashType, PerceptualHash, Precision, PreparedImage};
use super::dft; use super::dft;
use super::dft::Transform; use super::dft::Transform;
use super::image::Pixel; use super::image::Pixel;
use super::prepare_image; use super::prepare_image;
use self::image::{DynamicImage, GenericImage, GenericImageView};
pub struct PHash<'a> { pub struct PHash<'a> {
prepared_image: Box<PreparedImage<'a>>, prepared_image: Box<PreparedImage<'a>>,
} }
@ -37,8 +40,7 @@ impl<'a> PerceptualHash for PHash<'a> {
match self.prepared_image.image { match self.prepared_image.image {
Some(ref image) => { Some(ref image) => {
// Get the image data into a vector to perform the DFT on. // 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 // Get 2d data to 2d FFT/DFT
// Either from the cache or calculate it // 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) image: &DynamicImage)
-> Vec<Vec<f64>> { -> Vec<Vec<f64>> {
let mut data_matrix: Vec<Vec<f64>> = Vec::new(); let mut data_matrix: Vec<Vec<f64>> = Vec::new();
// Preparing the results // Preparing the results
for x in 0..width {
for x in 0..width as usize {
data_matrix.push(Vec::new()); data_matrix.push(Vec::new());
for y in 0..height { for y in 0..height {
let pos_x = x as u32; let pos_x = x as u32;

185
src/lib.rs

@ -6,18 +6,20 @@
// Enable nightly features for extra testing behind the bench feature // Enable nightly features for extra testing behind the bench feature
#![cfg_attr(feature = "bench", feature(test))] #![cfg_attr(feature = "bench", feature(test))]
extern crate image;
extern crate libc; extern crate libc;
extern crate rustc_serialize; extern crate rustc_serialize;
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
extern crate test; extern crate test;
pub mod hash;
pub mod cache;
use std::path::Path;
use std::ffi::CStr; use std::ffi::CStr;
use std::path::Path;
use cache::Cache; use cache::Cache;
pub mod hash;
pub mod cache;
#[repr(C)] #[repr(C)]
pub struct PIHash<'a> { pub struct PIHash<'a> {
cache: Option<Cache<'a>>, cache: Option<Cache<'a>>,
@ -174,11 +176,11 @@ pub extern "C" fn ext_get_phash(lib: &PIHash, path_char: *const libc::c_char) ->
pub struct PIHashes { pub struct PIHashes {
ahash: libc::uint64_t, ahash: libc::uint64_t,
dhash: libc::uint64_t, dhash: libc::uint64_t,
phash: libc::uint64_t
phash: libc::uint64_t,
} }
#[no_mangle] #[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 { unsafe {
let path_str = CStr::from_ptr(path_char); let path_str = CStr::from_ptr(path_char);
let image_path = match path_str.to_str() { 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 { Box::into_raw(Box::new(PIHashes {
ahash: phashes.ahash, ahash: phashes.ahash,
dhash: phashes.dhash, dhash: phashes.dhash,
phash: phashes.phash
phash: phashes.phash,
})) }))
} }
} }
@ -222,11 +224,12 @@ fn to_hex_string(bytes: &[u8]) -> String {
// //
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use hash;
use cache; use cache;
use hash;
use super::PIHash; use super::PIHash;
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
use super::test::Bencher; use super::test::Bencher;
@ -302,10 +305,14 @@ mod tests {
let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR)); let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR));
// Sample_01 tests // 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, test_imageset_hash(hash::HashType::AHash,
hash::Precision::Medium, hash::Precision::Medium,
1u64, 1u64,
@ -314,10 +321,14 @@ mod tests {
&lib); &lib);
// Sample_02 tests // 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, test_imageset_hash(hash::HashType::AHash,
hash::Precision::Medium, hash::Precision::Medium,
3u64, 3u64,
@ -326,10 +337,14 @@ mod tests {
&lib); &lib);
// Sample_03 tests // 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, test_imageset_hash(hash::HashType::AHash,
hash::Precision::Medium, hash::Precision::Medium,
1u64, 1u64,
@ -338,10 +353,14 @@ mod tests {
&lib); &lib);
// Sample_04 tests // 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, test_imageset_hash(hash::HashType::AHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
@ -359,10 +378,14 @@ mod tests {
let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR)); let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR));
// Sample_01 tests // 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, test_imageset_hash(hash::HashType::DHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
@ -371,10 +394,14 @@ mod tests {
&lib); &lib);
// Sample_02 tests // 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, test_imageset_hash(hash::HashType::DHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
@ -383,10 +410,14 @@ mod tests {
&lib); &lib);
// Sample_03 tests // 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, test_imageset_hash(hash::HashType::DHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
@ -395,10 +426,14 @@ mod tests {
&lib); &lib);
// Sample_04 tests // 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, test_imageset_hash(hash::HashType::DHash,
hash::Precision::Medium, hash::Precision::Medium,
1u64, 1u64,
@ -416,10 +451,14 @@ mod tests {
let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR)); let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR));
// Sample_01 tests // 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, test_imageset_hash(hash::HashType::PHash,
hash::Precision::Medium, hash::Precision::Medium,
1u64, 1u64,
@ -428,10 +467,14 @@ mod tests {
&lib); &lib);
// Sample_02 tests // 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, test_imageset_hash(hash::HashType::PHash,
hash::Precision::Medium, hash::Precision::Medium,
1u64, 1u64,
@ -440,10 +483,14 @@ mod tests {
&lib); &lib);
// Sample_03 tests // 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, test_imageset_hash(hash::HashType::PHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
@ -452,10 +499,14 @@ mod tests {
&lib); &lib);
// Sample_04 tests // 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, test_imageset_hash(hash::HashType::PHash,
hash::Precision::Medium, hash::Precision::Medium,
3u64, 3u64,
@ -480,11 +531,11 @@ mod tests {
&hash::HashType::PHash); &hash::HashType::PHash);
bench.iter(|| { 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")] #[cfg(feature = "bench")]
@ -494,10 +545,10 @@ mod tests {
let lib = PIHash::new(None); let lib = PIHash::new(None);
bench.iter(|| { 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);
})
} }
} }
Loading…
Cancel
Save