Rustのimage_hashクレートを使って画像の類似を調べる
まえがき
最近Rustをちょっとずつ勉強してます
勉強もかねてパソコンの中にある重複した画像を調べるアプリを作ろうと思い製作中です
実はもうすでにQiitaやZENで同じような記事を書いている人がいるので二番煎じみたいな記事ですが、image_hashクレートを使ってたのはあまりなかったのでチラシの裏的に書いていきます
初めてZENで記事書くので見にくかったりしたらゴメンナサイ
要点
やりたいこととしては画像のサイズや圧縮比が違っても正しく比較できるようにしたいので精度の高いpHash(Perseptual Hash)を使って画像ごとのハッシュ値を求め比較していくという方法になります
ハッシュ化というとMD5とかSHAを思い浮かべるかもしれませんがpHashはjpeg圧縮などにも使用されている画像の特徴をハッシュ化したものとなります
詳しいことは後述します
image_hashクレートを使う
もうすでに便利なクレートを作ってくれている人がいます
実用的なメソッドが用意されており使い勝手がとてもいいです
image_hashについて
画像のハッシュ化を手助けしてくれる便利なクレートです
このクレートを使用することで難しいロジックを実装する必要がなく目的を簡単にコードに実装できます
またpHashだけでなくGradient HashやBlockhashなどのアルゴリズムを実験的に組み込んであり
それぞれの特徴を比較することができます
HasherConfigで実装されているhash_algメソッドでハッシュアルゴリズムを指定することで各アルゴリズムを試すことができますが今回はこの説明は割愛いたします
具体例・実装
使い方
newメソッドを呼び出すことでaHashアルゴリズムを使用することとなり
離散コサイン変換(DCT)による前処理をすることでpHashアルゴリズムになります
これはインスタンスの作成時にpreproc_dctメソッドをつないであげることで有効になります
use img_hash::HasherConfig;
fn main() {
let hasher = HasherConfig::new().preproc_dct().to_hasher();
}
Hash値のハミング距離を比較する
では実際にpHashを使ってどのように画像が類似しているかを調べるかというと
計算したハッシュのハミング距離を比較し、しきい値より小さいかで判断します
これはdistメソッドを使用するだけでハミング距離を計算しu32型で返してくれます
ハミング距離は0~100の間で返されます
100は完全に不一致
0は完全に一致していると言えます
おおよそ10以下が類似している画像として判断できます
簡単な使用例
DynamicImageはimageクレートを使用しますのでCargo.tomlに以下のように記載します
[dependencies]
image = "0.22.3"
img_hash = "3.2.0"
use image::DynamicImage;
use img_hash::{HasherConfig, ImageHash};
pub fn get_phash(img: DynamicImage) -> ImageHash {
let hasher = HasherConfig::new().preproc_dct().to_hasher();
hasher.hash_image(&img)
}
pub fn is_similar(hash1: ImageHash, hash2: ImageHash) -> bool {
hash1.dist(&hash2) < 10
}
use image::DynamicImage;
use package_name::*;
fn main() {
let image1 = image::open("image1.png").unwrap();
let image2 = image::open("image2.png").unwrap();
let hash1 = get_phash(image1);
let hash2 = get_phash(image2);
if is_similar(hash1, hash2) {
println!("Images match!");
}
}
結論
image_hashを使うときにpreproc_dct()を使ってpHashを使おう!ということを伝えたいだけの記事でした
難しいコード書かずにシンプルに画像比較ロジックが実装できるのいいですよね
さいごに
実際に動かしてみると精度はいいのですがCPU使ってごりごり計算するので少し時間がかかってしまうのが課題ですね…
GPUで計算できたりしたら早かったりするのかな
まだまだ知識半端ところもありますので間違いありましたら気軽に指摘してください
参考にした記事など
aHash, pHashについて解説してくれている記事
特にRustだと実装からクレートの公開まで詳しくやってくれているこちらの記事が
今回のアイデアの実現と行動に大きく力を貸してくれました
用語説明
情報理論において、ハミング距離(ハミングきょり、英: Hamming distance)とは、等しい文字数を持つ二つの文字列の中で、対応する位置にある異なった文字の個数である。
Discussion