use image::RgbaImage;
pub trait SimilarityMetric: Send + Sync {
fn similarity(&self, a: &RgbaImage, b: &RgbaImage) -> f64;
fn duplicate_threshold(&self) -> f64;
fn name(&self) -> &'static str;
fn are_duplicates(&self, a: &RgbaImage, b: &RgbaImage) -> bool {
self.similarity(a, b) >= self.duplicate_threshold()
}
}
pub struct HashBasedSimilarity<H> {
hasher: H,
max_distance: u32,
}
impl<H> HashBasedSimilarity<H> {
pub fn new(hasher: H, max_distance: u32) -> Self {
Self {
hasher,
max_distance,
}
}
}
impl<H> SimilarityMetric for HashBasedSimilarity<H>
where
H: crate::traits::FrameHasher,
{
fn similarity(&self, a: &RgbaImage, b: &RgbaImage) -> f64 {
let hash_a = self.hasher.hash_frame(a);
let hash_b = self.hasher.hash_frame(b);
let distance = self.hasher.distance(&hash_a, &hash_b);
if distance >= self.max_distance {
0.0
} else {
1.0 - (distance as f64 / self.max_distance as f64)
}
}
fn duplicate_threshold(&self) -> f64 {
let threshold = self.hasher.suggested_threshold();
1.0 - (threshold as f64 / self.max_distance as f64)
}
fn name(&self) -> &'static str {
"hash-based"
}
}