Rust图像哈希处理库image_hasher的使用:高效生成感知哈希值并实现相似图片搜索

Rust图像哈希处理库image_hasher的使用:高效生成感知哈希值并实现相似图片搜索

Image Hasher是一个用于获取图像感知哈希值的库。

感谢Neal Krawetz博士提出的Mean(aHash)、Gradient(dHash)和DCT(pHash)感知哈希算法。

使用方法

Cargo.toml中添加依赖:

image_hasher = "3.0.0"

以下是示例程序:

use image_hasher::{HasherConfig, HashAlg};

fn main() {
    let image1 = image::open("image1.png").unwrap();
    let image2 = image::open("image2.png").unwrap();

    let hasher = HasherConfig::new().to_hasher();

    let hash1 = hasher.hash_image(&image1);
    let hash2 = hasher.hash_image(&image2);

    println!("Image1 hash: {}", hash1.to_base64());
    println!("Image2 hash: {}", hash2.to_base64());

    println!("Hamming Distance: {}", hash1.dist(&hash2));
}

完整示例demo

下面是一个完整的示例,展示如何使用image_hasher库生成图像哈希并比较相似度:

use image_hasher::{HasherConfig, HashAlg};
use std::path::Path;

fn main() {
    // 打开两张图片
    let image_path1 = Path::new("image1.jpg");
    let image_path2 = Path::new("image2.jpg");
    
    let image1 = image::open(image_path1).expect("Failed to open image1");
    let image2 = image::open(image_path2).expect("Failed to open image2");

    // 配置哈希器(可以选择不同的算法: aHash, dHash, pHash)
    let hasher = HasherConfig::with_hash_type(HashAlg::Gradient)
        .hash_size(8, 8)  // 设置哈希尺寸
        .to_hasher();

    // 生成哈希值
    let hash1 = hasher.hash_image(&image1);
    let hash2 = hasher.hash_image(&image2);

    // 输出哈希值(Base64格式)
    println!("Image1 hash: {}", hash1.to_base64());
    println!("Image2 hash: {}", hash2.to_base64());

    // 计算汉明距离(距离越小越相似)
    let distance = hash1.dist(&hash2);
    println!("Hamming Distance: {}", distance);

    // 判断是否相似(通常距离<=10可认为相似)
    if distance <= 10 {
        println!("These images are similar!");
    } else {
        println!("These images are different.");
    }
}

特性说明

  1. 支持的算法:

    • Mean(aHash): 基于平均像素值的算法
    • Gradient(dHash): 基于梯度变化的算法
    • DCT(pHash): 基于离散余弦变换的算法
    • Blockhash: Blockhash.io算法
  2. 性能优化:

    • 可以使用fast_image_unstable特性来启用更快的图像处理
  3. 最小Rust版本:

    • 需要Rust 1.70.0或更高版本

许可证

双重许可:

  • Apache License, Version 2.0
  • MIT license

注意事项

  1. 要运行基准测试,需要使用Rust nightly版本:
cargo +nightly bench
  1. 对于相似图片搜索,通常汉明距离<=10表示图片相似,但具体阈值可以根据需求调整。

  2. 不同算法适用于不同场景:

    • aHash: 简单快速,适合一般用途
    • dHash: 对亮度变化敏感
    • pHash: 更准确但计算更复杂

这个库可以方便地集成到Rust项目中,用于图像相似度比较、重复图片检测等场景。


1 回复

Rust图像哈希处理库image_hasher的使用指南

介绍

image_hasher是一个Rust库,用于计算图像的感知哈希(perceptual hash),可用于相似图片搜索、重复图片检测等场景。它能够将图像内容转换为紧凑的哈希值,即使图像经过缩放、旋转或轻微修改,相似的图像仍会产生相似的哈希值。

主要特性:

  • 支持多种哈希算法(包括aHash、dHash、pHash等)
  • 高效处理大图像(自动缩放)
  • 支持多种图像格式(通过image库)
  • 计算汉明距离比较哈希相似度

安装

在Cargo.toml中添加依赖:

[dependencies]
image_hasher = "1.1"
image = "0.24"  # 用于加载图像

基本使用方法

1. 计算图像哈希

use image_hasher::{HasherConfig, ImageHash};
use image::io::Reader as ImageReader;
use std::path::Path;

fn compute_hash(image_path: &Path) -> ImageHash {
    // 加载图像
    let img = ImageReader::open(image_path)
        .unwrap()
        .decode()
        .unwrap();
    
    // 创建hasher并计算哈希
    let hasher = HasherConfig::new().to_hasher();
    hasher.hash_image(&img)
}

fn main() {
    let hash = compute_hash(Path::new("test.jpg"));
    println!("Image hash: {:?}", hash.to_base64());
}

2. 比较两个图像的相似度

use image_hasher::HashAlg;

fn compare_images(img1_path: &Path, img2_path: &Path) -> f32 {
    let hasher = HasherConfig::with_bytes_type::<[u8; 8]>()
        .hash_alg(HashAlg::Gradient)
        .to_hasher();
    
    let img1 = ImageReader::open(img1_path).unwrap().decode().unwrap();
    let img2 = ImageReader::open(img2_path).unwrap().decode().unwrap();
    
    let hash1 = hasher.hash_image(&img1);
    let hash2 = hasher.hash_image(&img2);
    
    // 计算汉明距离并转换为相似度百分比
    let dist = hash1.dist(&hash2);
    let similarity = 1.0 - (dist as f32 / hash1.as_bytes().len() as f32);
    similarity * 100.0
}

fn main() {
    let similarity = compare_images(Path::new("img1.jpg"), Path::new("img2.jpg"));
    println!("Similarity: {:.2}%", similarity);
}

高级用法

1. 使用不同的哈希算法

use image_hasher::{HashAlg, HasherConfig};

let hasher = HasherConfig::new()
    .hash_alg(HashAlg::DoubleGradient)  // 使用双梯度哈希算法
    .hash_size(16)                     // 设置哈希大小为16x16
    .to_hasher();

支持的算法:

  • Mean (aHash)
  • Gradient (dHash)
  • Blockhash
  • DoubleGradient
  • VertGradient
  • HorzGradient

2. 构建简单的图片搜索引擎

use std::collections::HashMap;
use std::path::{Path, PathBuf};

struct ImageDatabase {
    hasher: image_hasher::Hasher,
    hashes: HashMap<PathBuf, ImageHash>,
}

impl ImageDatabase {
    fn new() -> Self {
        let hasher = HasherConfig::new().to_hasher();
        Self {
            hasher,
            hashes: HashMap::new(),
        }
    }
    
    fn add_image(&mut self, path极好的,您已经提供了完整的`image_hasher`使用指南内容。由于内容中没有图片,我不会添加任何图片。以下是基于您提供的内容的完整示例demo:

```rust
//! 完整示例:使用image_hasher构建图片相似度检测系统

use image_hasher::{HasherConfig, HashAlg, ImageHash};
use image::io::Reader as ImageReader;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use rayon::prelude::*;

/// 图像数据库结构体
struct ImageSimilaritySystem {
    hasher: image_hasher::Hasher,
    image_hashes: HashMap<PathBuf, ImageHash>,
}

impl ImageSimilaritySystem {
    /// 创建新的图像数据库
    pub fn new(hash_alg: HashAlg, hash_size: u32) -> Self {
        let hasher = HasherConfig::new()
            .hash_alg(hash_alg)
            .hash_size(hash_size)
            .to_hasher();
        
        Self {
            hasher,
            image_hashes: HashMap::new(),
        }
    }
    
    /// 添加单张图片到数据库
    pub fn add_image(&mut self, image_path: &Path) -> anyhow::Result<()> {
        let img = ImageReader::open(image_path)?.decode()?;
        let hash = self.hasher.hash_image(&img);
        self.image_hashes.insert(image_path.to_path_buf(), hash);
        Ok(())
    }
    
    /// 批量添加图片到数据库(并行处理)
    pub fn add_images_batch(&mut self, image_paths: &[PathBuf]) -> anyhow::Result<()> {
        let hashes: Vec<(PathBuf, ImageHash)> = image_paths
            .par_iter()
            .map(|path| {
                let img = ImageReader::open(path)?.decode()?;
                let hash = self.hasher.hash_image(&img);
                Ok((path.to_path_buf(), hash))
            })
            .collect::<anyhow::Result<Vec<_>>>()?;
        
        for (path, hash) in hashes {
            self.image_hashes.insert(path, hash);
        }
        
        Ok(())
    }
    
    /// 查找与查询图片相似的图片
    pub fn find_similar_images(
        &self,
        query_image: &Path,
        similarity_threshold: f32
    ) -> anyhow::Result<Vec<(PathBuf, f32)>> {
        let query_img = ImageReader::open(query_image)?.decode()?;
        let query_hash = self.hasher.hash_image(&query_img);
        
        let results = self.image_hashes
            .par_iter()
            .map(|(path, hash)| {
                let dist = hash.dist(&query_hash);
                let similarity = 1.0 - (dist as f32 / hash.as_bytes().len() as f32);
                (path.clone(), similarity * 100.0)
            })
            .filter(|(_, similarity)| *similarity >= similarity_threshold)
            .collect();
        
        Ok(results)
    }
}

fn main() -> anyhow::Result<()> {
    // 初始化系统 - 使用双梯度算法,哈希大小16x16
    let mut system = ImageSimilaritySystem::new(HashAlg::DoubleGradient, 16);
    
    // 添加图片到数据库
    let image_dir = Path::new("images");
    let image_paths: Vec<PathBuf> = std::fs::read_dir(image_dir)?
        .filter_map(|entry| entry.ok().map(|e| e.path()))
        .collect();
    
    system.add_images_batch(&image_paths)?;
    println!("Added {} images to database", image_paths.len());
    
    // 查询相似图片
    let query_image = Path::new("query.jpg");
    let results = system.find_similar_images(query_image, 80.0)?;
    
    println!("Similar images found:");
    for (path, similarity) in results {
        println!("- {}: {:.2}% similarity", path.display(), similarity);
    }
    
    Ok(())
}

这个完整示例展示了如何:

  1. 创建一个图像相似度检测系统
  2. 使用并行处理批量添加图片
  3. 使用不同哈希算法和配置
  4. 查询相似图片并显示相似度百分比
  5. 处理可能的错误

您可以根据需要调整哈希算法类型、哈希大小和相似度阈值来优化系统性能。

回到顶部