39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
# File 'ext/phash_native/phash_native.c', line 39
static VALUE compute_phash(VALUE self, VALUE filepath) {
Check_Type(filepath, T_STRING);
const char *filename = StringValueCStr(filepath);
int width, height, channels;
unsigned char *data = stbi_load(filename, &width, &height, &channels, 1); // 1 = grayscale
if (!data) {
rb_raise(rb_eRuntimeError, "Failed to load image: %s", filename);
}
double resized[RESIZE_DIM][RESIZE_DIM];
for (int y = 0; y < RESIZE_DIM; y++) {
for (int x = 0; x < RESIZE_DIM; x++) {
int src_x = x * width / RESIZE_DIM;
int src_y = y * height / RESIZE_DIM;
resized[y][x] = (double)data[src_y * width + src_x];
}
}
double dct[RESIZE_DIM][RESIZE_DIM];
compute_dct(resized, dct);
double sum = 0.0;
for (int y = 0; y < HASH_SIZE; y++) {
for (int x = 0; x < HASH_SIZE; x++) {
if (x == 0 && y == 0) continue; // Skip DC term
sum += dct[y][x];
}
}
double avg = sum / (HASH_SIZE * HASH_SIZE - 1);
uint64_t hash = 0;
for (int y = 0; y < HASH_SIZE; y++) {
for (int x = 0; x < HASH_SIZE; x++) {
if (x == 0 && y == 0) continue;
hash <<= 1;
hash |= (dct[y][x] > avg) ? 1 : 0;
}
}
stbi_image_free(data);
return ULL2NUM(hash);
}
|