Browse Source

Reformatted project with RustFMT

master
Drew Short 5 years ago
parent
commit
3206c81967
  1. 144
      src/cache.rs
  2. 16
      src/hash/ahash.rs
  3. 2
      src/hash/dhash.rs
  4. 62
      src/hash/mod.rs
  5. 21
      src/hash/phash.rs
  6. 383
      src/lib.rs
  7. 28
      src/main.rs

144
src/cache.rs

@ -8,20 +8,22 @@ extern crate image;
extern crate num; extern crate num;
extern crate sha1; extern crate sha1;
use self::flate2::Compression;
use self::flate2::read::ZlibDecoder;
use self::flate2::write::ZlibEncoder;
use self::image::DynamicImage;
use self::sha1::Sha1;
use std::default::Default; use std::default::Default;
use std::fs::{create_dir_all, File, remove_dir_all};
use std::fs::{create_dir_all, remove_dir_all, File};
use std::io::{Error, ErrorKind, Read, Write}; use std::io::{Error, ErrorKind, Read, Write};
use std::option::Option; use std::option::Option;
use std::path::Path; use std::path::Path;
use std::result::Result; use std::result::Result;
use std::str::FromStr; use std::str::FromStr;
use super::rustc_serialize::json; use super::rustc_serialize::json;
use self::flate2::read::ZlibDecoder;
use self::flate2::write::ZlibEncoder;
use self::flate2::Compression;
use self::image::DynamicImage;
use self::sha1::Sha1;
pub const DEFAULT_CACHE_DIR: &'static str = "./.hash_cache"; pub const DEFAULT_CACHE_DIR: &'static str = "./.hash_cache";
const CACHED_IMAGE_EXT: &'static str = "png"; const CACHED_IMAGE_EXT: &'static str = "png";
const CACHED_MATRIX_EXT: &'static str = "dft"; const CACHED_MATRIX_EXT: &'static str = "dft";
@ -36,7 +38,9 @@ struct CacheMetadata {
impl Default for CacheMetadata { impl Default for CacheMetadata {
fn default() -> CacheMetadata { fn default() -> CacheMetadata {
CacheMetadata { cache_version: CACHE_VERSION }
CacheMetadata {
cache_version: CACHE_VERSION,
}
} }
} }
@ -94,12 +98,10 @@ impl<'a> Cache<'a> {
if current_metadata != loaded_metadata { if current_metadata != loaded_metadata {
// If they don't wipe the cache to start new // If they don't wipe the cache to start new
match remove_dir_all(self.cache_dir) { match remove_dir_all(self.cache_dir) {
Ok(_) => {
match create_dir_all(self.cache_dir) {
Ok(_) => (),
Err(e) => println!("Error: {}", e),
}
}
Ok(_) => match create_dir_all(self.cache_dir) {
Ok(_) => (),
Err(e) => println!("Error: {}", e),
},
Err(e) => println!("Error: {}", e), Err(e) => println!("Error: {}", e),
}; };
}; };
@ -148,22 +150,26 @@ impl<'a> Cache<'a> {
/** /**
* Put an image buffer in the cache * Put an image buffer in the cache
*/ */
pub fn put_image_in_cache(&self,
path: &Path,
size: u32,
image: &DynamicImage)
-> Result<bool, Error> {
pub fn put_image_in_cache(
&self,
path: &Path,
size: u32,
image: &DynamicImage,
) -> Result<bool, Error> {
let hash = self.get_file_hash(&path); let hash = self.get_file_hash(&path);
match hash { match hash {
Ok(sha1) => { Ok(sha1) => {
let cache_path_str = format!("{}/image/{}x{}/{}/{}.{}",
self.cache_dir,
size,
size,
&sha1[..10],
sha1,
CACHED_IMAGE_EXT);
let cache_dir_str = format!("{}/image/{}x{}/{}", self.cache_dir, size, size, &sha1[..10]);
let cache_path_str = format!(
"{}/image/{}x{}/{}/{}.{}",
self.cache_dir,
size,
size,
&sha1[..10],
sha1,
CACHED_IMAGE_EXT
);
let cache_dir_str =
format!("{}/image/{}x{}/{}", self.cache_dir, size, size, &sha1[..10]);
// 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(_) => {
@ -196,22 +202,21 @@ impl<'a> Cache<'a> {
/** /**
* Get an image buffer out of the cache * Get an image buffer out of the cache
*/ */
pub fn get_image_from_cache(&self,
path: &Path,
size: u32)
-> Option<DynamicImage> {
pub fn get_image_from_cache(&self, path: &Path, size: u32) -> Option<DynamicImage> {
if self.use_cache { if self.use_cache {
let hash = self.get_file_hash(&path); let hash = self.get_file_hash(&path);
match hash { match hash {
Ok(sha1) => { Ok(sha1) => {
// Check if the file exists in the cache // Check if the file exists in the cache
let cache_path_str = format!("{}/image/{}x{}/{}/{}.{}",
self.cache_dir,
size,
size,
&sha1[..10],
sha1,
CACHED_IMAGE_EXT);
let cache_path_str = format!(
"{}/image/{}x{}/{}/{}.{}",
self.cache_dir,
size,
size,
&sha1[..10],
sha1,
CACHED_IMAGE_EXT
);
let cached_path = Path::new(&cache_path_str); let cached_path = Path::new(&cache_path_str);
// Try to open, if it does, then we can read the image in // Try to open, if it does, then we can read the image in
match File::open(&cached_path) { match File::open(&cached_path) {
@ -237,35 +242,44 @@ impl<'a> Cache<'a> {
/** /**
* Expects a slice of slices that represents lines in the file * Expects a slice of slices that represents lines in the file
*/ */
pub fn put_matrix_in_cache(&self,
path: &Path,
size: u32,
file_contents: &Vec<Vec<f64>>)
-> Result<bool, Error> {
pub fn put_matrix_in_cache(
&self,
path: &Path,
size: u32,
file_contents: &Vec<Vec<f64>>,
) -> Result<bool, Error> {
let hash = self.get_file_hash(&path); let hash = self.get_file_hash(&path);
match hash { match hash {
Ok(sha1) => { Ok(sha1) => {
let cache_path_str = format!("{}/matrix/{}x{}/{}/{}.{}",
self.cache_dir,
size,
size,
&sha1[..10],
sha1,
CACHED_MATRIX_EXT);
let cache_dir_str = format!("{}/matrix/{}x{}/{}", self.cache_dir, size, size, &sha1[..10]);
let cache_path_str = format!(
"{}/matrix/{}x{}/{}/{}.{}",
self.cache_dir,
size,
size,
&sha1[..10],
sha1,
CACHED_MATRIX_EXT
);
let cache_dir_str = format!(
"{}/matrix/{}x{}/{}",
self.cache_dir,
size,
size,
&sha1[..10]
);
match create_dir_all(cache_dir_str) { match create_dir_all(cache_dir_str) {
Ok(_) => { Ok(_) => {
let cached_path = Path::new(&cache_path_str); let cached_path = Path::new(&cache_path_str);
// Save the file into the cache // Save the file into the cache
match File::create(&cached_path) { match File::create(&cached_path) {
Ok(mut file) => { Ok(mut file) => {
let mut compressor = ZlibEncoder::new(Vec::new(),
Compression::default());
let mut compressor =
ZlibEncoder::new(Vec::new(), Compression::default());
for row in file_contents { for row in file_contents {
let mut row_str = let mut row_str =
row.iter()
.fold(String::new(),
|acc, &item| acc + &format!("{},", item));
row.iter().fold(String::new(), |acc, &item| {
acc + &format!("{},", item)
});
// remove the last comma // remove the last comma
let desire_len = row_str.len() - 1; let desire_len = row_str.len() - 1;
row_str.truncate(desire_len); row_str.truncate(desire_len);
@ -307,13 +321,15 @@ impl<'a> Cache<'a> {
match hash { match hash {
Ok(sha1) => { Ok(sha1) => {
// Check if the file exists in the cache // Check if the file exists in the cache
let cache_path_str = format!("{}/matrix/{}x{}/{}/{}.{}",
self.cache_dir,
size,
size,
&sha1[..10],
sha1,
CACHED_MATRIX_EXT);
let cache_path_str = format!(
"{}/matrix/{}x{}/{}/{}.{}",
self.cache_dir,
size,
size,
&sha1[..10],
sha1,
CACHED_MATRIX_EXT
);
let cached_path = Path::new(&cache_path_str); let cached_path = Path::new(&cache_path_str);
// Try to open, if it does, then we can read the image in // Try to open, if it does, then we can read the image in
match File::open(&cached_path) { match File::open(&cached_path) {
@ -332,9 +348,7 @@ impl<'a> Cache<'a> {
.trim() .trim()
.split("\n") .split("\n")
.map(|line| { .map(|line| {
line.split(",")
.map(|f| f64::from_str(f).unwrap())
.collect()
line.split(",").map(|f| f64::from_str(f).unwrap()).collect()
}) })
.collect(); .collect();

16
src/hash/ahash.rs

@ -9,8 +9,8 @@ use std::path::Path;
use cache::Cache; use cache::Cache;
use super::{HashType, PerceptualHash, Precision, PreparedImage};
use super::prepare_image; use super::prepare_image;
use super::{HashType, PerceptualHash, Precision, PreparedImage};
use self::image::{GenericImage, GenericImageView}; use self::image::{GenericImage, GenericImageView};
@ -28,12 +28,12 @@ impl<'a> AHash<'a> {
impl<'a> PerceptualHash for AHash<'a> { impl<'a> PerceptualHash for AHash<'a> {
/** /**
* Calculate the ahash of the provided prepared image.
*
* # Returns
*
* A u64 representing the value of the hash
*/
* Calculate the ahash of the provided prepared image.
*
* # Returns
*
* A u64 representing the value of the hash
*/
fn get_hash(&self, _: &Option<Cache>) -> u64 { fn get_hash(&self, _: &Option<Cache>) -> u64 {
match self.prepared_image.image { match self.prepared_image.image {
Some(ref image) => { Some(ref image) => {
@ -52,7 +52,7 @@ impl<'a> PerceptualHash for AHash<'a> {
for (_, _, pixel) in image.pixels() { for (_, _, pixel) in image.pixels() {
if pixel.0[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 {
hash |= 0; hash |= 0;
// println!("Pixel {} is < {} therefore {:b}", pixel_sum, mean, hash); // println!("Pixel {} is < {} therefore {:b}", pixel_sum, mean, hash);

2
src/hash/dhash.rs

@ -8,8 +8,8 @@ use std::path::Path;
use cache::Cache; use cache::Cache;
use super::{HashType, PerceptualHash, Precision, PreparedImage};
use super::prepare_image; use super::prepare_image;
use super::{HashType, PerceptualHash, Precision, PreparedImage};
use self::image::{GenericImage, GenericImageView}; use self::image::{GenericImage, GenericImageView};

62
src/hash/mod.rs

@ -6,11 +6,11 @@
extern crate dft; extern crate dft;
extern crate image; extern crate image;
use cache::Cache;
use self::image::FilterType; use self::image::FilterType;
use cache::Cache;
use std::f64; use std::f64;
use std::path::Path;
use std::fmt; use std::fmt;
use std::path::Path;
mod ahash; mod ahash;
mod dhash; mod dhash;
@ -59,13 +59,14 @@ pub struct PerceptualHashes<'a> {
impl<'a> PerceptualHashes<'a> { impl<'a> PerceptualHashes<'a> {
pub fn similar(&self, other: &'a PerceptualHashes<'a>) -> bool { pub fn similar(&self, other: &'a PerceptualHashes<'a>) -> bool {
if self.orig_path != other.orig_path &&
calculate_hamming_distance(self.ahash, other.ahash) <=
HAMMING_DISTANCE_SIMILARITY_LIMIT &&
calculate_hamming_distance(self.dhash, other.dhash) <=
HAMMING_DISTANCE_SIMILARITY_LIMIT &&
calculate_hamming_distance(self.phash, other.phash) <=
HAMMING_DISTANCE_SIMILARITY_LIMIT {
if self.orig_path != other.orig_path
&& calculate_hamming_distance(self.ahash, other.ahash)
<= HAMMING_DISTANCE_SIMILARITY_LIMIT
&& calculate_hamming_distance(self.dhash, other.dhash)
<= HAMMING_DISTANCE_SIMILARITY_LIMIT
&& calculate_hamming_distance(self.phash, other.phash)
<= HAMMING_DISTANCE_SIMILARITY_LIMIT
{
true true
} else { } else {
false false
@ -113,7 +114,7 @@ impl fmt::Display for HashType {
match *self { match *self {
HashType::AHash => write!(f, "AHash"), HashType::AHash => write!(f, "AHash"),
HashType::DHash => write!(f, "DHash"), HashType::DHash => write!(f, "DHash"),
HashType::PHash => write!(f, "PHash")
HashType::PHash => write!(f, "PHash"),
} }
} }
} }
@ -140,11 +141,12 @@ pub trait PerceptualHash {
* A PreparedImage struct with the required information for performing hashing * A PreparedImage struct with the required information for performing hashing
* *
*/ */
pub fn prepare_image<'a>(path: &'a Path,
hash_type: &HashType,
precision: &Precision,
cache: &Option<Cache>)
-> PreparedImage<'a> {
pub fn prepare_image<'a>(
path: &'a Path,
hash_type: &HashType,
precision: &Precision,
cache: &Option<Cache>,
) -> PreparedImage<'a> {
let image_path = path.to_str().unwrap(); let image_path = path.to_str().unwrap();
let size: u32 = match *hash_type { let size: u32 = match *hash_type {
HashType::PHash => precision.get_size() * 4, HashType::PHash => precision.get_size() * 4,
@ -154,12 +156,10 @@ pub fn prepare_image<'a>(path: &'a Path,
match *cache { match *cache {
Some(ref c) => { Some(ref c) => {
match c.get_image_from_cache(&path, size) { match c.get_image_from_cache(&path, size) {
Some(image) => {
PreparedImage {
orig_path: &*image_path,
image: Some(image),
}
}
Some(image) => PreparedImage {
orig_path: &*image_path,
image: Some(image),
},
None => { None => {
let processed_image = process_image(&image_path, size); let processed_image = process_image(&image_path, size);
// Oh, and save it in a cache // Oh, and save it in a cache
@ -205,11 +205,12 @@ fn process_image<'a>(image_path: &'a str, size: u32) -> PreparedImage<'a> {
/** /**
* Get a specific HashType hash * Get a specific HashType hash
*/ */
pub fn get_perceptual_hash<'a>(path: &'a Path,
precision: &Precision,
hash_type: &HashType,
cache: &Option<Cache>)
-> u64 {
pub fn get_perceptual_hash<'a>(
path: &'a Path,
precision: &Precision,
hash_type: &HashType,
cache: &Option<Cache>,
) -> u64 {
match *hash_type { match *hash_type {
HashType::AHash => ahash::AHash::new(&path, &precision, &cache).get_hash(&cache), HashType::AHash => ahash::AHash::new(&path, &precision, &cache).get_hash(&cache),
HashType::DHash => dhash::DHash::new(&path, &precision, &cache).get_hash(&cache), HashType::DHash => dhash::DHash::new(&path, &precision, &cache).get_hash(&cache),
@ -220,10 +221,11 @@ pub fn get_perceptual_hash<'a>(path: &'a Path,
/** /**
* Get all perceptual hashes for an image * Get all perceptual hashes for an image
*/ */
pub fn get_perceptual_hashes<'a>(path: &'a Path,
precision: &Precision,
cache: &Option<Cache>)
-> PerceptualHashes<'a> {
pub fn get_perceptual_hashes<'a>(
path: &'a Path,
precision: &Precision,
cache: &Option<Cache>,
) -> PerceptualHashes<'a> {
let image_path = path.to_str().unwrap(); let image_path = path.to_str().unwrap();
let ahash = ahash::AHash::new(&path, &precision, &cache).get_hash(&cache); let ahash = ahash::AHash::new(&path, &precision, &cache).get_hash(&cache);
let dhash = dhash::DHash::new(&path, &precision, &cache).get_hash(&cache); let dhash = dhash::DHash::new(&path, &precision, &cache).get_hash(&cache);

21
src/hash/phash.rs

@ -8,11 +8,11 @@ use std::path::Path;
use cache::Cache; use cache::Cache;
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 super::{HashType, PerceptualHash, Precision, PreparedImage};
use self::image::{DynamicImage, GenericImage, GenericImageView}; use self::image::{DynamicImage, GenericImage, GenericImageView};
@ -48,14 +48,18 @@ impl<'a> PerceptualHash for PHash<'a> {
// Atleast compared to opening and processing the images // Atleast compared to opening and processing the images
let data_matrix: Vec<Vec<f64>> = match *cache { let data_matrix: Vec<Vec<f64>> = match *cache {
Some(ref c) => { Some(ref c) => {
match c.get_matrix_from_cache(&Path::new(self.prepared_image.orig_path),
width as u32) {
match c.get_matrix_from_cache(
&Path::new(self.prepared_image.orig_path),
width as u32,
) {
Some(matrix) => matrix, Some(matrix) => matrix,
None => { None => {
let matrix = create_data_matrix(width, height, &image); let matrix = create_data_matrix(width, height, &image);
match c.put_matrix_in_cache(&Path::new(self.prepared_image.orig_path),
width as u32,
&matrix) {
match c.put_matrix_in_cache(
&Path::new(self.prepared_image.orig_path),
width as u32,
&matrix,
) {
Ok(_) => {} Ok(_) => {}
Err(e) => println!("Unable to store matrix in cache. {}", e), Err(e) => println!("Unable to store matrix in cache. {}", e),
}; };
@ -100,10 +104,7 @@ impl<'a> PerceptualHash for PHash<'a> {
} }
} }
fn create_data_matrix(width: u32,
height: u32,
image: &DynamicImage)
-> Vec<Vec<f64>> {
fn create_data_matrix(width: u32, height: u32, image: &DynamicImage) -> 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 as usize { for x in 0..width as usize {

383
src/lib.rs

@ -17,8 +17,8 @@ use std::path::Path;
use cache::Cache; use cache::Cache;
pub mod hash;
pub mod cache; pub mod cache;
pub mod hash;
#[repr(C)] #[repr(C)]
pub struct PIHash<'a> { pub struct PIHash<'a> {
@ -49,40 +49,44 @@ impl<'a> PIHash<'a> {
} }
} }
pub fn get_perceptual_hash(&self,
path: &Path,
precision: &hash::Precision,
hash_type: &hash::HashType)
-> u64 {
pub fn get_perceptual_hash(
&self,
path: &Path,
precision: &hash::Precision,
hash_type: &hash::HashType,
) -> u64 {
hash::get_perceptual_hash(&path, &precision, &hash_type, &self.cache) hash::get_perceptual_hash(&path, &precision, &hash_type, &self.cache)
} }
pub fn get_phashes(&self, path: &'a Path) -> hash::PerceptualHashes { pub fn get_phashes(&self, path: &'a Path) -> hash::PerceptualHashes {
hash::get_perceptual_hashes(&path,
&hash::Precision::Medium,
&self.cache)
hash::get_perceptual_hashes(&path, &hash::Precision::Medium, &self.cache)
} }
pub fn get_ahash(&self, path: &Path) -> u64 { pub fn get_ahash(&self, path: &Path) -> u64 {
hash::get_perceptual_hash(&path,
&hash::Precision::Medium,
&hash::HashType::AHash,
&self.cache)
hash::get_perceptual_hash(
&path,
&hash::Precision::Medium,
&hash::HashType::AHash,
&self.cache,
)
} }
pub fn get_dhash(&self, path: &Path) -> u64 { pub fn get_dhash(&self, path: &Path) -> u64 {
hash::get_perceptual_hash(&path,
&hash::Precision::Medium,
&hash::HashType::DHash,
&self.cache)
hash::get_perceptual_hash(
&path,
&hash::Precision::Medium,
&hash::HashType::DHash,
&self.cache,
)
} }
pub fn get_phash(&self, path: &Path) -> u64 { pub fn get_phash(&self, path: &Path) -> u64 {
hash::get_perceptual_hash(&path,
&hash::Precision::Medium,
&hash::HashType::PHash,
&self.cache)
hash::get_perceptual_hash(
&path,
&hash::Precision::Medium,
&hash::HashType::PHash,
&self.cache,
)
} }
} }
@ -125,9 +129,11 @@ pub extern "C" fn ext_get_ahash(lib: &PIHash, path_char: *const libc::c_char) ->
let image_path = match path_str.to_str() { let image_path = match path_str.to_str() {
Ok(result) => result, Ok(result) => result,
Err(e) => { Err(e) => {
println!("Error: {}. Unable to parse '{}'",
e,
to_hex_string(path_str.to_bytes()));
println!(
"Error: {}. Unable to parse '{}'",
e,
to_hex_string(path_str.to_bytes())
);
panic!("Unable to parse path") panic!("Unable to parse path")
} }
}; };
@ -143,9 +149,11 @@ pub extern "C" fn ext_get_dhash(lib: &PIHash, path_char: *const libc::c_char) ->
let image_path = match path_str.to_str() { let image_path = match path_str.to_str() {
Ok(result) => result, Ok(result) => result,
Err(e) => { Err(e) => {
println!("Error: {}. Unable to parse '{}'",
e,
to_hex_string(path_str.to_bytes()));
println!(
"Error: {}. Unable to parse '{}'",
e,
to_hex_string(path_str.to_bytes())
);
panic!("Unable to parse path") panic!("Unable to parse path")
} }
}; };
@ -161,9 +169,11 @@ pub extern "C" fn ext_get_phash(lib: &PIHash, path_char: *const libc::c_char) ->
let image_path = match path_str.to_str() { let image_path = match path_str.to_str() {
Ok(result) => result, Ok(result) => result,
Err(e) => { Err(e) => {
println!("Error: {}. Unable to parse '{}'",
e,
to_hex_string(path_str.to_bytes()));
println!(
"Error: {}. Unable to parse '{}'",
e,
to_hex_string(path_str.to_bytes())
);
panic!("Unable to parse path") panic!("Unable to parse path")
} }
}; };
@ -186,9 +196,11 @@ pub extern "C" fn ext_get_phashes(lib: &PIHash, path_char: *const libc::c_char)
let image_path = match path_str.to_str() { let image_path = match path_str.to_str() {
Ok(result) => result, Ok(result) => result,
Err(e) => { Err(e) => {
println!("Error: {}. Unable to parse '{}'",
e,
to_hex_string(path_str.to_bytes()));
println!(
"Error: {}. Unable to parse '{}'",
e,
to_hex_string(path_str.to_bytes())
);
panic!("Unable to parse path") panic!("Unable to parse path")
} }
}; };
@ -209,7 +221,6 @@ pub extern "C" fn ext_free_phashes(raw_phashes: *const libc::c_void) {
} }
} }
fn to_hex_string(bytes: &[u8]) -> String { fn to_hex_string(bytes: &[u8]) -> String {
println!("length: {}", bytes.len()); println!("length: {}", bytes.len());
let mut strs: Vec<String> = Vec::new(); let mut strs: Vec<String> = Vec::new();
@ -230,9 +241,9 @@ mod tests {
use cache; use cache;
use hash; use hash;
use super::PIHash;
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
use super::test::Bencher; use super::test::Bencher;
use super::PIHash;
#[test] #[test]
fn test_can_get_test_images() { fn test_can_get_test_images() {
@ -263,21 +274,25 @@ mod tests {
* Updated test function. Assumes 3 images to a set and no hamming distances. * Updated test function. Assumes 3 images to a set and no hamming distances.
* We don't need to confirm that the hamming distance calculation works in these tests. * We don't need to confirm that the hamming distance calculation works in these tests.
*/ */
fn test_imageset_hash(hash_type: hash::HashType,
hash_precision: hash::Precision,
max_hamming_distance: u64,
image_paths: [&Path; 3],
image_hashes: [u64; 3],
lib: &PIHash) {
fn test_imageset_hash(
hash_type: hash::HashType,
hash_precision: hash::Precision,
max_hamming_distance: u64,
image_paths: [&Path; 3],
image_hashes: [u64; 3],
lib: &PIHash,
) {
let mut hashes: [u64; 3] = [0; 3]; let mut hashes: [u64; 3] = [0; 3];
for index in 0..image_paths.len() { for index in 0..image_paths.len() {
let image_path = image_paths[index]; let image_path = image_paths[index];
let calculated_hash = lib.get_perceptual_hash(&image_path, &hash_precision, &hash_type); let calculated_hash = lib.get_perceptual_hash(&image_path, &hash_precision, &hash_type);
println!("[{}] Image hashes for [{}] expected: [{}] actual: [{}]",
hash_type,
image_path.to_str().unwrap(),
image_hashes[index],
calculated_hash);
println!(
"[{}] Image hashes for [{}] expected: [{}] actual: [{}]",
hash_type,
image_path.to_str().unwrap(),
image_hashes[index],
calculated_hash
);
assert_eq!(calculated_hash, image_hashes[index]); assert_eq!(calculated_hash, image_hashes[index]);
hashes[index] = calculated_hash; hashes[index] = calculated_hash;
} }
@ -308,65 +323,74 @@ mod tests {
let sample_01_images: [&Path; 3] = [ let sample_01_images: [&Path; 3] = [
&Path::new("./test_images/sample_01_large.jpg"), &Path::new("./test_images/sample_01_large.jpg"),
&Path::new("./test_images/sample_01_medium.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,
sample_01_images,
sample_01_hashes,
&lib);
&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,
sample_01_images,
sample_01_hashes,
&lib,
);
// Sample_02 tests // Sample_02 tests
let sample_02_images: [&Path; 3] = [ let sample_02_images: [&Path; 3] = [
&Path::new("./test_images/sample_02_large.jpg"), &Path::new("./test_images/sample_02_large.jpg"),
&Path::new("./test_images/sample_02_medium.jpg"), &Path::new("./test_images/sample_02_medium.jpg"),
&Path::new("./test_images/sample_02_small.jpg")];
&Path::new("./test_images/sample_02_small.jpg"),
];
let sample_02_hashes: [u64; 3] = [ let sample_02_hashes: [u64; 3] = [
18446744073441116160, 18446744073441116160,
18446744073441116160, 18446744073441116160,
18446744073441116160];
test_imageset_hash(hash::HashType::AHash,
hash::Precision::Medium,
3u64,
sample_02_images,
sample_02_hashes,
&lib);
18446744073441116160,
];
test_imageset_hash(
hash::HashType::AHash,
hash::Precision::Medium,
3u64,
sample_02_images,
sample_02_hashes,
&lib,
);
// Sample_03 tests // Sample_03 tests
let sample_03_images: [&Path; 3] = [ let sample_03_images: [&Path; 3] = [
&Path::new("./test_images/sample_03_large.jpg"), &Path::new("./test_images/sample_03_large.jpg"),
&Path::new("./test_images/sample_03_medium.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,
sample_03_images,
sample_03_hashes,
&lib);
&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,
sample_03_images,
sample_03_hashes,
&lib,
);
// Sample_04 tests // Sample_04 tests
let sample_04_images: [&Path; 3] = [ let sample_04_images: [&Path; 3] = [
&Path::new("./test_images/sample_04_large.jpg"), &Path::new("./test_images/sample_04_large.jpg"),
&Path::new("./test_images/sample_04_medium.jpg"), &Path::new("./test_images/sample_04_medium.jpg"),
&Path::new("./test_images/sample_04_small.jpg")];
&Path::new("./test_images/sample_04_small.jpg"),
];
let sample_04_hashes: [u64; 3] = [ let sample_04_hashes: [u64; 3] = [
18446460933225054208, 18446460933225054208,
18446460933225054208, 18446460933225054208,
18446460933225054208];
test_imageset_hash(hash::HashType::AHash,
hash::Precision::Medium,
0u64,
sample_04_images,
sample_04_hashes,
&lib);
18446460933225054208,
];
test_imageset_hash(
hash::HashType::AHash,
hash::Precision::Medium,
0u64,
sample_04_images,
sample_04_hashes,
&lib,
);
// Clean_Cache // Clean_Cache
// super::teardown(); // super::teardown();
@ -381,65 +405,78 @@ mod tests {
let sample_01_images: [&Path; 3] = [ let sample_01_images: [&Path; 3] = [
&Path::new("./test_images/sample_01_large.jpg"), &Path::new("./test_images/sample_01_large.jpg"),
&Path::new("./test_images/sample_01_medium.jpg"), &Path::new("./test_images/sample_01_medium.jpg"),
&Path::new("./test_images/sample_01_small.jpg")];
&Path::new("./test_images/sample_01_small.jpg"),
];
let sample_01_hashes: [u64; 3] = [ let sample_01_hashes: [u64; 3] = [
3404580580803739582, 3404580580803739582,
3404580580803739582, 3404580580803739582,
3404580580803739582];
test_imageset_hash(hash::HashType::DHash,
hash::Precision::Medium,
0u64,
sample_01_images,
sample_01_hashes,
&lib);
3404580580803739582,
];
test_imageset_hash(
hash::HashType::DHash,
hash::Precision::Medium,
0u64,
sample_01_images,
sample_01_hashes,
&lib,
);
// Sample_02 tests // Sample_02 tests
let sample_02_images: [&Path; 3] = [ let sample_02_images: [&Path; 3] = [
&Path::new("./test_images/sample_02_large.jpg"), &Path::new("./test_images/sample_02_large.jpg"),
&Path::new("./test_images/sample_02_medium.jpg"), &Path::new("./test_images/sample_02_medium.jpg"),
&Path::new("./test_images/sample_02_small.jpg")];
&Path::new("./test_images/sample_02_small.jpg"),
];
let sample_02_hashes: [u64; 3] = [ let sample_02_hashes: [u64; 3] = [
14726771606135242753, 14726771606135242753,
14726771606135242753, 14726771606135242753,
14726771606135242753];
test_imageset_hash(hash::HashType::DHash,
hash::Precision::Medium,
0u64,
sample_02_images,
sample_02_hashes,
&lib);
14726771606135242753,
];
test_imageset_hash(
hash::HashType::DHash,
hash::Precision::Medium,
0u64,
sample_02_images,
sample_02_hashes,
&lib,
);
// Sample_03 tests // Sample_03 tests
let sample_03_images: [&Path; 3] = [ let sample_03_images: [&Path; 3] = [
&Path::new("./test_images/sample_03_large.jpg"), &Path::new("./test_images/sample_03_large.jpg"),
&Path::new("./test_images/sample_03_medium.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,
sample_03_images,
sample_03_hashes,
&lib);
&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,
sample_03_images,
sample_03_hashes,
&lib,
);
// Sample_04 tests // Sample_04 tests
let sample_04_images: [&Path; 3] = [ let sample_04_images: [&Path; 3] = [
&Path::new("./test_images/sample_04_large.jpg"), &Path::new("./test_images/sample_04_large.jpg"),
&Path::new("./test_images/sample_04_medium.jpg"), &Path::new("./test_images/sample_04_medium.jpg"),
&Path::new("./test_images/sample_04_small.jpg")];
&Path::new("./test_images/sample_04_small.jpg"),
];
let sample_04_hashes: [u64; 3] = [ let sample_04_hashes: [u64; 3] = [
18374262188442386433, 18374262188442386433,
18374262188442386433, 18374262188442386433,
18374262188442386433];
test_imageset_hash(hash::HashType::DHash,
hash::Precision::Medium,
1u64,
sample_04_images,
sample_04_hashes,
&lib);
18374262188442386433,
];
test_imageset_hash(
hash::HashType::DHash,
hash::Precision::Medium,
1u64,
sample_04_images,
sample_04_hashes,
&lib,
);
// Clean_Cache // Clean_Cache
// super::teardown(); // super::teardown();
@ -454,65 +491,77 @@ mod tests {
let sample_01_images: [&Path; 3] = [ let sample_01_images: [&Path; 3] = [
&Path::new("./test_images/sample_01_large.jpg"), &Path::new("./test_images/sample_01_large.jpg"),
&Path::new("./test_images/sample_01_medium.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,
sample_01_images,
sample_01_hashes,
&lib);
&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,
sample_01_images,
sample_01_hashes,
&lib,
);
// Sample_02 tests // Sample_02 tests
let sample_02_images: [&Path; 3] = [ let sample_02_images: [&Path; 3] = [
&Path::new("./test_images/sample_02_large.jpg"), &Path::new("./test_images/sample_02_large.jpg"),
&Path::new("./test_images/sample_02_medium.jpg"), &Path::new("./test_images/sample_02_medium.jpg"),
&Path::new("./test_images/sample_02_small.jpg")];
&Path::new("./test_images/sample_02_small.jpg"),
];
let sample_02_hashes: [u64; 3] = [ let sample_02_hashes: [u64; 3] = [
5332332327550844928, 5332332327550844928,
5332332327550844928, 5332332327550844928,
5332332327550844928];
test_imageset_hash(hash::HashType::PHash,
hash::Precision::Medium,
1u64,
sample_02_images,
sample_02_hashes,
&lib);
5332332327550844928,
];
test_imageset_hash(
hash::HashType::PHash,
hash::Precision::Medium,
1u64,
sample_02_images,
sample_02_hashes,
&lib,
);
// Sample_03 tests // Sample_03 tests
let sample_03_images: [&Path; 3] = [ let sample_03_images: [&Path; 3] = [
&Path::new("./test_images/sample_03_large.jpg"), &Path::new("./test_images/sample_03_large.jpg"),
&Path::new("./test_images/sample_03_medium.jpg"), &Path::new("./test_images/sample_03_medium.jpg"),
&Path::new("./test_images/sample_03_small.jpg")];
&Path::new("./test_images/sample_03_small.jpg"),
];
let sample_03_hashes: [u64; 3] = [ let sample_03_hashes: [u64; 3] = [
6917529027641081856, 6917529027641081856,
6917529027641081856, 6917529027641081856,
6917529027641081856];
test_imageset_hash(hash::HashType::PHash,
hash::Precision::Medium,
0u64,
sample_03_images,
sample_03_hashes,
&lib);
6917529027641081856,
];
test_imageset_hash(
hash::HashType::PHash,
hash::Precision::Medium,
0u64,
sample_03_images,
sample_03_hashes,
&lib,
);
// Sample_04 tests // Sample_04 tests
let sample_04_images: [&Path; 3] = [ let sample_04_images: [&Path; 3] = [
&Path::new("./test_images/sample_04_large.jpg"), &Path::new("./test_images/sample_04_large.jpg"),
&Path::new("./test_images/sample_04_medium.jpg"), &Path::new("./test_images/sample_04_medium.jpg"),
&Path::new("./test_images/sample_04_small.jpg")];
&Path::new("./test_images/sample_04_small.jpg"),
];
let sample_04_hashes: [u64; 3] = [ let sample_04_hashes: [u64; 3] = [
10997931646002397184, 10997931646002397184,
10997931646002397184, 10997931646002397184,
10997931646002397184];
test_imageset_hash(hash::HashType::PHash,
hash::Precision::Medium,
3u64,
sample_04_images,
sample_04_hashes,
&lib);
10997931646002397184,
];
test_imageset_hash(
hash::HashType::PHash,
hash::Precision::Medium,
3u64,
sample_04_images,
sample_04_hashes,
&lib,
);
// Clean_Cache // Clean_Cache
// super::teardown(); // super::teardown();
@ -526,15 +575,19 @@ mod tests {
// Setup the caches to make sure we're good to properly bench // Setup the caches to make sure we're good to properly bench
// All phashes so that the matricies are pulled from cache as well // All phashes so that the matricies are pulled from cache as well
lib.get_perceptual_hash(&Path::new("./test_images/sample_01_large.jpg"),
&hash::Precision::Medium,
&hash::HashType::PHash);
lib.get_perceptual_hash(
&Path::new("./test_images/sample_01_large.jpg"),
&hash::Precision::Medium,
&hash::HashType::PHash,
);
bench.iter(|| { bench.iter(|| {
// Sample_01 Bench // Sample_01 Bench
lib.get_perceptual_hash(&Path::new("./test_images/sample_01_large.jpg"),
&hash::Precision::Medium,
&hash::HashType::PHash);
lib.get_perceptual_hash(
&Path::new("./test_images/sample_01_large.jpg"),
&hash::Precision::Medium,
&hash::HashType::PHash,
);
}) })
} }
@ -546,9 +599,11 @@ mod tests {
bench.iter(|| { bench.iter(|| {
// Sample_01 Bench // Sample_01 Bench
lib.get_perceptual_hash(&Path::new("./test_images/sample_01_large.jpg"),
&hash::Precision::Medium,
&hash::HashType::PHash);
lib.get_perceptual_hash(
&Path::new("./test_images/sample_01_large.jpg"),
&hash::Precision::Medium,
&hash::HashType::PHash,
);
}) })
} }
} }

28
src/main.rs

@ -65,10 +65,11 @@ fn main() {
let mut comparison_hashes: Vec<pihash::hash::PerceptualHashes> = Vec::new(); let mut comparison_hashes: Vec<pihash::hash::PerceptualHashes> = Vec::new();
for index in 0..args.arg_comparison.len() { for index in 0..args.arg_comparison.len() {
comparison_hashes
.push(get_requested_perceptual_hashes(&lib,
&Path::new(&args.arg_comparison[index]),
&args));
comparison_hashes.push(get_requested_perceptual_hashes(
&lib,
&Path::new(&args.arg_comparison[index]),
&args,
));
} }
let mut similar_images: Vec<&str> = Vec::new(); let mut similar_images: Vec<&str> = Vec::new();
@ -94,23 +95,22 @@ ahash: {}
dhash: {} dhash: {}
phash: {} phash: {}
"#, "#,
hashes.orig_path,
hashes.ahash,
hashes.dhash,
hashes.phash);
hashes.orig_path, hashes.ahash, hashes.dhash, hashes.phash
);
println!("{}", hash_result); println!("{}", hash_result);
} }
} }
fn flags_get_all_perceptual_hashes(args: &Args) -> bool { fn flags_get_all_perceptual_hashes(args: &Args) -> bool {
(args.flag_ahash && args.flag_dhash && args.flag_phash) ||
(!args.flag_ahash && !args.flag_dhash && !args.flag_phash)
(args.flag_ahash && args.flag_dhash && args.flag_phash)
|| (!args.flag_ahash && !args.flag_dhash && !args.flag_phash)
} }
fn get_requested_perceptual_hashes<'a>(lib: &pihash::PIHash,
image_path: &'a Path,
args: &Args)
-> pihash::hash::PerceptualHashes<'a> {
fn get_requested_perceptual_hashes<'a>(
lib: &pihash::PIHash,
image_path: &'a Path,
args: &Args,
) -> pihash::hash::PerceptualHashes<'a> {
let ahash = if args.flag_ahash || flags_get_all_perceptual_hashes(&args) { let ahash = if args.flag_ahash || flags_get_all_perceptual_hashes(&args) {
lib.get_ahash(&image_path) lib.get_ahash(&image_path)
} else { } else {

Loading…
Cancel
Save