seeklib 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/seeklib/cmp.cpp +64 -0
- data/ext/seeklib/cmp.h +19 -0
- data/ext/seeklib/extconf.rb +5 -0
- data/ext/seeklib/haar.cpp +329 -0
- data/ext/seeklib/haar.h +70 -0
- data/ext/seeklib/sig.cpp +67 -0
- data/ext/seeklib/sig.h +56 -0
- data/lib/seeklib.rb +54 -0
- metadata +67 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 67101c1094ca597a68d498218b92b828f5e60e09
|
4
|
+
data.tar.gz: 29c5bb1e7a64e540d20e4ce004fa51dc56b1b299
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ea0954aac3fed9eb35dda4333ca2d4b954979a578ca640385eba3924e88d4fb1e7fc45f34cd06a53b2740103c0eb140ef77b91e9904c40f578e4fb27f74f87ad
|
7
|
+
data.tar.gz: bd710b7b83790eb622bd5576573173ca68bd5e531d5da368151be6b30bd6d8933568b93a2392f8fef5a6156eb8cdf3d6400acfb40eeff9bc1d993744154e2275
|
data/ext/seeklib/cmp.cpp
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#include <cmath>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <string.h>
|
4
|
+
|
5
|
+
#include "cmp.h"
|
6
|
+
#include "haar.h"
|
7
|
+
|
8
|
+
unsigned char imgBin[NUM_PIXELS_SQUARED];
|
9
|
+
int imgBinInited = 0;
|
10
|
+
|
11
|
+
void initImgBin() {
|
12
|
+
imgBinInited = 1;
|
13
|
+
|
14
|
+
/* setup initial fixed weights that each coefficient represents */
|
15
|
+
int i, j;
|
16
|
+
|
17
|
+
/*
|
18
|
+
0 1 2 3 4 5 6 i
|
19
|
+
0 0 1 2 3 4 5 5
|
20
|
+
1 1 1 2 3 4 5 5
|
21
|
+
2 2 2 2 3 4 5 5
|
22
|
+
3 3 3 3 3 4 5 5
|
23
|
+
4 4 4 4 4 4 5 5
|
24
|
+
5 5 5 5 5 5 5 5
|
25
|
+
5 5 5 5 5 5 5 5
|
26
|
+
j
|
27
|
+
*/
|
28
|
+
|
29
|
+
/* Every position has value 5, */
|
30
|
+
memset(imgBin, 5, NUM_PIXELS_SQUARED);
|
31
|
+
|
32
|
+
/* Except for the 5 by 5 upper-left quadrant: */
|
33
|
+
for (i = 0; i < 5; i++)
|
34
|
+
for (j = 0; j < 5; j++)
|
35
|
+
imgBin[i * NUM_PIXELS + j] = max(i, j);
|
36
|
+
// Note: imgBin[0] == 0
|
37
|
+
}
|
38
|
+
|
39
|
+
|
40
|
+
double calcDiff(SigStruct *siga, SigStruct *sigb) {
|
41
|
+
/* use it to tell the content-based difference between two images
|
42
|
+
*/
|
43
|
+
if (!imgBinInited) {
|
44
|
+
initImgBin();
|
45
|
+
}
|
46
|
+
double diff = calcAvglDiff(siga, sigb);
|
47
|
+
Idx *corea[3] = { siga->sig1, siga->sig2, siga->sig3 };
|
48
|
+
Idx *coreb[3] = { sigb->sig1, sigb->sig2, sigb->sig3 };
|
49
|
+
|
50
|
+
for (int b = 0; b < NUM_COEFS; b++)
|
51
|
+
for (int c = 0; c < 3; c++)
|
52
|
+
for (int b2 = 0; b2 < NUM_COEFS; b2++)
|
53
|
+
if (coreb[c][b2] == corea[c][b])
|
54
|
+
diff -= picture_weights[imgBin[abs(corea[c][b])]][c];
|
55
|
+
|
56
|
+
return diff;
|
57
|
+
}
|
58
|
+
|
59
|
+
double calcAvglDiff(SigStruct *siga, SigStruct *sigb) {
|
60
|
+
return fabs(siga->avgl[0] - sigb->avgl[0])
|
61
|
+
+ fabs(siga->avgl[1] - sigb->avgl[1])
|
62
|
+
+ fabs(siga->avgl[2] - sigb->avgl[2]);
|
63
|
+
}
|
64
|
+
|
data/ext/seeklib/cmp.h
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#ifndef CMP_H
|
2
|
+
#define CMP_H
|
3
|
+
|
4
|
+
#include "sig.h"
|
5
|
+
|
6
|
+
#ifdef __cplusplus
|
7
|
+
extern "C" {
|
8
|
+
#endif
|
9
|
+
|
10
|
+
double calcDiff(SigStruct *siga, SigStruct *sigb);
|
11
|
+
|
12
|
+
#ifdef __cplusplus
|
13
|
+
}
|
14
|
+
#endif
|
15
|
+
|
16
|
+
// not api
|
17
|
+
double calcAvglDiff(SigStruct *siga, SigStruct *sigb);
|
18
|
+
|
19
|
+
#endif // CMP_H
|
@@ -0,0 +1,329 @@
|
|
1
|
+
/***************************************************************************
|
2
|
+
imgSeek :: Haar 2d transform implemented in C/C++ to speed things up
|
3
|
+
-------------------
|
4
|
+
begin : Fri Jan 17 2003
|
5
|
+
email : ricardo.cabral|at|imgseek.net
|
6
|
+
Time-stamp: <05/01/30 19:58:56 rnc>
|
7
|
+
***************************************************************************
|
8
|
+
* Wavelet algorithms, metric and query ideas based on the paper *
|
9
|
+
* Fast Multiresolution Image Querying *
|
10
|
+
* by Charles E. Jacobs, Adam Finkelstein and David H. Salesin. *
|
11
|
+
* <http://www.cs.washington.edu/homes/salesin/abstracts.html> *
|
12
|
+
***************************************************************************
|
13
|
+
|
14
|
+
Copyright (C) 2003 Ricardo Niederberger Cabral
|
15
|
+
|
16
|
+
Clean-up and speed-ups by Geert Janssen <geert at ieee.org>, Jan 2006:
|
17
|
+
- introduced names for various `magic' numbers
|
18
|
+
- made coding style suitable for Emacs c-mode
|
19
|
+
- expressly doing constant propagation by hand (combined scalings)
|
20
|
+
- preferring pointer access over indexed access of arrays
|
21
|
+
- introduced local variables to avoid expression re-evaluations
|
22
|
+
- took out all dynamic allocations
|
23
|
+
- completely rewrote calcHaar and eliminated truncq()
|
24
|
+
- better scheme of introducing sqrt(0.5) factors borrowed from
|
25
|
+
FXT package: author Joerg Arndt, email: arndt@jjj.de,
|
26
|
+
http://www.jjj.de/
|
27
|
+
- separate processing per array: better cache behavior
|
28
|
+
- do away with all scaling; not needed except for DC component
|
29
|
+
|
30
|
+
To do:
|
31
|
+
- the whole Haar transform should be done using fixpoints
|
32
|
+
|
33
|
+
This program is free software; you can redistribute it and/or modify
|
34
|
+
it under the terms of the GNU General Public License as published by
|
35
|
+
the Free Software Foundation; either version 2 of the License, or
|
36
|
+
(at your option) any later version.
|
37
|
+
|
38
|
+
This program is distributed in the hope that it will be useful,
|
39
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
40
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
41
|
+
GNU General Public License for more details.
|
42
|
+
|
43
|
+
You should have received a copy of the GNU General Public License
|
44
|
+
along with this program; if not, write to the Free Software
|
45
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
46
|
+
*/
|
47
|
+
|
48
|
+
/* C Includes */
|
49
|
+
#include <math.h>
|
50
|
+
#include <stdio.h>
|
51
|
+
#include <stdlib.h>
|
52
|
+
#include <string.h>
|
53
|
+
|
54
|
+
/* imgSeek Includes */
|
55
|
+
#include "haar.h"
|
56
|
+
|
57
|
+
// RGB -> YIQ colorspace conversion; Y luminance, I,Q chrominance.
|
58
|
+
// If RGB in [0..255] then Y in [0..255] and I,Q in [-127..127].
|
59
|
+
#define RGB_2_YIQ(a, b, c) \
|
60
|
+
do { \
|
61
|
+
int i; \
|
62
|
+
\
|
63
|
+
for (i = 0; i < NUM_PIXELS_SQUARED; i++) { \
|
64
|
+
Unit Y, I, Q; \
|
65
|
+
\
|
66
|
+
Y = 0.299 * a[i] + 0.587 * b[i] + 0.114 * c[i]; \
|
67
|
+
I = 0.596 * a[i] - 0.275 * b[i] - 0.321 * c[i]; \
|
68
|
+
Q = 0.212 * a[i] - 0.523 * b[i] + 0.311 * c[i]; \
|
69
|
+
a[i] = Y; \
|
70
|
+
b[i] = I; \
|
71
|
+
c[i] = Q; \
|
72
|
+
} \
|
73
|
+
} while(0)
|
74
|
+
|
75
|
+
#if 0
|
76
|
+
/* Haar 2D transform.
|
77
|
+
Not doing any scaling by 1/sqrt(128).
|
78
|
+
Better cache behaviour when processing array by array.
|
79
|
+
|
80
|
+
This version needs a different imgBin array! FIXME.
|
81
|
+
*/
|
82
|
+
static void
|
83
|
+
haar2D(Unit a[])
|
84
|
+
{
|
85
|
+
int i, i1;
|
86
|
+
|
87
|
+
/* scale by 1/sqrt(128) = 0.08838834764831843: */
|
88
|
+
/*
|
89
|
+
for (i = 0; i < NUM_PIXELS_SQUARED; i++)
|
90
|
+
a[i] *= 0.08838834764831843;
|
91
|
+
*/
|
92
|
+
|
93
|
+
/* Decompose rows: */
|
94
|
+
for (i = 0; i < NUM_PIXELS_SQUARED; i = i1) {
|
95
|
+
Unit C = 1;
|
96
|
+
int l, l1;
|
97
|
+
|
98
|
+
i1 = i + NUM_PIXELS; /* start of next row, next i */
|
99
|
+
for (l = 1; l < NUM_PIXELS; l = l1) {
|
100
|
+
int j;
|
101
|
+
|
102
|
+
C *= 0.7071; /* 1/sqrt(2) */
|
103
|
+
l1 = l << 1; /* l1 = 2*l, next l */
|
104
|
+
for (j = i; j < i1; j += l1) {
|
105
|
+
int j1 = j+l;
|
106
|
+
Unit t1;
|
107
|
+
|
108
|
+
t1 = (a[j] - a[j1]) * C;
|
109
|
+
a[j] += a[j1];
|
110
|
+
a[j1] = t1;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
/* Fix first element of each row: */
|
114
|
+
a[i] *= C; /* C = 1/sqrt(NUM_PIXELS) */
|
115
|
+
}
|
116
|
+
|
117
|
+
/* scale by 1/sqrt(128) = 0.08838834764831843: */
|
118
|
+
/*
|
119
|
+
for (i = 0; i < NUM_PIXELS_SQUARED; i++)
|
120
|
+
a[i] *= 0.08838834764831843;
|
121
|
+
*/
|
122
|
+
|
123
|
+
/* Decompose columns: */
|
124
|
+
for (i = 0; i < NUM_PIXELS; i++) {
|
125
|
+
Unit C = 1;
|
126
|
+
int l, l1;
|
127
|
+
|
128
|
+
for (l = 1; l < NUM_PIXELS; l = l1) {
|
129
|
+
int j;
|
130
|
+
|
131
|
+
C *= 0.7071; /* 1/sqrt(2) = 0.7071 */
|
132
|
+
l1 = l << 1; /* l1 = 2*l, next l */
|
133
|
+
for (j = i; j < i+NUM_PIXELS_SQUARED; j += l1*NUM_PIXELS) {
|
134
|
+
int j1 = j+(l*NUM_PIXELS);
|
135
|
+
Unit t1;
|
136
|
+
|
137
|
+
t1 = (a[j] - a[j1]) * C;
|
138
|
+
a[j] += a[j1];
|
139
|
+
a[j1] = t1;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
/* Fix first element of each column: */
|
143
|
+
a[i] *= C;
|
144
|
+
}
|
145
|
+
}
|
146
|
+
#else
|
147
|
+
|
148
|
+
// Do the Haar tensorial 2d transform itself.
|
149
|
+
// Here input is RGB data [0..255] in Unit arrays
|
150
|
+
// Computation is (almost) in-situ.
|
151
|
+
static void
|
152
|
+
haar2D(Unit a[])
|
153
|
+
{
|
154
|
+
int i;
|
155
|
+
Unit t[NUM_PIXELS >> 1];
|
156
|
+
|
157
|
+
// scale by 1/sqrt(128) = 0.08838834764831843:
|
158
|
+
/*
|
159
|
+
for (i = 0; i < NUM_PIXELS_SQUARED; i++)
|
160
|
+
a[i] *= 0.08838834764831843;
|
161
|
+
*/
|
162
|
+
|
163
|
+
// Decompose rows:
|
164
|
+
for (i = 0; i < NUM_PIXELS_SQUARED; i += NUM_PIXELS) {
|
165
|
+
int h, h1;
|
166
|
+
Unit C = 1;
|
167
|
+
|
168
|
+
for (h = NUM_PIXELS; h > 1; h = h1) {
|
169
|
+
int j1, j2, k;
|
170
|
+
|
171
|
+
h1 = h >> 1; // h = 2*h1
|
172
|
+
C *= 0.7071; // 1/sqrt(2)
|
173
|
+
for (k = 0, j1 = j2 = i; k < h1; k++, j1++, j2 += 2) {
|
174
|
+
int j21 = j2+1;
|
175
|
+
|
176
|
+
t[k] = (a[j2] - a[j21]) * C;
|
177
|
+
a[j1] = (a[j2] + a[j21]);
|
178
|
+
}
|
179
|
+
// Write back subtraction results:
|
180
|
+
memcpy(a+i+h1, t, h1*sizeof(a[0]));
|
181
|
+
}
|
182
|
+
// Fix first element of each row:
|
183
|
+
a[i] *= C; // C = 1/sqrt(NUM_PIXELS)
|
184
|
+
}
|
185
|
+
|
186
|
+
// scale by 1/sqrt(128) = 0.08838834764831843:
|
187
|
+
/*
|
188
|
+
for (i = 0; i < NUM_PIXELS_SQUARED; i++)
|
189
|
+
a[i] *= 0.08838834764831843;
|
190
|
+
*/
|
191
|
+
|
192
|
+
// Decompose columns:
|
193
|
+
for (i = 0; i < NUM_PIXELS; i++) {
|
194
|
+
Unit C = 1;
|
195
|
+
int h, h1;
|
196
|
+
|
197
|
+
for (h = NUM_PIXELS; h > 1; h = h1) {
|
198
|
+
int j1, j2, k;
|
199
|
+
|
200
|
+
h1 = h >> 1;
|
201
|
+
C *= 0.7071; // 1/sqrt(2) = 0.7071
|
202
|
+
for (k = 0, j1 = j2 = i; k < h1;
|
203
|
+
k++, j1 += NUM_PIXELS, j2 += 2*NUM_PIXELS) {
|
204
|
+
int j21 = j2+NUM_PIXELS;
|
205
|
+
|
206
|
+
t[k] = (a[j2] - a[j21]) * C;
|
207
|
+
a[j1] = (a[j2] + a[j21]);
|
208
|
+
}
|
209
|
+
// Write back subtraction results:
|
210
|
+
for (k = 0, j1 = i+h1*NUM_PIXELS; k < h1; k++, j1 += NUM_PIXELS)
|
211
|
+
a[j1]=t[k];
|
212
|
+
}
|
213
|
+
// Fix first element of each column:
|
214
|
+
a[i] *= C;
|
215
|
+
}
|
216
|
+
}
|
217
|
+
#endif
|
218
|
+
|
219
|
+
/* Do the Haar tensorial 2d transform itself.
|
220
|
+
Here input is RGB data [0..255] in Unit arrays.
|
221
|
+
Results are available in a, b, and c.
|
222
|
+
Fully inplace calculation; order of result is interleaved though,
|
223
|
+
but we don't care about that.
|
224
|
+
*/
|
225
|
+
void
|
226
|
+
transform(Unit* a, Unit* b, Unit* c)
|
227
|
+
{
|
228
|
+
RGB_2_YIQ(a, b, c);
|
229
|
+
|
230
|
+
haar2D(a);
|
231
|
+
haar2D(b);
|
232
|
+
haar2D(c);
|
233
|
+
|
234
|
+
/* Reintroduce the skipped scaling factors: */
|
235
|
+
a[0] /= 256 * 128;
|
236
|
+
b[0] /= 256 * 128;
|
237
|
+
c[0] /= 256 * 128;
|
238
|
+
}
|
239
|
+
|
240
|
+
// Do the Haar tensorial 2d transform itself.
|
241
|
+
// Here input RGB data is in unsigned char arrays ([0..255])
|
242
|
+
// Results are available in a, b, and c.
|
243
|
+
void
|
244
|
+
transformChar(unsigned char* c1, unsigned char* c2, unsigned char* c3,
|
245
|
+
Unit* a, Unit* b, Unit* c)
|
246
|
+
{
|
247
|
+
int i;
|
248
|
+
Unit *p = a;
|
249
|
+
Unit *q = b;
|
250
|
+
Unit *r = c;
|
251
|
+
|
252
|
+
for (i = 0; i < NUM_PIXELS_SQUARED; i++) {
|
253
|
+
*p++ = *c1++;
|
254
|
+
*q++ = *c2++;
|
255
|
+
*r++ = *c3++;
|
256
|
+
}
|
257
|
+
transform(a, b, c);
|
258
|
+
}
|
259
|
+
|
260
|
+
// Find the NUM_COEFS largest numbers in cdata[] (in magnitude that is)
|
261
|
+
// and store their indices in sig[].
|
262
|
+
inline static void
|
263
|
+
get_m_largests(Unit *cdata, Idx *sig)
|
264
|
+
{
|
265
|
+
int cnt, i;
|
266
|
+
valStruct val;
|
267
|
+
valqueue vq; // dynamic priority queue of valStruct's
|
268
|
+
|
269
|
+
// Could skip i=0: goes into separate avgl
|
270
|
+
|
271
|
+
// Fill up the bounded queue. (Assuming NUM_PIXELS_SQUARED > NUM_COEFS)
|
272
|
+
for (i = 1; i < NUM_COEFS+1; i++) {
|
273
|
+
val.i = i;
|
274
|
+
val.d = ABS(cdata[i]);
|
275
|
+
vq.push(val);
|
276
|
+
}
|
277
|
+
// Queue is full (size is NUM_COEFS)
|
278
|
+
|
279
|
+
for (/*i = NUM_COEFS+1*/; i < NUM_PIXELS_SQUARED; i++) {
|
280
|
+
val.d = ABS(cdata[i]);
|
281
|
+
|
282
|
+
if (val.d > vq.top().d) {
|
283
|
+
// Make room by dropping smallest entry:
|
284
|
+
vq.pop();
|
285
|
+
// Insert val as new entry:
|
286
|
+
val.i = i;
|
287
|
+
vq.push(val);
|
288
|
+
}
|
289
|
+
// else discard: do nothing
|
290
|
+
}
|
291
|
+
|
292
|
+
// Empty the (non-empty) queue and fill-in sig:
|
293
|
+
cnt=0;
|
294
|
+
do {
|
295
|
+
int t;
|
296
|
+
|
297
|
+
val = vq.top();
|
298
|
+
t = (cdata[val.i] <= 0); /* t = 0 if pos else 1 */
|
299
|
+
/* i - 0 ^ 0 = i; i - 1 ^ 0b111..1111 = 2-compl(i) = -i */
|
300
|
+
sig[cnt++] = (val.i - t) ^ -t; // never 0
|
301
|
+
vq.pop();
|
302
|
+
} while(!vq.empty());
|
303
|
+
// Must have cnt==NUM_COEFS here.
|
304
|
+
}
|
305
|
+
|
306
|
+
// Determines a total of NUM_COEFS positions in the image that have the
|
307
|
+
// largest magnitude (absolute value) in color value. Returns linearized
|
308
|
+
// coordinates in sig1, sig2, and sig3. avgl are the [0,0] values.
|
309
|
+
// The order of occurrence of the coordinates in sig doesn't matter.
|
310
|
+
// Complexity is 3 x NUM_PIXELS^2 x 2log(NUM_COEFS).
|
311
|
+
int
|
312
|
+
calcHaar(Unit *cdata1, Unit *cdata2, Unit *cdata3,
|
313
|
+
Idx *sig1, Idx *sig2, Idx *sig3, double *avgl)
|
314
|
+
{
|
315
|
+
avgl[0]=cdata1[0];
|
316
|
+
avgl[1]=cdata2[0];
|
317
|
+
avgl[2]=cdata3[0];
|
318
|
+
|
319
|
+
// Color channel 1:
|
320
|
+
get_m_largests(cdata1, sig1);
|
321
|
+
|
322
|
+
// Color channel 2:
|
323
|
+
get_m_largests(cdata2, sig2);
|
324
|
+
|
325
|
+
// Color channel 3:
|
326
|
+
get_m_largests(cdata3, sig3);
|
327
|
+
|
328
|
+
return 1;
|
329
|
+
}
|
data/ext/seeklib/haar.h
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
/***************************************************************************
|
2
|
+
imgSeek :: This file is the haar 2d transform implemented in C/C++ to speed things up
|
3
|
+
-------------------
|
4
|
+
begin : Fri Jan 17 2003
|
5
|
+
email : nieder|at|mail.ru
|
6
|
+
Time-stamp: <03/05/09 21:29:35 rnc>
|
7
|
+
|
8
|
+
Copyright (C) 2003 Ricardo Niederberger Cabral
|
9
|
+
This program is free software; you can redistribute it and/or modify
|
10
|
+
it under the terms of the GNU General Public License as published by
|
11
|
+
the Free Software Foundation; either version 2 of the License, or
|
12
|
+
(at your option) any later version.
|
13
|
+
|
14
|
+
This program is distributed in the hope that it will be useful,
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
GNU General Public License for more details.
|
18
|
+
|
19
|
+
You should have received a copy of the GNU General Public License
|
20
|
+
along with this program; if not, write to the Free Software
|
21
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
22
|
+
*/
|
23
|
+
#ifndef HAAR_H
|
24
|
+
#define HAAR_H
|
25
|
+
|
26
|
+
/* STL Includes */
|
27
|
+
#include <queue>
|
28
|
+
|
29
|
+
/* Number of pixels on one side of image; required to be a power of 2. */
|
30
|
+
#define NUM_PIXELS 128
|
31
|
+
/* Totals pixels in a square image. */
|
32
|
+
#define NUM_PIXELS_SQUARED (NUM_PIXELS * NUM_PIXELS)
|
33
|
+
/* Number of Haar coeffients we retain as signature for an image. */
|
34
|
+
#define NUM_COEFS 40
|
35
|
+
|
36
|
+
#define UNIT_IS_DOUBLE
|
37
|
+
|
38
|
+
#undef ABS
|
39
|
+
#ifdef UNIT_IS_DOUBLE
|
40
|
+
#define ABS(x) fabs(x)
|
41
|
+
typedef double Unit;
|
42
|
+
#else
|
43
|
+
#define UNIT_IS_INT
|
44
|
+
#define ABS(x) abs(x)
|
45
|
+
typedef int Unit;
|
46
|
+
#endif
|
47
|
+
|
48
|
+
typedef int Idx;
|
49
|
+
|
50
|
+
/* signature structure */
|
51
|
+
typedef struct valStruct_{
|
52
|
+
Unit d; /* [f]abs(a[i]) */
|
53
|
+
int i; /* index i of a[i] */
|
54
|
+
// warning: order is inverse so valqueue is ordered smallest->biggest
|
55
|
+
bool operator< (const valStruct_ &right) const {
|
56
|
+
return d > right.d;
|
57
|
+
}
|
58
|
+
} valStruct;
|
59
|
+
|
60
|
+
typedef std::priority_queue < valStruct > valqueue;
|
61
|
+
|
62
|
+
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
63
|
+
#define min(a, b) (((a) > (b)) ? (b) : (a))
|
64
|
+
|
65
|
+
void initImgBin();
|
66
|
+
void transform(Unit* a, Unit* b, Unit* c);
|
67
|
+
void transformChar(unsigned char* c1, unsigned char* c2, unsigned char* c3, Unit* a, Unit* b, Unit* c);
|
68
|
+
int calcHaar(Unit* cdata1, Unit* cdata2, Unit* cdata3, Idx* sig1, Idx* sig2, Idx* sig3, double * avgl);
|
69
|
+
|
70
|
+
#endif
|
data/ext/seeklib/sig.cpp
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
|
3
|
+
#include <CImg.h>
|
4
|
+
|
5
|
+
#include "sig.h"
|
6
|
+
|
7
|
+
using namespace cimg_library;
|
8
|
+
|
9
|
+
SigStruct *pathSig(char *path) {
|
10
|
+
CImg<unsigned char> img(path);
|
11
|
+
SigStruct *sig = imgSig(&img);
|
12
|
+
return sig;
|
13
|
+
}
|
14
|
+
|
15
|
+
SigStruct *imgSig(CImg<unsigned char> *img) {
|
16
|
+
img->resize(NUM_PIXELS, NUM_PIXELS);
|
17
|
+
static Unit cdata1[NUM_PIXELS_SQUARED];
|
18
|
+
static Unit cdata2[NUM_PIXELS_SQUARED];
|
19
|
+
static Unit cdata3[NUM_PIXELS_SQUARED];
|
20
|
+
unsigned char rchan[NUM_PIXELS_SQUARED];
|
21
|
+
unsigned char gchan[NUM_PIXELS_SQUARED];
|
22
|
+
unsigned char bchan[NUM_PIXELS_SQUARED];
|
23
|
+
int i = 0;
|
24
|
+
cimg_for(img->get_shared_channel(0), p, unsigned char) {
|
25
|
+
rchan[i] = *p;
|
26
|
+
i++;
|
27
|
+
}
|
28
|
+
i = 0;
|
29
|
+
cimg_for(img->get_shared_channel(1), p, unsigned char) {
|
30
|
+
gchan[i] = *p;
|
31
|
+
i++;
|
32
|
+
}
|
33
|
+
i = 0;
|
34
|
+
cimg_for(img->get_shared_channel(2), p, unsigned char) {
|
35
|
+
bchan[i] = *p;
|
36
|
+
i++;
|
37
|
+
}
|
38
|
+
transformChar(rchan, gchan, bchan, cdata1, cdata2, cdata3);
|
39
|
+
SigStruct *nsig = new SigStruct();
|
40
|
+
calcHaar(cdata1, cdata2, cdata3,
|
41
|
+
nsig->sig1, nsig->sig2, nsig->sig3, nsig->avgl);
|
42
|
+
|
43
|
+
return nsig;
|
44
|
+
}
|
45
|
+
|
46
|
+
void printSig(SigStruct *sig) {
|
47
|
+
printSigSect(sig->sig1);
|
48
|
+
printSigSect(sig->sig2);
|
49
|
+
printSigSect(sig->sig3);
|
50
|
+
}
|
51
|
+
|
52
|
+
void printSigObj(SigStruct *sig) {
|
53
|
+
printSig(sig);
|
54
|
+
// avg lum
|
55
|
+
for (int i=0; i<3; i++) {
|
56
|
+
printf("%e ", sig->avgl[i]);
|
57
|
+
}
|
58
|
+
printf("\n");
|
59
|
+
}
|
60
|
+
|
61
|
+
void printSigSect(Idx *sigSect) {
|
62
|
+
for (int i=0; i<NUM_COEFS; i++) {
|
63
|
+
// typedef int Idx
|
64
|
+
printf("%d ", sigSect[i]);
|
65
|
+
}
|
66
|
+
printf("\n");
|
67
|
+
}
|
data/ext/seeklib/sig.h
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#ifndef SIG_H
|
2
|
+
#define SIG_H
|
3
|
+
|
4
|
+
#include "haar.h"
|
5
|
+
|
6
|
+
// Weights for the Haar coefficients.
|
7
|
+
// Straight from the referenced paper:
|
8
|
+
|
9
|
+
const float picture_weights[6][3] = {
|
10
|
+
// For scanned picture (sketch=0):
|
11
|
+
// Y I Q idx total occurs
|
12
|
+
{ 5.00f, 19.21f, 34.37f}, // 0 58.58 1 (`DC' component)
|
13
|
+
{ 0.83f, 1.26f, 0.36f}, // 1 2.45 3
|
14
|
+
{ 1.01f, 0.44f, 0.45f}, // 2 1.90 5
|
15
|
+
{ 0.52f, 0.53f, 0.14f}, // 3 1.19 7
|
16
|
+
{ 0.47f, 0.28f, 0.18f}, // 4 0.93 9
|
17
|
+
{ 0.30f, 0.14f, 0.27f} // 5 0.71 16384-25=16359
|
18
|
+
};
|
19
|
+
|
20
|
+
// Global typedefs
|
21
|
+
typedef long int imageId;
|
22
|
+
|
23
|
+
namespace cimg_library {
|
24
|
+
template<typename T> struct CImg;
|
25
|
+
};
|
26
|
+
|
27
|
+
#ifdef __cplusplus
|
28
|
+
extern "C" {
|
29
|
+
#endif
|
30
|
+
|
31
|
+
typedef struct _SigStruct {
|
32
|
+
Idx sig1[NUM_COEFS]; /* Y positions with largest magnitude */
|
33
|
+
Idx sig2[NUM_COEFS]; /* I positions with largest magnitude */
|
34
|
+
Idx sig3[NUM_COEFS]; /* Q positions with largest magnitude */
|
35
|
+
double avgl[3]; /* YIQ for position [0,0] */
|
36
|
+
/* image properties extracted when opened for the first time */
|
37
|
+
} SigStruct;
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
SigStruct *pathSig(char *path);
|
42
|
+
SigStruct *imgSig(cimg_library::CImg<unsigned char> *img);
|
43
|
+
// TODO: blob -> cimg
|
44
|
+
// SigStruct *blobSig(const char *blob, const long length);
|
45
|
+
|
46
|
+
|
47
|
+
#ifdef __cplusplus
|
48
|
+
}
|
49
|
+
#endif
|
50
|
+
|
51
|
+
void printSig(SigStruct *sig);
|
52
|
+
|
53
|
+
// not api
|
54
|
+
void printSigSect(Idx *sigSect);
|
55
|
+
|
56
|
+
#endif // SIG_H
|
data/lib/seeklib.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module SeekLib
|
4
|
+
extend FFI::Library
|
5
|
+
local_lib_path = File.join File.dirname(__FILE__), '..', 'ext', 'seeklib', 'seeklib.so'
|
6
|
+
if File.exists? local_lib_path
|
7
|
+
ffi_lib local_lib_path
|
8
|
+
else
|
9
|
+
ffi_lib 'seek'
|
10
|
+
end
|
11
|
+
|
12
|
+
class Sig < FFI::Struct
|
13
|
+
layout \
|
14
|
+
:sig1, [:int, 40],
|
15
|
+
:sig2, [:int, 40],
|
16
|
+
:sig3, [:int, 40],
|
17
|
+
:avgl, [:double, 3]
|
18
|
+
def get_data
|
19
|
+
[
|
20
|
+
self[:sig1].to_a,
|
21
|
+
self[:sig2].to_a,
|
22
|
+
self[:sig3].to_a,
|
23
|
+
self[:avgl].to_a
|
24
|
+
]
|
25
|
+
end
|
26
|
+
def inspect
|
27
|
+
data = get_data.map {|x| x.inspect}
|
28
|
+
"#<Sig: #{data.join ' '}>"
|
29
|
+
end
|
30
|
+
# these methods might not be fast enough, but whatever
|
31
|
+
def marshal_dump
|
32
|
+
Marshal.dump get_data
|
33
|
+
end
|
34
|
+
def marshal_load str
|
35
|
+
array = Marshal.load str
|
36
|
+
fields = [:sig1, :sig2, :sig3, :avgl]
|
37
|
+
fields.zip(array).each do |field, data|
|
38
|
+
data.each_index do |i|
|
39
|
+
self[field][i] = data[i]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
attach_function :calcDiff, [:pointer, :pointer], :double
|
46
|
+
attach_function :pathSig, [:string], :pointer
|
47
|
+
|
48
|
+
def self.path_sig path
|
49
|
+
Sig.new pathSig(path)
|
50
|
+
end
|
51
|
+
def self.calc_diff a, b
|
52
|
+
calcDiff a, b
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: seeklib
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Radetsky
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.9'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.9'
|
27
|
+
description: ffi bindings for seeklib, the fingerprint algorithm of imgseek
|
28
|
+
email:
|
29
|
+
- dradetsky@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions:
|
32
|
+
- ext/seeklib/extconf.rb
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ext/seeklib/cmp.cpp
|
36
|
+
- ext/seeklib/cmp.h
|
37
|
+
- ext/seeklib/extconf.rb
|
38
|
+
- ext/seeklib/haar.cpp
|
39
|
+
- ext/seeklib/haar.h
|
40
|
+
- ext/seeklib/sig.cpp
|
41
|
+
- ext/seeklib/sig.h
|
42
|
+
- lib/seeklib.rb
|
43
|
+
homepage: https://bitbucket.org/dradetsky/seeklib/
|
44
|
+
licenses:
|
45
|
+
- WTFPL
|
46
|
+
metadata: {}
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 2.4.7
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: seeklib ffi bindings
|
67
|
+
test_files: []
|