17 | 1月 | 2013 | HMDT Blog

カテゴリー : 2013年 1月17日

UIImageからハッシュ値を求めるときのパフォーマンス


画像を開いた2つのUIImageがあるとき、それが同じ画像かどうか判断したいときがある。いちばん負荷が少ないのは、画像を開くときのパスなりURLなりから判断する事だけど、そうもいかなくて、UIImageインスタンスを直接比較するしかない、ってときがある。

こんなときはハッシュを使うのが一般的だ。ハッシュを使えば、大きなバイナリデータも、その特徴を表す16バイトのデータを取得できる。これを比較してやればいい。iOSの場合は、CommonCryptoフレームワークにMD5ハッシュを取得するための関数があるので、これを使う。

となると次の問題は、どうやってバイナリデータを取得するか、ということだ。つまり、UIImageから、その画像を表すデータを取得したい。ざっと思いついたのは、次の3つの方法だ。

1. UIImagePNGRepresentationを使ってPNGデータを取得する

unsigned char   hash[16];
NSData*         data;
data = UIImagePNGRepresentation(image);
CC_MD5([data bytes], [data length], hash);

2. UIImageJPEGRepresentationを使ってJPEGデータを取得する

unsigned char   hash[16];
NSData*         data;
data = UIImageJPEGRepresentation(image, 1.0f);
CC_MD5([data bytes], [data length], hash);

3. CGImageからCGDataProviderを取得してビットマップデータを取得する

unsigned char       hash[16];
CGDataProviderRef   dataProvider;
NSData*             data;
dataProvider = CGImageGetDataProvider(image.CGImage);
data = (NSData*)CFBridgingRelease(CGDataProviderCopyData(dataProvider));
CC_MD5([data bytes], [data length], hash);

どの手法であっても、比較すること自体は問題ない。あとは、パフォーマンスの差だけだ。

ということで実測してみた。iPad 3rdで、1255 x 1322サイズの画像のハッシュ値を求めた。結果は次の通り。

1. PNG 1.647941sec

2. JPEG 0.442495sec

3. Data Provider 0.323576sec

ということで、Data Providerを使う手法がいちばんパフォーマンスが良かった。これを使うのがいいかな。

ちなみに、実行時間のほとんどはバイナリデータを取得する処理にかかっていた。ハッシュを求める計算が占める割合は、とても低かった。PNGへの変換は、エライこと時間がかかるわけね。