quirc 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/LICENSE +21 -0
- data/README.md +7 -0
- data/ext/quirc/embed/LICENSE +16 -0
- data/ext/quirc/embed/Makefile +35 -0
- data/ext/quirc/embed/lib/decode.c +913 -0
- data/ext/quirc/embed/lib/identify.c +1151 -0
- data/ext/quirc/embed/lib/quirc.c +91 -0
- data/ext/quirc/embed/lib/quirc.h +173 -0
- data/ext/quirc/embed/lib/quirc_internal.h +114 -0
- data/ext/quirc/embed/lib/version_db.c +421 -0
- data/ext/quirc/extconf.rb +20 -0
- data/ext/quirc/quirc.c +92 -0
- data/lib/quirc.rb +16 -0
- data/lib/quirc/version.rb +5 -0
- data/test/fixtures/hello-120-utf8-h.png +0 -0
- data/test/fixtures/hello-120-utf8-l.png +0 -0
- data/test/fixtures/hello-120-utf8-m.png +0 -0
- data/test/fixtures/hello-120-utf8-q.png +0 -0
- data/test/helper.rb +15 -0
- data/test/test_decode.rb +24 -0
- metadata +126 -0
@@ -0,0 +1,1151 @@
|
|
1
|
+
/* quirc - QR-code recognition library
|
2
|
+
* Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
|
3
|
+
*
|
4
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
5
|
+
* purpose with or without fee is hereby granted, provided that the above
|
6
|
+
* copyright notice and this permission notice appear in all copies.
|
7
|
+
*
|
8
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
9
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
10
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
11
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
12
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
13
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
14
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
15
|
+
*/
|
16
|
+
|
17
|
+
#include <string.h>
|
18
|
+
#include <stdlib.h>
|
19
|
+
#include <math.h>
|
20
|
+
#include "quirc_internal.h"
|
21
|
+
|
22
|
+
/************************************************************************
|
23
|
+
* Linear algebra routines
|
24
|
+
*/
|
25
|
+
|
26
|
+
static int line_intersect(const struct quirc_point *p0,
|
27
|
+
const struct quirc_point *p1,
|
28
|
+
const struct quirc_point *q0,
|
29
|
+
const struct quirc_point *q1,
|
30
|
+
struct quirc_point *r)
|
31
|
+
{
|
32
|
+
/* (a, b) is perpendicular to line p */
|
33
|
+
int a = -(p1->y - p0->y);
|
34
|
+
int b = p1->x - p0->x;
|
35
|
+
|
36
|
+
/* (c, d) is perpendicular to line q */
|
37
|
+
int c = -(q1->y - q0->y);
|
38
|
+
int d = q1->x - q0->x;
|
39
|
+
|
40
|
+
/* e and f are dot products of the respective vectors with p and q */
|
41
|
+
int e = a * p1->x + b * p1->y;
|
42
|
+
int f = c * q1->x + d * q1->y;
|
43
|
+
|
44
|
+
/* Now we need to solve:
|
45
|
+
* [a b] [rx] [e]
|
46
|
+
* [c d] [ry] = [f]
|
47
|
+
*
|
48
|
+
* We do this by inverting the matrix and applying it to (e, f):
|
49
|
+
* [ d -b] [e] [rx]
|
50
|
+
* 1/det [-c a] [f] = [ry]
|
51
|
+
*/
|
52
|
+
int det = (a * d) - (b * c);
|
53
|
+
|
54
|
+
if (!det)
|
55
|
+
return 0;
|
56
|
+
|
57
|
+
r->x = (d * e - b * f) / det;
|
58
|
+
r->y = (-c * e + a * f) / det;
|
59
|
+
|
60
|
+
return 1;
|
61
|
+
}
|
62
|
+
|
63
|
+
static void perspective_setup(double *c,
|
64
|
+
const struct quirc_point *rect,
|
65
|
+
double w, double h)
|
66
|
+
{
|
67
|
+
double x0 = rect[0].x;
|
68
|
+
double y0 = rect[0].y;
|
69
|
+
double x1 = rect[1].x;
|
70
|
+
double y1 = rect[1].y;
|
71
|
+
double x2 = rect[2].x;
|
72
|
+
double y2 = rect[2].y;
|
73
|
+
double x3 = rect[3].x;
|
74
|
+
double y3 = rect[3].y;
|
75
|
+
|
76
|
+
double wden = w * (x2*y3 - x3*y2 + (x3-x2)*y1 + x1*(y2-y3));
|
77
|
+
double hden = h * (x2*y3 + x1*(y2-y3) - x3*y2 + (x3-x2)*y1);
|
78
|
+
|
79
|
+
c[0] = (x1*(x2*y3-x3*y2) + x0*(-x2*y3+x3*y2+(x2-x3)*y1) +
|
80
|
+
x1*(x3-x2)*y0) / wden;
|
81
|
+
c[1] = -(x0*(x2*y3+x1*(y2-y3)-x2*y1) - x1*x3*y2 + x2*x3*y1
|
82
|
+
+ (x1*x3-x2*x3)*y0) / hden;
|
83
|
+
c[2] = x0;
|
84
|
+
c[3] = (y0*(x1*(y3-y2)-x2*y3+x3*y2) + y1*(x2*y3-x3*y2) +
|
85
|
+
x0*y1*(y2-y3)) / wden;
|
86
|
+
c[4] = (x0*(y1*y3-y2*y3) + x1*y2*y3 - x2*y1*y3 +
|
87
|
+
y0*(x3*y2-x1*y2+(x2-x3)*y1)) / hden;
|
88
|
+
c[5] = y0;
|
89
|
+
c[6] = (x1*(y3-y2) + x0*(y2-y3) + (x2-x3)*y1 + (x3-x2)*y0) / wden;
|
90
|
+
c[7] = (-x2*y3 + x1*y3 + x3*y2 + x0*(y1-y2) - x3*y1 + (x2-x1)*y0) /
|
91
|
+
hden;
|
92
|
+
}
|
93
|
+
|
94
|
+
static void perspective_map(const double *c,
|
95
|
+
double u, double v, struct quirc_point *ret)
|
96
|
+
{
|
97
|
+
double den = c[6]*u + c[7]*v + 1.0;
|
98
|
+
double x = (c[0]*u + c[1]*v + c[2]) / den;
|
99
|
+
double y = (c[3]*u + c[4]*v + c[5]) / den;
|
100
|
+
|
101
|
+
ret->x = rint(x);
|
102
|
+
ret->y = rint(y);
|
103
|
+
}
|
104
|
+
|
105
|
+
static void perspective_unmap(const double *c,
|
106
|
+
const struct quirc_point *in,
|
107
|
+
double *u, double *v)
|
108
|
+
{
|
109
|
+
double x = in->x;
|
110
|
+
double y = in->y;
|
111
|
+
double den = -c[0]*c[7]*y + c[1]*c[6]*y + (c[3]*c[7]-c[4]*c[6])*x +
|
112
|
+
c[0]*c[4] - c[1]*c[3];
|
113
|
+
|
114
|
+
*u = -(c[1]*(y-c[5]) - c[2]*c[7]*y + (c[5]*c[7]-c[4])*x + c[2]*c[4]) /
|
115
|
+
den;
|
116
|
+
*v = (c[0]*(y-c[5]) - c[2]*c[6]*y + (c[5]*c[6]-c[3])*x + c[2]*c[3]) /
|
117
|
+
den;
|
118
|
+
}
|
119
|
+
|
120
|
+
/************************************************************************
|
121
|
+
* Span-based floodfill routine
|
122
|
+
*/
|
123
|
+
|
124
|
+
#define FLOOD_FILL_MAX_DEPTH 4096
|
125
|
+
|
126
|
+
typedef void (*span_func_t)(void *user_data, int y, int left, int right);
|
127
|
+
|
128
|
+
static void flood_fill_seed(struct quirc *q, int x, int y, int from, int to,
|
129
|
+
span_func_t func, void *user_data,
|
130
|
+
int depth)
|
131
|
+
{
|
132
|
+
int left = x;
|
133
|
+
int right = x;
|
134
|
+
int i;
|
135
|
+
quirc_pixel_t *row = q->pixels + y * q->w;
|
136
|
+
|
137
|
+
if (depth >= FLOOD_FILL_MAX_DEPTH)
|
138
|
+
return;
|
139
|
+
|
140
|
+
while (left > 0 && row[left - 1] == from)
|
141
|
+
left--;
|
142
|
+
|
143
|
+
while (right < q->w - 1 && row[right + 1] == from)
|
144
|
+
right++;
|
145
|
+
|
146
|
+
/* Fill the extent */
|
147
|
+
for (i = left; i <= right; i++)
|
148
|
+
row[i] = to;
|
149
|
+
|
150
|
+
if (func)
|
151
|
+
func(user_data, y, left, right);
|
152
|
+
|
153
|
+
/* Seed new flood-fills */
|
154
|
+
if (y > 0) {
|
155
|
+
row = q->pixels + (y - 1) * q->w;
|
156
|
+
|
157
|
+
for (i = left; i <= right; i++)
|
158
|
+
if (row[i] == from)
|
159
|
+
flood_fill_seed(q, i, y - 1, from, to,
|
160
|
+
func, user_data, depth + 1);
|
161
|
+
}
|
162
|
+
|
163
|
+
if (y < q->h - 1) {
|
164
|
+
row = q->pixels + (y + 1) * q->w;
|
165
|
+
|
166
|
+
for (i = left; i <= right; i++)
|
167
|
+
if (row[i] == from)
|
168
|
+
flood_fill_seed(q, i, y + 1, from, to,
|
169
|
+
func, user_data, depth + 1);
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
/************************************************************************
|
174
|
+
* Adaptive thresholding
|
175
|
+
*/
|
176
|
+
|
177
|
+
#define THRESHOLD_S_MIN 1
|
178
|
+
#define THRESHOLD_S_DEN 8
|
179
|
+
#define THRESHOLD_T 5
|
180
|
+
|
181
|
+
static void threshold(struct quirc *q)
|
182
|
+
{
|
183
|
+
int x, y;
|
184
|
+
int avg_w = 0;
|
185
|
+
int avg_u = 0;
|
186
|
+
int threshold_s = q->w / THRESHOLD_S_DEN;
|
187
|
+
quirc_pixel_t *row = q->pixels;
|
188
|
+
|
189
|
+
/*
|
190
|
+
* Ensure a sane, non-zero value for threshold_s.
|
191
|
+
*
|
192
|
+
* threshold_s can be zero if the image width is small. We need to avoid
|
193
|
+
* SIGFPE as it will be used as divisor.
|
194
|
+
*/
|
195
|
+
if (threshold_s < THRESHOLD_S_MIN)
|
196
|
+
threshold_s = THRESHOLD_S_MIN;
|
197
|
+
|
198
|
+
for (y = 0; y < q->h; y++) {
|
199
|
+
int row_average[q->w];
|
200
|
+
|
201
|
+
memset(row_average, 0, sizeof(row_average));
|
202
|
+
|
203
|
+
for (x = 0; x < q->w; x++) {
|
204
|
+
int w, u;
|
205
|
+
|
206
|
+
if (y & 1) {
|
207
|
+
w = x;
|
208
|
+
u = q->w - 1 - x;
|
209
|
+
} else {
|
210
|
+
w = q->w - 1 - x;
|
211
|
+
u = x;
|
212
|
+
}
|
213
|
+
|
214
|
+
avg_w = (avg_w * (threshold_s - 1)) /
|
215
|
+
threshold_s + row[w];
|
216
|
+
avg_u = (avg_u * (threshold_s - 1)) /
|
217
|
+
threshold_s + row[u];
|
218
|
+
|
219
|
+
row_average[w] += avg_w;
|
220
|
+
row_average[u] += avg_u;
|
221
|
+
}
|
222
|
+
|
223
|
+
for (x = 0; x < q->w; x++) {
|
224
|
+
if (row[x] < row_average[x] *
|
225
|
+
(100 - THRESHOLD_T) / (200 * threshold_s))
|
226
|
+
row[x] = QUIRC_PIXEL_BLACK;
|
227
|
+
else
|
228
|
+
row[x] = QUIRC_PIXEL_WHITE;
|
229
|
+
}
|
230
|
+
|
231
|
+
row += q->w;
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
static void area_count(void *user_data, int y, int left, int right)
|
236
|
+
{
|
237
|
+
((struct quirc_region *)user_data)->count += right - left + 1;
|
238
|
+
}
|
239
|
+
|
240
|
+
static int region_code(struct quirc *q, int x, int y)
|
241
|
+
{
|
242
|
+
int pixel;
|
243
|
+
struct quirc_region *box;
|
244
|
+
int region;
|
245
|
+
|
246
|
+
if (x < 0 || y < 0 || x >= q->w || y >= q->h)
|
247
|
+
return -1;
|
248
|
+
|
249
|
+
pixel = q->pixels[y * q->w + x];
|
250
|
+
|
251
|
+
if (pixel >= QUIRC_PIXEL_REGION)
|
252
|
+
return pixel;
|
253
|
+
|
254
|
+
if (pixel == QUIRC_PIXEL_WHITE)
|
255
|
+
return -1;
|
256
|
+
|
257
|
+
if (q->num_regions >= QUIRC_MAX_REGIONS)
|
258
|
+
return -1;
|
259
|
+
|
260
|
+
region = q->num_regions;
|
261
|
+
box = &q->regions[q->num_regions++];
|
262
|
+
|
263
|
+
memset(box, 0, sizeof(*box));
|
264
|
+
|
265
|
+
box->seed.x = x;
|
266
|
+
box->seed.y = y;
|
267
|
+
box->capstone = -1;
|
268
|
+
|
269
|
+
flood_fill_seed(q, x, y, pixel, region, area_count, box, 0);
|
270
|
+
|
271
|
+
return region;
|
272
|
+
}
|
273
|
+
|
274
|
+
struct polygon_score_data {
|
275
|
+
struct quirc_point ref;
|
276
|
+
|
277
|
+
int scores[4];
|
278
|
+
struct quirc_point *corners;
|
279
|
+
};
|
280
|
+
|
281
|
+
static void find_one_corner(void *user_data, int y, int left, int right)
|
282
|
+
{
|
283
|
+
struct polygon_score_data *psd =
|
284
|
+
(struct polygon_score_data *)user_data;
|
285
|
+
int xs[2] = {left, right};
|
286
|
+
int dy = y - psd->ref.y;
|
287
|
+
int i;
|
288
|
+
|
289
|
+
for (i = 0; i < 2; i++) {
|
290
|
+
int dx = xs[i] - psd->ref.x;
|
291
|
+
int d = dx * dx + dy * dy;
|
292
|
+
|
293
|
+
if (d > psd->scores[0]) {
|
294
|
+
psd->scores[0] = d;
|
295
|
+
psd->corners[0].x = xs[i];
|
296
|
+
psd->corners[0].y = y;
|
297
|
+
}
|
298
|
+
}
|
299
|
+
}
|
300
|
+
|
301
|
+
static void find_other_corners(void *user_data, int y, int left, int right)
|
302
|
+
{
|
303
|
+
struct polygon_score_data *psd =
|
304
|
+
(struct polygon_score_data *)user_data;
|
305
|
+
int xs[2] = {left, right};
|
306
|
+
int i;
|
307
|
+
|
308
|
+
for (i = 0; i < 2; i++) {
|
309
|
+
int up = xs[i] * psd->ref.x + y * psd->ref.y;
|
310
|
+
int right = xs[i] * -psd->ref.y + y * psd->ref.x;
|
311
|
+
int scores[4] = {up, right, -up, -right};
|
312
|
+
int j;
|
313
|
+
|
314
|
+
for (j = 0; j < 4; j++) {
|
315
|
+
if (scores[j] > psd->scores[j]) {
|
316
|
+
psd->scores[j] = scores[j];
|
317
|
+
psd->corners[j].x = xs[i];
|
318
|
+
psd->corners[j].y = y;
|
319
|
+
}
|
320
|
+
}
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
static void find_region_corners(struct quirc *q,
|
325
|
+
int rcode, const struct quirc_point *ref,
|
326
|
+
struct quirc_point *corners)
|
327
|
+
{
|
328
|
+
struct quirc_region *region = &q->regions[rcode];
|
329
|
+
struct polygon_score_data psd;
|
330
|
+
int i;
|
331
|
+
|
332
|
+
memset(&psd, 0, sizeof(psd));
|
333
|
+
psd.corners = corners;
|
334
|
+
|
335
|
+
memcpy(&psd.ref, ref, sizeof(psd.ref));
|
336
|
+
psd.scores[0] = -1;
|
337
|
+
flood_fill_seed(q, region->seed.x, region->seed.y,
|
338
|
+
rcode, QUIRC_PIXEL_BLACK,
|
339
|
+
find_one_corner, &psd, 0);
|
340
|
+
|
341
|
+
psd.ref.x = psd.corners[0].x - psd.ref.x;
|
342
|
+
psd.ref.y = psd.corners[0].y - psd.ref.y;
|
343
|
+
|
344
|
+
for (i = 0; i < 4; i++)
|
345
|
+
memcpy(&psd.corners[i], ®ion->seed,
|
346
|
+
sizeof(psd.corners[i]));
|
347
|
+
|
348
|
+
i = region->seed.x * psd.ref.x + region->seed.y * psd.ref.y;
|
349
|
+
psd.scores[0] = i;
|
350
|
+
psd.scores[2] = -i;
|
351
|
+
i = region->seed.x * -psd.ref.y + region->seed.y * psd.ref.x;
|
352
|
+
psd.scores[1] = i;
|
353
|
+
psd.scores[3] = -i;
|
354
|
+
|
355
|
+
flood_fill_seed(q, region->seed.x, region->seed.y,
|
356
|
+
QUIRC_PIXEL_BLACK, rcode,
|
357
|
+
find_other_corners, &psd, 0);
|
358
|
+
}
|
359
|
+
|
360
|
+
static void record_capstone(struct quirc *q, int ring, int stone)
|
361
|
+
{
|
362
|
+
struct quirc_region *stone_reg = &q->regions[stone];
|
363
|
+
struct quirc_region *ring_reg = &q->regions[ring];
|
364
|
+
struct quirc_capstone *capstone;
|
365
|
+
int cs_index;
|
366
|
+
|
367
|
+
if (q->num_capstones >= QUIRC_MAX_CAPSTONES)
|
368
|
+
return;
|
369
|
+
|
370
|
+
cs_index = q->num_capstones;
|
371
|
+
capstone = &q->capstones[q->num_capstones++];
|
372
|
+
|
373
|
+
memset(capstone, 0, sizeof(*capstone));
|
374
|
+
|
375
|
+
capstone->qr_grid = -1;
|
376
|
+
capstone->ring = ring;
|
377
|
+
capstone->stone = stone;
|
378
|
+
stone_reg->capstone = cs_index;
|
379
|
+
ring_reg->capstone = cs_index;
|
380
|
+
|
381
|
+
/* Find the corners of the ring */
|
382
|
+
find_region_corners(q, ring, &stone_reg->seed, capstone->corners);
|
383
|
+
|
384
|
+
/* Set up the perspective transform and find the center */
|
385
|
+
perspective_setup(capstone->c, capstone->corners, 7.0, 7.0);
|
386
|
+
perspective_map(capstone->c, 3.5, 3.5, &capstone->center);
|
387
|
+
}
|
388
|
+
|
389
|
+
static void test_capstone(struct quirc *q, int x, int y, int *pb)
|
390
|
+
{
|
391
|
+
int ring_right = region_code(q, x - pb[4], y);
|
392
|
+
int stone = region_code(q, x - pb[4] - pb[3] - pb[2], y);
|
393
|
+
int ring_left = region_code(q, x - pb[4] - pb[3] -
|
394
|
+
pb[2] - pb[1] - pb[0],
|
395
|
+
y);
|
396
|
+
struct quirc_region *stone_reg;
|
397
|
+
struct quirc_region *ring_reg;
|
398
|
+
int ratio;
|
399
|
+
|
400
|
+
if (ring_left < 0 || ring_right < 0 || stone < 0)
|
401
|
+
return;
|
402
|
+
|
403
|
+
/* Left and ring of ring should be connected */
|
404
|
+
if (ring_left != ring_right)
|
405
|
+
return;
|
406
|
+
|
407
|
+
/* Ring should be disconnected from stone */
|
408
|
+
if (ring_left == stone)
|
409
|
+
return;
|
410
|
+
|
411
|
+
stone_reg = &q->regions[stone];
|
412
|
+
ring_reg = &q->regions[ring_left];
|
413
|
+
|
414
|
+
/* Already detected */
|
415
|
+
if (stone_reg->capstone >= 0 || ring_reg->capstone >= 0)
|
416
|
+
return;
|
417
|
+
|
418
|
+
/* Ratio should ideally be 37.5 */
|
419
|
+
ratio = stone_reg->count * 100 / ring_reg->count;
|
420
|
+
if (ratio < 10 || ratio > 70)
|
421
|
+
return;
|
422
|
+
|
423
|
+
record_capstone(q, ring_left, stone);
|
424
|
+
}
|
425
|
+
|
426
|
+
static void finder_scan(struct quirc *q, int y)
|
427
|
+
{
|
428
|
+
quirc_pixel_t *row = q->pixels + y * q->w;
|
429
|
+
int x;
|
430
|
+
int last_color;
|
431
|
+
int run_length = 0;
|
432
|
+
int run_count = 0;
|
433
|
+
int pb[5];
|
434
|
+
|
435
|
+
memset(pb, 0, sizeof(pb));
|
436
|
+
for (x = 0; x < q->w; x++) {
|
437
|
+
int color = row[x] ? 1 : 0;
|
438
|
+
|
439
|
+
if (x && color != last_color) {
|
440
|
+
memmove(pb, pb + 1, sizeof(pb[0]) * 4);
|
441
|
+
pb[4] = run_length;
|
442
|
+
run_length = 0;
|
443
|
+
run_count++;
|
444
|
+
|
445
|
+
if (!color && run_count >= 5) {
|
446
|
+
static int check[5] = {1, 1, 3, 1, 1};
|
447
|
+
int avg, err;
|
448
|
+
int i;
|
449
|
+
int ok = 1;
|
450
|
+
|
451
|
+
avg = (pb[0] + pb[1] + pb[3] + pb[4]) / 4;
|
452
|
+
err = avg * 3 / 4;
|
453
|
+
|
454
|
+
for (i = 0; i < 5; i++)
|
455
|
+
if (pb[i] < check[i] * avg - err ||
|
456
|
+
pb[i] > check[i] * avg + err)
|
457
|
+
ok = 0;
|
458
|
+
|
459
|
+
if (ok)
|
460
|
+
test_capstone(q, x, y, pb);
|
461
|
+
}
|
462
|
+
}
|
463
|
+
|
464
|
+
run_length++;
|
465
|
+
last_color = color;
|
466
|
+
}
|
467
|
+
}
|
468
|
+
|
469
|
+
static void find_alignment_pattern(struct quirc *q, int index)
|
470
|
+
{
|
471
|
+
struct quirc_grid *qr = &q->grids[index];
|
472
|
+
struct quirc_capstone *c0 = &q->capstones[qr->caps[0]];
|
473
|
+
struct quirc_capstone *c2 = &q->capstones[qr->caps[2]];
|
474
|
+
struct quirc_point a;
|
475
|
+
struct quirc_point b;
|
476
|
+
struct quirc_point c;
|
477
|
+
int size_estimate;
|
478
|
+
int step_size = 1;
|
479
|
+
int dir = 0;
|
480
|
+
double u, v;
|
481
|
+
|
482
|
+
/* Grab our previous estimate of the alignment pattern corner */
|
483
|
+
memcpy(&b, &qr->align, sizeof(b));
|
484
|
+
|
485
|
+
/* Guess another two corners of the alignment pattern so that we
|
486
|
+
* can estimate its size.
|
487
|
+
*/
|
488
|
+
perspective_unmap(c0->c, &b, &u, &v);
|
489
|
+
perspective_map(c0->c, u, v + 1.0, &a);
|
490
|
+
perspective_unmap(c2->c, &b, &u, &v);
|
491
|
+
perspective_map(c2->c, u + 1.0, v, &c);
|
492
|
+
|
493
|
+
size_estimate = abs((a.x - b.x) * -(c.y - b.y) +
|
494
|
+
(a.y - b.y) * (c.x - b.x));
|
495
|
+
|
496
|
+
/* Spiral outwards from the estimate point until we find something
|
497
|
+
* roughly the right size. Don't look too far from the estimate
|
498
|
+
* point.
|
499
|
+
*/
|
500
|
+
while (step_size * step_size < size_estimate * 100) {
|
501
|
+
static const int dx_map[] = {1, 0, -1, 0};
|
502
|
+
static const int dy_map[] = {0, -1, 0, 1};
|
503
|
+
int i;
|
504
|
+
|
505
|
+
for (i = 0; i < step_size; i++) {
|
506
|
+
int code = region_code(q, b.x, b.y);
|
507
|
+
|
508
|
+
if (code >= 0) {
|
509
|
+
struct quirc_region *reg = &q->regions[code];
|
510
|
+
|
511
|
+
if (reg->count >= size_estimate / 2 &&
|
512
|
+
reg->count <= size_estimate * 2) {
|
513
|
+
qr->align_region = code;
|
514
|
+
return;
|
515
|
+
}
|
516
|
+
}
|
517
|
+
|
518
|
+
b.x += dx_map[dir];
|
519
|
+
b.y += dy_map[dir];
|
520
|
+
}
|
521
|
+
|
522
|
+
dir = (dir + 1) % 4;
|
523
|
+
if (!(dir & 1))
|
524
|
+
step_size++;
|
525
|
+
}
|
526
|
+
}
|
527
|
+
|
528
|
+
static void find_leftmost_to_line(void *user_data, int y, int left, int right)
|
529
|
+
{
|
530
|
+
struct polygon_score_data *psd =
|
531
|
+
(struct polygon_score_data *)user_data;
|
532
|
+
int xs[2] = {left, right};
|
533
|
+
int i;
|
534
|
+
|
535
|
+
for (i = 0; i < 2; i++) {
|
536
|
+
int d = -psd->ref.y * xs[i] + psd->ref.x * y;
|
537
|
+
|
538
|
+
if (d < psd->scores[0]) {
|
539
|
+
psd->scores[0] = d;
|
540
|
+
psd->corners[0].x = xs[i];
|
541
|
+
psd->corners[0].y = y;
|
542
|
+
}
|
543
|
+
}
|
544
|
+
}
|
545
|
+
|
546
|
+
/* Do a Bresenham scan from one point to another and count the number
|
547
|
+
* of black/white transitions.
|
548
|
+
*/
|
549
|
+
static int timing_scan(const struct quirc *q,
|
550
|
+
const struct quirc_point *p0,
|
551
|
+
const struct quirc_point *p1)
|
552
|
+
{
|
553
|
+
int n = p1->x - p0->x;
|
554
|
+
int d = p1->y - p0->y;
|
555
|
+
int x = p0->x;
|
556
|
+
int y = p0->y;
|
557
|
+
int *dom, *nondom;
|
558
|
+
int dom_step;
|
559
|
+
int nondom_step;
|
560
|
+
int a = 0;
|
561
|
+
int i;
|
562
|
+
int run_length = 0;
|
563
|
+
int count = 0;
|
564
|
+
|
565
|
+
if (p0->x < 0 || p0->y < 0 || p0->x >= q->w || p0->y >= q->h)
|
566
|
+
return -1;
|
567
|
+
if (p1->x < 0 || p1->y < 0 || p1->x >= q->w || p1->y >= q->h)
|
568
|
+
return -1;
|
569
|
+
|
570
|
+
if (abs(n) > abs(d)) {
|
571
|
+
int swap = n;
|
572
|
+
|
573
|
+
n = d;
|
574
|
+
d = swap;
|
575
|
+
|
576
|
+
dom = &x;
|
577
|
+
nondom = &y;
|
578
|
+
} else {
|
579
|
+
dom = &y;
|
580
|
+
nondom = &x;
|
581
|
+
}
|
582
|
+
|
583
|
+
if (n < 0) {
|
584
|
+
n = -n;
|
585
|
+
nondom_step = -1;
|
586
|
+
} else {
|
587
|
+
nondom_step = 1;
|
588
|
+
}
|
589
|
+
|
590
|
+
if (d < 0) {
|
591
|
+
d = -d;
|
592
|
+
dom_step = -1;
|
593
|
+
} else {
|
594
|
+
dom_step = 1;
|
595
|
+
}
|
596
|
+
|
597
|
+
x = p0->x;
|
598
|
+
y = p0->y;
|
599
|
+
for (i = 0; i <= d; i++) {
|
600
|
+
int pixel;
|
601
|
+
|
602
|
+
if (y < 0 || y >= q->h || x < 0 || x >= q->w)
|
603
|
+
break;
|
604
|
+
|
605
|
+
pixel = q->pixels[y * q->w + x];
|
606
|
+
|
607
|
+
if (pixel) {
|
608
|
+
if (run_length >= 2)
|
609
|
+
count++;
|
610
|
+
run_length = 0;
|
611
|
+
} else {
|
612
|
+
run_length++;
|
613
|
+
}
|
614
|
+
|
615
|
+
a += n;
|
616
|
+
*dom += dom_step;
|
617
|
+
if (a >= d) {
|
618
|
+
*nondom += nondom_step;
|
619
|
+
a -= d;
|
620
|
+
}
|
621
|
+
}
|
622
|
+
|
623
|
+
return count;
|
624
|
+
}
|
625
|
+
|
626
|
+
/* Try the measure the timing pattern for a given QR code. This does
|
627
|
+
* not require the global perspective to have been set up, but it
|
628
|
+
* does require that the capstone corners have been set to their
|
629
|
+
* canonical rotation.
|
630
|
+
*
|
631
|
+
* For each capstone, we find a point in the middle of the ring band
|
632
|
+
* which is nearest the centre of the code. Using these points, we do
|
633
|
+
* a horizontal and a vertical timing scan.
|
634
|
+
*/
|
635
|
+
static int measure_timing_pattern(struct quirc *q, int index)
|
636
|
+
{
|
637
|
+
struct quirc_grid *qr = &q->grids[index];
|
638
|
+
int i;
|
639
|
+
int scan;
|
640
|
+
int ver;
|
641
|
+
int size;
|
642
|
+
|
643
|
+
for (i = 0; i < 3; i++) {
|
644
|
+
static const double us[] = {6.5, 6.5, 0.5};
|
645
|
+
static const double vs[] = {0.5, 6.5, 6.5};
|
646
|
+
struct quirc_capstone *cap = &q->capstones[qr->caps[i]];
|
647
|
+
|
648
|
+
perspective_map(cap->c, us[i], vs[i], &qr->tpep[i]);
|
649
|
+
}
|
650
|
+
|
651
|
+
qr->hscan = timing_scan(q, &qr->tpep[1], &qr->tpep[2]);
|
652
|
+
qr->vscan = timing_scan(q, &qr->tpep[1], &qr->tpep[0]);
|
653
|
+
|
654
|
+
scan = qr->hscan;
|
655
|
+
if (qr->vscan > scan)
|
656
|
+
scan = qr->vscan;
|
657
|
+
|
658
|
+
/* If neither scan worked, we can't go any further. */
|
659
|
+
if (scan < 0)
|
660
|
+
return -1;
|
661
|
+
|
662
|
+
/* Choose the nearest allowable grid size */
|
663
|
+
size = scan * 2 + 13;
|
664
|
+
ver = (size - 15) / 4;
|
665
|
+
qr->grid_size = ver * 4 + 17;
|
666
|
+
|
667
|
+
return 0;
|
668
|
+
}
|
669
|
+
|
670
|
+
/* Read a cell from a grid using the currently set perspective
|
671
|
+
* transform. Returns +/- 1 for black/white, 0 for cells which are
|
672
|
+
* out of image bounds.
|
673
|
+
*/
|
674
|
+
static int read_cell(const struct quirc *q, int index, int x, int y)
|
675
|
+
{
|
676
|
+
const struct quirc_grid *qr = &q->grids[index];
|
677
|
+
struct quirc_point p;
|
678
|
+
|
679
|
+
perspective_map(qr->c, x + 0.5, y + 0.5, &p);
|
680
|
+
if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w)
|
681
|
+
return 0;
|
682
|
+
|
683
|
+
return q->pixels[p.y * q->w + p.x] ? 1 : -1;
|
684
|
+
}
|
685
|
+
|
686
|
+
static int fitness_cell(const struct quirc *q, int index, int x, int y)
|
687
|
+
{
|
688
|
+
const struct quirc_grid *qr = &q->grids[index];
|
689
|
+
int score = 0;
|
690
|
+
int u, v;
|
691
|
+
|
692
|
+
for (v = 0; v < 3; v++)
|
693
|
+
for (u = 0; u < 3; u++) {
|
694
|
+
static const double offsets[] = {0.3, 0.5, 0.7};
|
695
|
+
struct quirc_point p;
|
696
|
+
|
697
|
+
perspective_map(qr->c, x + offsets[u],
|
698
|
+
y + offsets[v], &p);
|
699
|
+
if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w)
|
700
|
+
continue;
|
701
|
+
|
702
|
+
if (q->pixels[p.y * q->w + p.x])
|
703
|
+
score++;
|
704
|
+
else
|
705
|
+
score--;
|
706
|
+
}
|
707
|
+
|
708
|
+
return score;
|
709
|
+
}
|
710
|
+
|
711
|
+
static int fitness_ring(const struct quirc *q, int index, int cx, int cy,
|
712
|
+
int radius)
|
713
|
+
{
|
714
|
+
int i;
|
715
|
+
int score = 0;
|
716
|
+
|
717
|
+
for (i = 0; i < radius * 2; i++) {
|
718
|
+
score += fitness_cell(q, index, cx - radius + i, cy - radius);
|
719
|
+
score += fitness_cell(q, index, cx - radius, cy + radius - i);
|
720
|
+
score += fitness_cell(q, index, cx + radius, cy - radius + i);
|
721
|
+
score += fitness_cell(q, index, cx + radius - i, cy + radius);
|
722
|
+
}
|
723
|
+
|
724
|
+
return score;
|
725
|
+
}
|
726
|
+
|
727
|
+
static int fitness_apat(const struct quirc *q, int index, int cx, int cy)
|
728
|
+
{
|
729
|
+
return fitness_cell(q, index, cx, cy) -
|
730
|
+
fitness_ring(q, index, cx, cy, 1) +
|
731
|
+
fitness_ring(q, index, cx, cy, 2);
|
732
|
+
}
|
733
|
+
|
734
|
+
static int fitness_capstone(const struct quirc *q, int index, int x, int y)
|
735
|
+
{
|
736
|
+
x += 3;
|
737
|
+
y += 3;
|
738
|
+
|
739
|
+
return fitness_cell(q, index, x, y) +
|
740
|
+
fitness_ring(q, index, x, y, 1) -
|
741
|
+
fitness_ring(q, index, x, y, 2) +
|
742
|
+
fitness_ring(q, index, x, y, 3);
|
743
|
+
}
|
744
|
+
|
745
|
+
/* Compute a fitness score for the currently configured perspective
|
746
|
+
* transform, using the features we expect to find by scanning the
|
747
|
+
* grid.
|
748
|
+
*/
|
749
|
+
static int fitness_all(const struct quirc *q, int index)
|
750
|
+
{
|
751
|
+
const struct quirc_grid *qr = &q->grids[index];
|
752
|
+
int version = (qr->grid_size - 17) / 4;
|
753
|
+
const struct quirc_version_info *info = &quirc_version_db[version];
|
754
|
+
int score = 0;
|
755
|
+
int i, j;
|
756
|
+
int ap_count;
|
757
|
+
|
758
|
+
/* Check the timing pattern */
|
759
|
+
for (i = 0; i < qr->grid_size - 14; i++) {
|
760
|
+
int expect = (i & 1) ? 1 : -1;
|
761
|
+
|
762
|
+
score += fitness_cell(q, index, i + 7, 6) * expect;
|
763
|
+
score += fitness_cell(q, index, 6, i + 7) * expect;
|
764
|
+
}
|
765
|
+
|
766
|
+
/* Check capstones */
|
767
|
+
score += fitness_capstone(q, index, 0, 0);
|
768
|
+
score += fitness_capstone(q, index, qr->grid_size - 7, 0);
|
769
|
+
score += fitness_capstone(q, index, 0, qr->grid_size - 7);
|
770
|
+
|
771
|
+
if (version < 0 || version > QUIRC_MAX_VERSION)
|
772
|
+
return score;
|
773
|
+
|
774
|
+
/* Check alignment patterns */
|
775
|
+
ap_count = 0;
|
776
|
+
while ((ap_count < QUIRC_MAX_ALIGNMENT) && info->apat[ap_count])
|
777
|
+
ap_count++;
|
778
|
+
|
779
|
+
for (i = 1; i + 1 < ap_count; i++) {
|
780
|
+
score += fitness_apat(q, index, 6, info->apat[i]);
|
781
|
+
score += fitness_apat(q, index, info->apat[i], 6);
|
782
|
+
}
|
783
|
+
|
784
|
+
for (i = 1; i < ap_count; i++)
|
785
|
+
for (j = 1; j < ap_count; j++)
|
786
|
+
score += fitness_apat(q, index,
|
787
|
+
info->apat[i], info->apat[j]);
|
788
|
+
|
789
|
+
return score;
|
790
|
+
}
|
791
|
+
|
792
|
+
static void jiggle_perspective(struct quirc *q, int index)
|
793
|
+
{
|
794
|
+
struct quirc_grid *qr = &q->grids[index];
|
795
|
+
int best = fitness_all(q, index);
|
796
|
+
int pass;
|
797
|
+
double adjustments[8];
|
798
|
+
int i;
|
799
|
+
|
800
|
+
for (i = 0; i < 8; i++)
|
801
|
+
adjustments[i] = qr->c[i] * 0.02;
|
802
|
+
|
803
|
+
for (pass = 0; pass < 5; pass++) {
|
804
|
+
for (i = 0; i < 16; i++) {
|
805
|
+
int j = i >> 1;
|
806
|
+
int test;
|
807
|
+
double old = qr->c[j];
|
808
|
+
double step = adjustments[j];
|
809
|
+
double new;
|
810
|
+
|
811
|
+
if (i & 1)
|
812
|
+
new = old + step;
|
813
|
+
else
|
814
|
+
new = old - step;
|
815
|
+
|
816
|
+
qr->c[j] = new;
|
817
|
+
test = fitness_all(q, index);
|
818
|
+
|
819
|
+
if (test > best)
|
820
|
+
best = test;
|
821
|
+
else
|
822
|
+
qr->c[j] = old;
|
823
|
+
}
|
824
|
+
|
825
|
+
for (i = 0; i < 8; i++)
|
826
|
+
adjustments[i] *= 0.5;
|
827
|
+
}
|
828
|
+
}
|
829
|
+
|
830
|
+
/* Once the capstones are in place and an alignment point has been
|
831
|
+
* chosen, we call this function to set up a grid-reading perspective
|
832
|
+
* transform.
|
833
|
+
*/
|
834
|
+
static void setup_qr_perspective(struct quirc *q, int index)
|
835
|
+
{
|
836
|
+
struct quirc_grid *qr = &q->grids[index];
|
837
|
+
struct quirc_point rect[4];
|
838
|
+
|
839
|
+
/* Set up the perspective map for reading the grid */
|
840
|
+
memcpy(&rect[0], &q->capstones[qr->caps[1]].corners[0],
|
841
|
+
sizeof(rect[0]));
|
842
|
+
memcpy(&rect[1], &q->capstones[qr->caps[2]].corners[0],
|
843
|
+
sizeof(rect[0]));
|
844
|
+
memcpy(&rect[2], &qr->align, sizeof(rect[0]));
|
845
|
+
memcpy(&rect[3], &q->capstones[qr->caps[0]].corners[0],
|
846
|
+
sizeof(rect[0]));
|
847
|
+
perspective_setup(qr->c, rect, qr->grid_size - 7, qr->grid_size - 7);
|
848
|
+
|
849
|
+
jiggle_perspective(q, index);
|
850
|
+
}
|
851
|
+
|
852
|
+
/* Rotate the capstone with so that corner 0 is the leftmost with respect
|
853
|
+
* to the given reference line.
|
854
|
+
*/
|
855
|
+
static void rotate_capstone(struct quirc_capstone *cap,
|
856
|
+
const struct quirc_point *h0,
|
857
|
+
const struct quirc_point *hd)
|
858
|
+
{
|
859
|
+
struct quirc_point copy[4];
|
860
|
+
int j;
|
861
|
+
int best;
|
862
|
+
int best_score;
|
863
|
+
|
864
|
+
for (j = 0; j < 4; j++) {
|
865
|
+
struct quirc_point *p = &cap->corners[j];
|
866
|
+
int score = (p->x - h0->x) * -hd->y +
|
867
|
+
(p->y - h0->y) * hd->x;
|
868
|
+
|
869
|
+
if (!j || score < best_score) {
|
870
|
+
best = j;
|
871
|
+
best_score = score;
|
872
|
+
}
|
873
|
+
}
|
874
|
+
|
875
|
+
/* Rotate the capstone */
|
876
|
+
for (j = 0; j < 4; j++)
|
877
|
+
memcpy(©[j], &cap->corners[(j + best) % 4],
|
878
|
+
sizeof(copy[j]));
|
879
|
+
memcpy(cap->corners, copy, sizeof(cap->corners));
|
880
|
+
perspective_setup(cap->c, cap->corners, 7.0, 7.0);
|
881
|
+
}
|
882
|
+
|
883
|
+
static void record_qr_grid(struct quirc *q, int a, int b, int c)
|
884
|
+
{
|
885
|
+
struct quirc_point h0, hd;
|
886
|
+
int i;
|
887
|
+
int qr_index;
|
888
|
+
struct quirc_grid *qr;
|
889
|
+
|
890
|
+
if (q->num_grids >= QUIRC_MAX_GRIDS)
|
891
|
+
return;
|
892
|
+
|
893
|
+
/* Construct the hypotenuse line from A to C. B should be to
|
894
|
+
* the left of this line.
|
895
|
+
*/
|
896
|
+
memcpy(&h0, &q->capstones[a].center, sizeof(h0));
|
897
|
+
hd.x = q->capstones[c].center.x - q->capstones[a].center.x;
|
898
|
+
hd.y = q->capstones[c].center.y - q->capstones[a].center.y;
|
899
|
+
|
900
|
+
/* Make sure A-B-C is clockwise */
|
901
|
+
if ((q->capstones[b].center.x - h0.x) * -hd.y +
|
902
|
+
(q->capstones[b].center.y - h0.y) * hd.x > 0) {
|
903
|
+
int swap = a;
|
904
|
+
|
905
|
+
a = c;
|
906
|
+
c = swap;
|
907
|
+
hd.x = -hd.x;
|
908
|
+
hd.y = -hd.y;
|
909
|
+
}
|
910
|
+
|
911
|
+
/* Record the grid and its components */
|
912
|
+
qr_index = q->num_grids;
|
913
|
+
qr = &q->grids[q->num_grids++];
|
914
|
+
|
915
|
+
memset(qr, 0, sizeof(*qr));
|
916
|
+
qr->caps[0] = a;
|
917
|
+
qr->caps[1] = b;
|
918
|
+
qr->caps[2] = c;
|
919
|
+
qr->align_region = -1;
|
920
|
+
|
921
|
+
/* Rotate each capstone so that corner 0 is top-left with respect
|
922
|
+
* to the grid.
|
923
|
+
*/
|
924
|
+
for (i = 0; i < 3; i++) {
|
925
|
+
struct quirc_capstone *cap = &q->capstones[qr->caps[i]];
|
926
|
+
|
927
|
+
rotate_capstone(cap, &h0, &hd);
|
928
|
+
cap->qr_grid = qr_index;
|
929
|
+
}
|
930
|
+
|
931
|
+
/* Check the timing pattern. This doesn't require a perspective
|
932
|
+
* transform.
|
933
|
+
*/
|
934
|
+
if (measure_timing_pattern(q, qr_index) < 0)
|
935
|
+
goto fail;
|
936
|
+
|
937
|
+
/* Make an estimate based for the alignment pattern based on extending
|
938
|
+
* lines from capstones A and C.
|
939
|
+
*/
|
940
|
+
if (!line_intersect(&q->capstones[a].corners[0],
|
941
|
+
&q->capstones[a].corners[1],
|
942
|
+
&q->capstones[c].corners[0],
|
943
|
+
&q->capstones[c].corners[3],
|
944
|
+
&qr->align))
|
945
|
+
goto fail;
|
946
|
+
|
947
|
+
/* On V2+ grids, we should use the alignment pattern. */
|
948
|
+
if (qr->grid_size > 21) {
|
949
|
+
/* Try to find the actual location of the alignment pattern. */
|
950
|
+
find_alignment_pattern(q, qr_index);
|
951
|
+
|
952
|
+
/* Find the point of the alignment pattern closest to the
|
953
|
+
* top-left of the QR grid.
|
954
|
+
*/
|
955
|
+
if (qr->align_region >= 0) {
|
956
|
+
struct polygon_score_data psd;
|
957
|
+
struct quirc_region *reg =
|
958
|
+
&q->regions[qr->align_region];
|
959
|
+
|
960
|
+
/* Start from some point inside the alignment pattern */
|
961
|
+
memcpy(&qr->align, ®->seed, sizeof(qr->align));
|
962
|
+
|
963
|
+
memcpy(&psd.ref, &hd, sizeof(psd.ref));
|
964
|
+
psd.corners = &qr->align;
|
965
|
+
psd.scores[0] = -hd.y * qr->align.x +
|
966
|
+
hd.x * qr->align.y;
|
967
|
+
|
968
|
+
flood_fill_seed(q, reg->seed.x, reg->seed.y,
|
969
|
+
qr->align_region, QUIRC_PIXEL_BLACK,
|
970
|
+
NULL, NULL, 0);
|
971
|
+
flood_fill_seed(q, reg->seed.x, reg->seed.y,
|
972
|
+
QUIRC_PIXEL_BLACK, qr->align_region,
|
973
|
+
find_leftmost_to_line, &psd, 0);
|
974
|
+
}
|
975
|
+
}
|
976
|
+
|
977
|
+
setup_qr_perspective(q, qr_index);
|
978
|
+
return;
|
979
|
+
|
980
|
+
fail:
|
981
|
+
/* We've been unable to complete setup for this grid. Undo what we've
|
982
|
+
* recorded and pretend it never happened.
|
983
|
+
*/
|
984
|
+
for (i = 0; i < 3; i++)
|
985
|
+
q->capstones[qr->caps[i]].qr_grid = -1;
|
986
|
+
q->num_grids--;
|
987
|
+
}
|
988
|
+
|
989
|
+
struct neighbour {
|
990
|
+
int index;
|
991
|
+
double distance;
|
992
|
+
};
|
993
|
+
|
994
|
+
struct neighbour_list {
|
995
|
+
struct neighbour n[QUIRC_MAX_CAPSTONES];
|
996
|
+
int count;
|
997
|
+
};
|
998
|
+
|
999
|
+
static void test_neighbours(struct quirc *q, int i,
|
1000
|
+
const struct neighbour_list *hlist,
|
1001
|
+
const struct neighbour_list *vlist)
|
1002
|
+
{
|
1003
|
+
int j, k;
|
1004
|
+
double best_score = 0.0;
|
1005
|
+
int best_h = -1, best_v = -1;
|
1006
|
+
|
1007
|
+
/* Test each possible grouping */
|
1008
|
+
for (j = 0; j < hlist->count; j++)
|
1009
|
+
for (k = 0; k < vlist->count; k++) {
|
1010
|
+
const struct neighbour *hn = &hlist->n[j];
|
1011
|
+
const struct neighbour *vn = &vlist->n[k];
|
1012
|
+
double score = fabs(1.0 - hn->distance / vn->distance);
|
1013
|
+
|
1014
|
+
if (score > 2.5)
|
1015
|
+
continue;
|
1016
|
+
|
1017
|
+
if (best_h < 0 || score < best_score) {
|
1018
|
+
best_h = hn->index;
|
1019
|
+
best_v = vn->index;
|
1020
|
+
best_score = score;
|
1021
|
+
}
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
if (best_h < 0 || best_v < 0)
|
1025
|
+
return;
|
1026
|
+
|
1027
|
+
record_qr_grid(q, best_h, i, best_v);
|
1028
|
+
}
|
1029
|
+
|
1030
|
+
static void test_grouping(struct quirc *q, int i)
|
1031
|
+
{
|
1032
|
+
struct quirc_capstone *c1 = &q->capstones[i];
|
1033
|
+
int j;
|
1034
|
+
struct neighbour_list hlist;
|
1035
|
+
struct neighbour_list vlist;
|
1036
|
+
|
1037
|
+
if (c1->qr_grid >= 0)
|
1038
|
+
return;
|
1039
|
+
|
1040
|
+
hlist.count = 0;
|
1041
|
+
vlist.count = 0;
|
1042
|
+
|
1043
|
+
/* Look for potential neighbours by examining the relative gradients
|
1044
|
+
* from this capstone to others.
|
1045
|
+
*/
|
1046
|
+
for (j = 0; j < q->num_capstones; j++) {
|
1047
|
+
struct quirc_capstone *c2 = &q->capstones[j];
|
1048
|
+
double u, v;
|
1049
|
+
|
1050
|
+
if (i == j || c2->qr_grid >= 0)
|
1051
|
+
continue;
|
1052
|
+
|
1053
|
+
perspective_unmap(c1->c, &c2->center, &u, &v);
|
1054
|
+
|
1055
|
+
u = fabs(u - 3.5);
|
1056
|
+
v = fabs(v - 3.5);
|
1057
|
+
|
1058
|
+
if (u < 0.2 * v) {
|
1059
|
+
struct neighbour *n = &hlist.n[hlist.count++];
|
1060
|
+
|
1061
|
+
n->index = j;
|
1062
|
+
n->distance = v;
|
1063
|
+
}
|
1064
|
+
|
1065
|
+
if (v < 0.2 * u) {
|
1066
|
+
struct neighbour *n = &vlist.n[vlist.count++];
|
1067
|
+
|
1068
|
+
n->index = j;
|
1069
|
+
n->distance = u;
|
1070
|
+
}
|
1071
|
+
}
|
1072
|
+
|
1073
|
+
if (!(hlist.count && vlist.count))
|
1074
|
+
return;
|
1075
|
+
|
1076
|
+
test_neighbours(q, i, &hlist, &vlist);
|
1077
|
+
}
|
1078
|
+
|
1079
|
+
static void pixels_setup(struct quirc *q)
|
1080
|
+
{
|
1081
|
+
if (sizeof(*q->image) == sizeof(*q->pixels)) {
|
1082
|
+
q->pixels = (quirc_pixel_t *)q->image;
|
1083
|
+
} else {
|
1084
|
+
int x, y;
|
1085
|
+
for (y = 0; y < q->h; y++) {
|
1086
|
+
for (x = 0; x < q->w; x++) {
|
1087
|
+
q->pixels[y * q->w + x] = q->image[y * q->w + x];
|
1088
|
+
}
|
1089
|
+
}
|
1090
|
+
}
|
1091
|
+
}
|
1092
|
+
|
1093
|
+
uint8_t *quirc_begin(struct quirc *q, int *w, int *h)
|
1094
|
+
{
|
1095
|
+
q->num_regions = QUIRC_PIXEL_REGION;
|
1096
|
+
q->num_capstones = 0;
|
1097
|
+
q->num_grids = 0;
|
1098
|
+
|
1099
|
+
if (w)
|
1100
|
+
*w = q->w;
|
1101
|
+
if (h)
|
1102
|
+
*h = q->h;
|
1103
|
+
|
1104
|
+
return q->image;
|
1105
|
+
}
|
1106
|
+
|
1107
|
+
void quirc_end(struct quirc *q)
|
1108
|
+
{
|
1109
|
+
int i;
|
1110
|
+
|
1111
|
+
pixels_setup(q);
|
1112
|
+
threshold(q);
|
1113
|
+
|
1114
|
+
for (i = 0; i < q->h; i++)
|
1115
|
+
finder_scan(q, i);
|
1116
|
+
|
1117
|
+
for (i = 0; i < q->num_capstones; i++)
|
1118
|
+
test_grouping(q, i);
|
1119
|
+
}
|
1120
|
+
|
1121
|
+
void quirc_extract(const struct quirc *q, int index,
|
1122
|
+
struct quirc_code *code)
|
1123
|
+
{
|
1124
|
+
const struct quirc_grid *qr = &q->grids[index];
|
1125
|
+
int y;
|
1126
|
+
int i = 0;
|
1127
|
+
|
1128
|
+
if (index < 0 || index > q->num_grids)
|
1129
|
+
return;
|
1130
|
+
|
1131
|
+
memset(code, 0, sizeof(*code));
|
1132
|
+
|
1133
|
+
perspective_map(qr->c, 0.0, 0.0, &code->corners[0]);
|
1134
|
+
perspective_map(qr->c, qr->grid_size, 0.0, &code->corners[1]);
|
1135
|
+
perspective_map(qr->c, qr->grid_size, qr->grid_size,
|
1136
|
+
&code->corners[2]);
|
1137
|
+
perspective_map(qr->c, 0.0, qr->grid_size, &code->corners[3]);
|
1138
|
+
|
1139
|
+
code->size = qr->grid_size;
|
1140
|
+
|
1141
|
+
for (y = 0; y < qr->grid_size; y++) {
|
1142
|
+
int x;
|
1143
|
+
|
1144
|
+
for (x = 0; x < qr->grid_size; x++) {
|
1145
|
+
if (read_cell(q, index, x, y) > 0)
|
1146
|
+
code->cell_bitmap[i >> 3] |= (1 << (i & 7));
|
1147
|
+
|
1148
|
+
i++;
|
1149
|
+
}
|
1150
|
+
}
|
1151
|
+
}
|