Average Hashを使って画像の類似度を計算する方法。
Average Hashとは
- 簡易化された画像の類似度検出アルゴリズム。
- それなりの精度で類似した画像を探すことができる。
アルゴリズム
- グレースケール化。
- 画像を8×8に縮小。(16×16などでも良い。)
- 画素の平均値を調べる。
- 各画素を走査して平均値より上なら1、下なら0という風にハッシュ化していく。
こーど
// Average Hash
// clang -Os -o ahash ahash.c -lm
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"
#define AHASH_SIZE 16
void imgp_gray(uint8_t *s, int sx, int sy, int stride, uint8_t *p, int gstride)
{
for (int y=0; y<sy; y++) {
for (int x=0; x<sx; x++) {
p[x] = 0.3 * s[x*3+0] + 0.59 * s[x*3+1] + 0.11*s[x*3+2];
}
s += stride*3;
p += gstride;
}
}
int main(int argc, char* argv[])
{
char *name = argv[1];
uint8_t *pixels;
int w, h, bpp;
pixels = stbi_load(name, &w, &h, &bpp, 3);
assert(pixels);
uint8_t *gray = malloc(w*h+AHASH_SIZE*AHASH_SIZE);
uint8_t *resize = gray+w*h;
imgp_gray(pixels, w, h, w, gray, w);
//stbi_write_jpg("gray.jpg", w, h, 1, gray, 0);
stbir_resize_uint8(gray, w, h, 0, resize, AHASH_SIZE, AHASH_SIZE, 0, 1);
//stbi_write_jpg("resize.jpg", AHASH_SIZE, AHASH_SIZE, 1, resize, 0);
double avg = 0;
for (int i=0; i<AHASH_SIZE*AHASH_SIZE; i++) {
avg += resize[i];
}
avg /= AHASH_SIZE*AHASH_SIZE;
printf("avg: %f\n", avg);
uint8_t ahash[AHASH_SIZE*AHASH_SIZE/8];
for (int i=0; i<AHASH_SIZE*AHASH_SIZE; i++) {
ahash[i/8] <<= 1;
if (avg <= (double)resize[i]) ahash[i/8] |= 1;
else ahash[i/8] &= ~1;
}
for (int i=0; i<AHASH_SIZE*AHASH_SIZE/8; i++) {
printf("%02x", ahash[i]);
}
printf("\n");
free(gray);
stbi_image_free(pixels);
}
参考
- https://tech.unifa-e.com/entry/2017/11/27/111546
- http://hideack.hatenablog.com/entry/2015/03/16/194336