-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdct_perceptual_hasher.hpp
149 lines (109 loc) · 3.1 KB
/
dct_perceptual_hasher.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#ifndef __DCT_PERCEPTUAL_HASHER_HPP_INCLUDED__
#define __DCT_PERCEPTUAL_HASHER_HPP_INCLUDED__
#include <vector>
#include <string>
#include <stdint.h>
#include <Magick++.h>
#include <Eigen/Dense>
#include "phash.hpp"
namespace imgdupl
{
template <int N, int Bits>
class DCTHasher
{
public:
DCTHasher()
{
make_dct_matrix();
dct_t = dct.transpose();
}
~DCTHasher()
{
}
std::pair<bool, PHash> hash(const Magick::Image& original_image) const
{
PHash phash;
bool status = true;
try {
phash = hash_impl(original_image);
} catch (Magick::Exception& e) {
status = false;
}
return std::make_pair(status, phash);
}
private:
typedef Eigen::Matrix<float, N, N> DCTMatrix;
typedef Eigen::Matrix<float, N, N> ImgMatrix;
DCTMatrix dct;
DCTMatrix dct_t;
void make_dct_matrix()
{
unsigned int i, k, rows, cols;
cols = dct.cols();
rows = dct.rows();
float n = static_cast<float>(dct.cols());
for (i = 0; i < cols; i++) {
dct(0, i) = sqrt(1.0 / n);
}
const float c = sqrt(2.0 / n);
for (k = 1; k < rows; k++) {
for (i = 0; i < cols; i++) {
dct(k, i) = c * cos((M_PI / (2 * n)) * k * (2 * i + 1));
}
}
}
PHash hash_impl(const Magick::Image& image_) const
{
Magick::Image image(image_);
image.type(Magick::GrayscaleType);
Magick::Geometry geometry(N, N);
geometry.aspect(true);
image.transform(geometry);
unsigned int width = image.size().width();
unsigned int height = image.size().height();
Magick::PixelPacket* pixels = image.getPixels(0, 0, width, height);
ImgMatrix img;
for (unsigned int i = 0; i < width; i++) {
for (unsigned int j = 0; j < height; j++) {
img(i, j) = static_cast<float>(pixels->red);
++pixels;
}
}
DCTMatrix c = dct * img * dct_t;
float coeffs[Bits];
float coeffs_copy[Bits];
for (int i = 0, j = 0, k = 0; k < Bits; k++) {
coeffs[k] = c(i, j);
j++;
i--;
if (i < 0) {
i = j;
j = 0;
}
}
memcpy(coeffs_copy, coeffs, sizeof(coeffs));
std::sort(coeffs_copy, coeffs_copy + Bits);
float median = (coeffs_copy[Bits / 2] + coeffs_copy[Bits / 2 - 1]) / 2.0;
PHash phash;
uint64_t hash = 0;
int basic_hash_bits_count = sizeof(hash) * 8;
uint64_t one = 1;
for (size_t i = 0; i < Bits; i++) {
if (coeffs[i] > median) {
hash |= one;
}
one = one << 1;
if ((i + 1) % basic_hash_bits_count == 0) {
phash.push_back(hash);
hash = 0;
one = 1;
}
}
if (Bits % basic_hash_bits_count != 0) {
phash.push_back(hash);
}
return phash;
}
};
} // namespace
#endif