Drew Short 8 years ago
parent
commit
8773a5a323
  1. 1
      .gitignore
  2. 4
      .gitlab-ci.yml
  3. 2
      Cargo.toml
  4. 2
      README.md
  5. 71
      src/cache.rs
  6. 6
      src/hash.rs

1
.gitignore

@ -1,5 +1,6 @@
# System Files
.directory
*.swp
# Compiled files
*.o

4
.gitlab-ci.yml

@ -5,7 +5,9 @@ stages:
test:
stage: test
script:
- cargo test --release
- rustc -V
- cargo -V
- cargo test
only:
- master
tags:

2
Cargo.toml

@ -1,6 +1,6 @@
[package]
name = "pihash"
version = "0.1.1"
version = "0.2.0"
authors = ["Drew Short <warrick@sothr.com>"]
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/"

2
README.md

@ -6,6 +6,8 @@
The goal of this library is to offer a utility for calculating perceptual hashes of images for the purpose of comparing images for similarity
- [ ] Add DCT in addition to DFT and some additional wrappings around the perceptual hashing.
# Examples
To Be Added

71
src/cache.rs

@ -10,7 +10,7 @@ use self::image::ImageBuffer;
use self::sha1::Sha1;
use std::path::Path;
use std::fs::{File, create_dir_all, remove_dir_all};
use std::io::{Read, Error};
use std::io::{Read, Error, Write};
use std::option::Option;
use std::result::Result;
@ -42,7 +42,7 @@ fn get_file_hash(path: &Path) -> Result<String, Error> {
/**
* Put an image buffer in the cache
*/
pub fn put_in_cache(path: &Path, size: u32, image: &ImageBuffer<image::Luma<u8>, Vec<u8>>) {
pub fn put_image_in_cache(path: &Path, size: u32, image: &ImageBuffer<image::Luma<u8>, Vec<u8>>) {
let hash = get_file_hash(&path);
match hash {
Ok(sha1) => {
@ -58,10 +58,39 @@ pub fn put_in_cache(path: &Path, size: u32, image: &ImageBuffer<image::Luma<u8>,
}
}
/**
* Expects a slice of slices that represents lines in the file
*/
pub fn put_matrix_in_cache(path: &Path, size: u32, extension: &str, file_contents: &Vec<Vec<f64>>) {
let hash = get_file_hash(&path);
match hash {
Ok(sha1) => {
let cache_path_str = format!("{}/{}x{}_{}.{}",CACHE_DIR, size, size, sha1, extension);
let cached_path = Path::new(&cache_path_str);
// Save the file into the cache
match File::create(&cached_path) {
Ok(mut file) => {
for row in file_contents {
let mut row_str = row.iter().fold(String::new(), |acc, &item| acc + &format!("{},",item));
//remove the last comma
let desire_len = row_str.len()-1;
row_str.truncate(desire_len);
row_str.push_str("\n");
file.write(&row_str.into_bytes());
}
file.flush();
},
Err(_) => {},
}
},
Err(e) => println!("Error: {}", e),
}
}
/**
* Get an image buffer out of the cache
*/
pub fn get_from_cache(path: &Path, size: u32) -> Option<ImageBuffer<image::Luma<u8>, Vec<u8>>> {
pub fn get_image_from_cache(path: &Path, size: u32) -> Option<ImageBuffer<image::Luma<u8>, Vec<u8>>> {
let hash = get_file_hash(&path);
match hash {
Ok(sha1) => {
@ -88,6 +117,42 @@ pub fn get_from_cache(path: &Path, size: u32) -> Option<ImageBuffer<image::Luma<
}
}
/**
* Get a matrix out of the cache
*/
pub fn get_matrix_from_cache(path: &Path, size: u32, extension: &str) -> Option<Vec<Vec<f64>>> {
let hash = get_file_hash(&path);
match hash {
Ok(sha1) => {
// Check if the file exists in the cache
let cache_path_str = format!("{}/{}x{}_{}.{}",CACHE_DIR, size, size, sha1, extension);
let cached_path = Path::new(&cache_path_str);
// Try to open, if it does, then we can read the image in
match File::open(&cached_path) {
Ok(mut file) => {
let mut matrix: Vec<Vec<f64>> = Vec::new();
let mut matrix_data: Vec<u8> = Vec::new();
file.read_to_end(&mut matrix_data);
let matrix_data_str = String::from_utf8(matrix_data);
//convert the matrix
Some(matrix)
},
// Don't really care here, it just means an existing cached
// file doesn't exist, or can't be read.
Err(_) => {
None
},
}
},
Err(e) => {
println!("Error: {}", e);
None
},
}
}
#[test]
fn test_get_file_hash() {
let target = "test_images/sample_01_large.jpg";

6
src/hash.rs

@ -109,7 +109,7 @@ pub fn prepare_image<'a>(path: &'a Path, hash_type: &HashType, precision: &Preci
_ => precision.get_size()
};
// Check if we have the already converted image in a cache and use that if possible.
match cache::get_from_cache(&path, size) {
match cache::get_image_from_cache(&path, size) {
Some(image) => {
PreparedImage { orig_path: &*image_path, image: image }
},
@ -118,7 +118,7 @@ pub fn prepare_image<'a>(path: &'a Path, hash_type: &HashType, precision: &Preci
let image = image::open(path).unwrap();
let small_image = image.resize_exact(size, size, FilterType::Lanczos3);
let grey_image = small_image.to_luma();
cache::put_in_cache(&path, size, &grey_image);
cache::put_image_in_cache(&path, size, &grey_image);
PreparedImage { orig_path: &*image_path, image: grey_image }
},
}
@ -297,6 +297,8 @@ impl<'a> PerceptualHash for PHash<'a> {
// Perform the 2D DFT operation on our matrix
calculate_2d_dft(&mut data_matrix);
// Store this DFT in the cache
cache::put_matrix_in_cache(&Path::new(self.prepared_image.orig_path),width as u32,&"dft",&data_matrix);
// Only need the top left quadrant
let target_width = (width / 4) as usize;

Loading…
Cancel
Save