Browse Source

Added full ahash test for sample_01. Renamed sample images for testing purposes. Working on a more comprehensive testing for ahashes.

develop
Drew Short 9 years ago
parent
commit
2849c529d4
  1. 80
      src/hash.rs
  2. 65
      src/lib.rs
  3. 6
      test_images/credits.txt
  4. 0
      test_images/sample_02_large.jpg
  5. 0
      test_images/sample_02_medium.jpg
  6. 0
      test_images/sample_02_small.jpg
  7. 0
      test_images/sample_03_large.jpg
  8. 0
      test_images/sample_03_medium.jpg
  9. 0
      test_images/sample_03_small.jpg
  10. 0
      test_images/sample_04_large.jpg
  11. 0
      test_images/sample_04_medium.jpg
  12. 0
      test_images/sample_04_small.jpg

80
src/hash.rs

@ -0,0 +1,80 @@
// Copyright 2015 Drew Short <drew@sothr.com>.
//
// Licensed under the MIT license<LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.
// Pull in the image processing crate
extern crate image;
use std::path::Path;
use self::image::{
GenericImage,
Pixel
};
pub struct PreparedImage<'a> {
orig_path: &'a str,
grey_image: image::ImageBuffer<image::Luma<u8>,Vec<u8>>
}
pub fn prepare_image(path: &Path) -> PreparedImage {
let grey_img = image::open(path).unwrap().to_luma();
let image_path = path.to_str().unwrap();
PreparedImage { orig_path: &*image_path, grey_image: grey_img }
}
/*
* Calculate the number of bits different between two hashes
*/
pub fn calculate_hamming_distance(hash1: u64, hash2: u64) -> u64 {
// The binary xor of the two hashes should give us a number representing
// the differences between the two hashes. All that's left is to count
// the number of 1's in the difference to determine the hamming distance
let bin_diff = hash1 ^ hash2;
let bin_diff_str = format!("{:b}", bin_diff);
let mut hamming = 0u64;
for bit in bin_diff_str.chars() {
match bit {
'1' => hamming+=1,
_ => continue
}
}
hamming
}
/**
* Calculate the ahash of an image provided at the indicated path.
*
* # Arguments
*
* * 'path' - The path to the image file to create a hash from.
*
* Returns a u64 representing the value of the hash
*/
pub fn get_ahash(prepared_image: PreparedImage) -> u64 {
let img = prepared_image.grey_image;
let (width, height) = img.dimensions();
// calculating the average pixel value
let mut total = 0u64;
for pixel in img.pixels() {
let channels = pixel.channels();
total += channels[0] as u64;
}
let mean = total / (width*height) as u64;
// Calculating a hash based on the mean
let mut hash = 0u64;
for pixel in img.pixels() {
let channels = pixel.channels();
let pixel_sum = channels[0] as u64;
hash <<= 1;
if pixel_sum >= mean {
hash |= 1;
} else {
hash |= 0;
}
}
return hash;
}

65
src/lib.rs

@ -3,6 +3,9 @@
// Licensed under the MIT license<LICENSE-MIT or http://opensource.org/licenses/MIT>. // Licensed under the MIT license<LICENSE-MIT or http://opensource.org/licenses/MIT>.
// 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.
mod hash;
pub fn hello(mut result: String) -> String { pub fn hello(mut result: String) -> String {
let helloworld = "Hello, World!"; let helloworld = "Hello, World!";
result.push_str(helloworld); result.push_str(helloworld);
@ -18,6 +21,7 @@ mod tests {
use super::*; use super::*;
use std::fs; use std::fs;
use std::path; use std::path;
use hash;
#[test] #[test]
fn can_get_test_images() { fn can_get_test_images() {
@ -29,8 +33,8 @@ mod tests {
match ext { match ext {
Some(_) => { Some(_) => {
if ext.unwrap() == "jpg" { if ext.unwrap() == "jpg" {
println!("Is a image {}: {:?}", num_paths, orig_path) ;
num_paths += 1; num_paths += 1;
println!("Is a image {}: {:?}", num_paths, orig_path) ;
} }
}, },
_ => { _ => {
@ -44,4 +48,63 @@ mod tests {
assert!(num_paths == 12); assert!(num_paths == 12);
} }
// Simple function for the unit tests to succinctly test a set of images
// that are organized in the fashion of large->medium->small
fn test_image_set_ahash(
large_path: &str,
medium_path: &str,
small_path: &str,
expected_large_hash: u64,
expected_medium_hash: u64,
expected_small_hash: u64,
expected_large_medium_hamming: u64,
expected_large_small_hamming: u64,
expected_medium_small_hamming: u64) {
let large_prepared_image = hash::prepare_image(path::Path::new(large_path));
let medium_prepared_image = hash::prepare_image(path::Path::new(medium_path));
let small_prepared_image = hash::prepare_image(path::Path::new(small_path));
let large_ahash = hash::get_ahash(large_prepared_image);
let medium_ahash = hash::get_ahash(medium_prepared_image);
let small_ahash = hash::get_ahash(small_prepared_image);
println!("./test_images/sample_01_large.jpg: {}", large_ahash);
println!("./test_images/sample_01_medium.jpg: {}", medium_ahash);
println!("./test_images/sample_01_small.jpg: {}", small_ahash);
assert!(large_ahash == expected_large_hash);
assert!(medium_ahash == expected_medium_hash);
assert!(small_ahash == expected_small_hash);
let large_medium_hamming = hash::calculate_hamming_distance(large_ahash, medium_ahash);
let large_small_hamming = hash::calculate_hamming_distance(large_ahash, small_ahash);
let medium_small_hamming = hash::calculate_hamming_distance(medium_ahash, small_ahash);
println!("Large-Medium Hamming Distance: {}", large_medium_hamming);
println!("Large-Small Hamming Distance: {}", large_small_hamming);
println!("Medium-Small Hamming Distance: {}", medium_small_hamming);
assert!(large_medium_hamming == expected_large_medium_hamming);
assert!(large_small_hamming == expected_large_small_hamming);
assert!(medium_small_hamming == expected_medium_small_hamming);
}
#[test]
fn confirm_ahash_results() {
// Sample_01 tests
test_image_set_ahash(
"./test_images/sample_01_large.jpg",
"./test_images/sample_01_medium.jpg",
"./test_images/sample_01_small.jpg",
18446744073709551615u64,
18446744073709551615u64,
9223372036854775807u64,
0u64,
1u64,
1u64
);
}
} }

6
test_images/credits.txt

@ -3,9 +3,9 @@ All test images are Creative Commons Licensed
This document seeks to credit the original authors where possible This document seeks to credit the original authors where possible
# Landscapes # Landscapes
14095127199_e60a64e1b6_h_{large,medium,small}.jpg https://m.flickr.com/#/photos/cubagallery/14095127199/in/search_QM_q_IS_landscape_AND_w_IS_commons
15720949851_c94c8b2d54_h_{large,medium,small}.jpg https://m.flickr.com/#/photos/cubagallery/15720949851/in/search_QM_q_IS_landscape_AND_w_IS_commons
14191645299_7179d4a859_h_{large,medium,small}.jpg https://m.flickr.com/#/photos/cubagallery/14191645299/in/search_QM_q_IS_landscape_AND_w_IS_commons
sample_02_{large,medium,small}.jpg https://m.flickr.com/#/photos/cubagallery/14095127199/in/search_QM_q_IS_landscape_AND_w_IS_commons
sample_03_{large,medium,small}.jpg https://m.flickr.com/#/photos/cubagallery/15720949851/in/search_QM_q_IS_landscape_AND_w_IS_commons
sample_04_{large,medium,small}.jpg https://m.flickr.com/#/photos/cubagallery/14191645299/in/search_QM_q_IS_landscape_AND_w_IS_commons
# Faces # Faces

0
test_images/14095127199_e60a64e1b6_h_large.jpg → test_images/sample_02_large.jpg

Before

Width: 1600  |  Height: 1600  |  Size: 1.1 MiB

After

Width: 1600  |  Height: 1600  |  Size: 1.1 MiB

0
test_images/14095127199_e60a64e1b6_h_medium.jpg → test_images/sample_02_medium.jpg

Before

Width: 800  |  Height: 800  |  Size: 288 KiB

After

Width: 800  |  Height: 800  |  Size: 288 KiB

0
test_images/14095127199_e60a64e1b6_h_small.jpg → test_images/sample_02_small.jpg

Before

Width: 400  |  Height: 400  |  Size: 72 KiB

After

Width: 400  |  Height: 400  |  Size: 72 KiB

0
test_images/15720949851_c94c8b2d54_h_large.jpg → test_images/sample_03_large.jpg

Before

Width: 1600  |  Height: 1600  |  Size: 611 KiB

After

Width: 1600  |  Height: 1600  |  Size: 611 KiB

0
test_images/15720949851_c94c8b2d54_h_medium.jpg → test_images/sample_03_medium.jpg

Before

Width: 800  |  Height: 800  |  Size: 132 KiB

After

Width: 800  |  Height: 800  |  Size: 132 KiB

0
test_images/15720949851_c94c8b2d54_h_small.jpg → test_images/sample_03_small.jpg

Before

Width: 400  |  Height: 400  |  Size: 37 KiB

After

Width: 400  |  Height: 400  |  Size: 37 KiB

0
test_images/14191645299_7179d4a859_h_large.jpg → test_images/sample_04_large.jpg

Before

Width: 1600  |  Height: 1600  |  Size: 1.3 MiB

After

Width: 1600  |  Height: 1600  |  Size: 1.3 MiB

0
test_images/14191645299_7179d4a859_h_medium.jpg → test_images/sample_04_medium.jpg

Before

Width: 800  |  Height: 800  |  Size: 340 KiB

After

Width: 800  |  Height: 800  |  Size: 340 KiB

0
test_images/14191645299_7179d4a859_h_small.jpg → test_images/sample_04_small.jpg

Before

Width: 400  |  Height: 400  |  Size: 89 KiB

After

Width: 400  |  Height: 400  |  Size: 89 KiB

Loading…
Cancel
Save