LoginSignup
4
9

More than 3 years have passed since last update.

OpenCVで画像をハッシュ値に変換する方法

Last updated at Posted at 2019-10-24

Background

画像の類似度を比較する手法として画像をハッシュ値に変換してハミング距離で計算する方法があります。今回はOpenCVでハッシュ値を変換しようと思います。

ImageHash

アルゴリズムの元ネタはhackerfactorのようですが、これをベースにしたライブラリはPythonでは imagehash が主流みたいです。種類としては ahash phash dhash whash の4つが存在します。

テストデータ

Mandrill.png  おなじみの画像です。

必要なパッケージ
from PIL import Image
import imagehash
name code result
average hashing imagehash.average_hash(Image.open('Mandrill.png')) 01833f3cbc98ebfc
perception hashing imagehash.phash(Image.open('Mandrill.png')) df20607d1fa0d88f
difference hashing imagehash.dhash(Image.open('Mandrill.png')) 1fabea6869305668
wavelet hashing imagehash.whash(Image.open('Mandrill.png')) 01433f3cbc98e2fc

で、Python版のOpenCVにハッシュ値を変換するモジュールがあるかというと、、、、ありません:tired_face:

OpenCV(C++)

ですが、C++版にはモジュールが入っています。メソッドの種類は上記で挙げたImageHashとは異なります。

  • AverageHash
  • PHash
  • MarrHildrethHash
  • RadialVarianceHash
  • BlockMeanHash
  • ColorMomentHash

とりあえず、メソッドを元に出力値を出してみます。

Development

The module brings implementations of different image hashing algorithms.にあるコードを参考に実装します。

LDLIBS =  -lopencv_core -lopencv_imgcodecs -lopencv_imgproc -lopencv_img_hash
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/img_hash.hpp>
#include <cxxabi.h>

template <typename T> inline void output_hash(const cv::Mat &src)
{
    cv::Mat dst;
    cv::Ptr<cv::img_hash::ImgHashBase> func;
    func = T::create();

    func->compute(src, dst);

    std::string name = abi::__cxa_demangle(typeid(T).name(), 0, 0, 0);
    std::cout << name << "\t" << dst << std::endl;
}

int main( int argc, char** argv )
{

    cv::Mat imageMat = cv::imread("./Mandrill.png", cv::IMREAD_COLOR  );
    output_hash<cv::img_hash::AverageHash>(imageMat);
    output_hash<cv::img_hash::PHash>(imageMat);
    output_hash<cv::img_hash::MarrHildrethHash>(imageMat);
    output_hash<cv::img_hash::RadialVarianceHash>(imageMat);
    output_hash<cv::img_hash::BlockMeanHash>(imageMat);
    output_hash<cv::img_hash::ColorMomentHash>(imageMat);
    return 0;
}

Result

cv::img_hash::AverageHash   [  9, 129, 239,  54,  53,   3, 195, 229]
cv::img_hash::PHash [249,   4,   6, 190, 240, 133,  27, 249]
cv::img_hash::MarrHildrethHash  [240, 120,  59,  19,  49,  56, 156,  14,  89,   5, 137, 192, 228, 177, 255, 211, 208,  27,  37, 143, 188,  28,  14,  71,  98, 109, 192, 102,  77, 196, 227, 241,  57, 121, 242,  27, 164, 237, 191,  31, 143, 199, 100, 214, 115, 100, 236, 196, 193, 240,  56, 127, 108, 182, 108, 252,  60,  29, 142,   6, 147, 192,  75,   3, 137, 193, 229, 240, 126, 114, 112, 201]
cv::img_hash::RadialVarianceHash    [ 69,  62, 255,  42, 193,  80, 150,  70,   0, 104,  38,  66,  73, 101,  61,  64,  81,  81,  82,  52,  56,  71,  52,  60,  63,  84,  65,  56,  70,  68,  72,  67,  65,  74,  78,  65,  55,  67,  63,  70]
cv::img_hash::BlockMeanHash [  2,  96,   2,  64,   6,  96,   6, 230, 102, 238, 116, 126, 240, 111, 240,  14, 241,   7,  97,   7,  67,   3, 139,   3, 139, 177,  63, 190, 255,  63, 247,  15]
cv::img_hash::ColorMomentHash   [0.002503659152184849, 2.471939932761336e-08, 4.467702288443572e-11, 2.753929884994291e-11, 3.907790057002085e-22, -4.24497491111126e-15, -8.834156975661139e-22, 0.001648706395707542, 4.497051261680711e-09, 3.146007555704344e-11, 1.673749393818875e-11, 3.312616975083822e-23, 1.117844884043978e-15, 3.826433279309091e-22, 0.000964146950520186, 3.507447150328149e-09, 4.712173150861858e-13, 1.510627115300825e-12, -1.25450023857693e-24, 3.736683447133399e-17, 2.250099503660287e-25, 0.001264405759998173, 4.013957543909037e-09, 7.996919537752477e-13, 9.256331740589708e-13, -5.433089299218264e-25, -2.969719150917409e-17, -5.822668758123276e-25, 0.001221333669445427, 6.085465009873859e-10, 2.11537441698962e-14, 4.10817520446575e-12, -6.598046593374036e-25, 8.906807344893997e-17, 1.015545954823273e-24, 0.001350832788790067, 7.253752695174111e-10, 4.409337297754683e-13, 1.21565621533617e-12, -5.606880832077259e-26, -2.143611937655263e-17, 8.882584320430919e-25]

ImageHashと共通としてあるメソッドがAverageHashPHashの2つですが結構値が異なります。
aHash:01833f3cbc98ebfc pHash:df20607d1fa0d88fをそれぞれ16進数から10進数に直すと [1, 131, 63, 60, 188, 152, 235, 252] [223, 32, 96, 125, 31, 160, 216, 143]になります。
同じメソッド名でもモジュールが異なるとアルゴリズムが少し違うみたいです。

おわりに

ハッシュ値は出力できたので次は画像の類似度を計算してみます。どのようにハッシュ値にしているかはPerceptual Hashを使って画像の類似度を計算してみるが一番丁寧に説明していて参考になります。

4
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
9