Skip to content

Commit c8e77ce

Browse files
authored
Merge pull request #134 from igrr/feature/customize_fp_type
Add an option to use single-precision floating point in calculations
2 parents 516d91a + cc67312 commit c8e77ce

File tree

3 files changed

+101
-55
lines changed

3 files changed

+101
-55
lines changed

README.md

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,10 @@ the default macros like CFLAGS from sys.mk can cause unintended effects.
102102

103103
Installation
104104
------------
105-
To build the library and associated demos/tests, type `make`. If you need to
106-
decode "large" image files build with `CFLAGS="-DQUIRC_MAX_REGIONS=65534" make`
107-
instead. Note that this will increase the memory usage, it is discouraged for
108-
low resource devices (i.e. embedded).
105+
To build the library and associated demos/tests, type `make`.
106+
107+
Several options can be adjusted at compile time by passing additional arguments
108+
to `make`. See [Compile-time options](#compile-time-options) section below for details.
109109

110110
Type `make install` to install the library, header file and camera demos.
111111

@@ -236,6 +236,34 @@ decode attempt with the flipped image data whenever you get an ECC failure:
236236
printf("Data: %s\n", data.payload);
237237
```
238238
239+
Compile-time options
240+
--------------------
241+
242+
The following compile-time options can be used to adjust the library to a
243+
particular use case.
244+
245+
Each option is a C preprocessor macro. To set an option, add it to CFLAGS
246+
using `-DOPTION=VALUE` syntax, for example:
247+
```bash
248+
make CFLAGS="-DQUIRC_MAX_REGIONS=65534"
249+
```
250+
251+
* `QUIRC_MAX_REGIONS`: If you need to decode "large" image files, set
252+
`QUIRC_MAX_REGIONS=65534`. Note that since this will increase the memory
253+
usage, it is discouraged for low resource devices (i.e. embedded).
254+
255+
* `QUIRC_FLOAT_TYPE`: If defined, it sets the type name to use
256+
in floating point calculations. For example, on an embedded system
257+
with only a single precision FPU, set `QUIRC_FLOAT_TYPE=float` to
258+
improve performance.
259+
260+
* `QUIRC_USE_TGMATH`: if defined, quirc will internally use `<tgmath.h>`
261+
header instead of `<math.h>`, ensuring that the math function calls
262+
use the same precision as the arguments. Define this option if you are
263+
setting `QUIRC_FLOAT_TYPE=float` and the compiler supports C99 or later
264+
language standard.
265+
266+
239267
Copyright
240268
---------
241269
Copyright (C) 2010-2012 Daniel Beer <<[email protected]>>

lib/identify.c

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
#include <string.h>
1919
#include <stdbool.h>
2020
#include <stdlib.h>
21+
#ifdef QUIRC_USE_TGMATH
22+
#include <tgmath.h>
23+
#else
2124
#include <math.h>
25+
#endif // QUIRC_USE_TGMATH
2226
#include "quirc_internal.h"
2327

2428
/************************************************************************
@@ -62,21 +66,21 @@ static int line_intersect(const struct quirc_point *p0,
6266
return 1;
6367
}
6468

65-
static void perspective_setup(double *c,
69+
static void perspective_setup(quirc_float_t *c,
6670
const struct quirc_point *rect,
67-
double w, double h)
71+
quirc_float_t w, quirc_float_t h)
6872
{
69-
double x0 = rect[0].x;
70-
double y0 = rect[0].y;
71-
double x1 = rect[1].x;
72-
double y1 = rect[1].y;
73-
double x2 = rect[2].x;
74-
double y2 = rect[2].y;
75-
double x3 = rect[3].x;
76-
double y3 = rect[3].y;
77-
78-
double wden = w * (x2*y3 - x3*y2 + (x3-x2)*y1 + x1*(y2-y3));
79-
double hden = h * (x2*y3 + x1*(y2-y3) - x3*y2 + (x3-x2)*y1);
73+
quirc_float_t x0 = rect[0].x;
74+
quirc_float_t y0 = rect[0].y;
75+
quirc_float_t x1 = rect[1].x;
76+
quirc_float_t y1 = rect[1].y;
77+
quirc_float_t x2 = rect[2].x;
78+
quirc_float_t y2 = rect[2].y;
79+
quirc_float_t x3 = rect[3].x;
80+
quirc_float_t y3 = rect[3].y;
81+
82+
quirc_float_t wden = w * (x2*y3 - x3*y2 + (x3-x2)*y1 + x1*(y2-y3));
83+
quirc_float_t hden = h * (x2*y3 + x1*(y2-y3) - x3*y2 + (x3-x2)*y1);
8084

8185
c[0] = (x1*(x2*y3-x3*y2) + x0*(-x2*y3+x3*y2+(x2-x3)*y1) +
8286
x1*(x3-x2)*y0) / wden;
@@ -93,24 +97,24 @@ static void perspective_setup(double *c,
9397
hden;
9498
}
9599

96-
static void perspective_map(const double *c,
97-
double u, double v, struct quirc_point *ret)
100+
static void perspective_map(const quirc_float_t *c,
101+
quirc_float_t u, quirc_float_t v, struct quirc_point *ret)
98102
{
99-
double den = c[6]*u + c[7]*v + 1.0;
100-
double x = (c[0]*u + c[1]*v + c[2]) / den;
101-
double y = (c[3]*u + c[4]*v + c[5]) / den;
103+
quirc_float_t den = c[6]*u + c[7]*v + 1.0;
104+
quirc_float_t x = (c[0]*u + c[1]*v + c[2]) / den;
105+
quirc_float_t y = (c[3]*u + c[4]*v + c[5]) / den;
102106

103107
ret->x = (int) rint(x);
104108
ret->y = (int) rint(y);
105109
}
106110

107-
static void perspective_unmap(const double *c,
111+
static void perspective_unmap(const quirc_float_t *c,
108112
const struct quirc_point *in,
109-
double *u, double *v)
113+
quirc_float_t *u, quirc_float_t *v)
110114
{
111-
double x = in->x;
112-
double y = in->y;
113-
double den = -c[0]*c[7]*y + c[1]*c[6]*y + (c[3]*c[7]-c[4]*c[6])*x +
115+
quirc_float_t x = in->x;
116+
quirc_float_t y = in->y;
117+
quirc_float_t den = -c[0]*c[7]*y + c[1]*c[6]*y + (c[3]*c[7]-c[4]*c[6])*x +
114118
c[0]*c[4] - c[1]*c[3];
115119

116120
*u = -(c[1]*(y-c[5]) - c[2]*c[7]*y + (c[5]*c[7]-c[4])*x + c[2]*c[4]) /
@@ -299,16 +303,16 @@ static uint8_t otsu(const struct quirc *q)
299303
}
300304

301305
// Calculate weighted sum of histogram values
302-
double sum = 0;
306+
quirc_float_t sum = 0;
303307
unsigned int i = 0;
304308
for (i = 0; i <= UINT8_MAX; ++i) {
305309
sum += i * histogram[i];
306310
}
307311

308312
// Compute threshold
309-
double sumB = 0;
313+
quirc_float_t sumB = 0;
310314
unsigned int q1 = 0;
311-
double max = 0;
315+
quirc_float_t max = 0;
312316
uint8_t threshold = 0;
313317
for (i = 0; i <= UINT8_MAX; ++i) {
314318
// Weighted background
@@ -322,10 +326,10 @@ static uint8_t otsu(const struct quirc *q)
322326
break;
323327

324328
sumB += i * histogram[i];
325-
const double m1 = sumB / q1;
326-
const double m2 = (sum - sumB) / q2;
327-
const double m1m2 = m1 - m2;
328-
const double variance = m1m2 * m1m2 * q1 * q2;
329+
const quirc_float_t m1 = sumB / q1;
330+
const quirc_float_t m2 = (sum - sumB) / q2;
331+
const quirc_float_t m1m2 = m1 - m2;
332+
const quirc_float_t variance = m1m2 * m1m2 * q1 * q2;
329333
if (variance >= max) {
330334
threshold = i;
331335
max = variance;
@@ -582,7 +586,7 @@ static void find_alignment_pattern(struct quirc *q, int index)
582586
int size_estimate;
583587
int step_size = 1;
584588
int dir = 0;
585-
double u, v;
589+
quirc_float_t u, v;
586590

587591
/* Grab our previous estimate of the alignment pattern corner */
588592
memcpy(&b, &qr->align, sizeof(b));
@@ -648,10 +652,10 @@ static void find_leftmost_to_line(void *user_data, int y, int left, int right)
648652
}
649653
}
650654

651-
static double length(struct quirc_point a, struct quirc_point b)
655+
static quirc_float_t length(struct quirc_point a, struct quirc_point b)
652656
{
653-
double x = abs(a.x - b.x) + 1;
654-
double y = abs(a.y - b.y) + 1;
657+
quirc_float_t x = abs(a.x - b.x) + 1;
658+
quirc_float_t y = abs(a.y - b.y) + 1;
655659
return sqrt(x * x + y * y);
656660
}
657661
/* Estimate grid size by determing distance between capstones
@@ -664,15 +668,15 @@ static void measure_grid_size(struct quirc *q, int index)
664668
struct quirc_capstone *b = &(q->capstones[qr->caps[1]]);
665669
struct quirc_capstone *c = &(q->capstones[qr->caps[2]]);
666670

667-
double ab = length(b->corners[0], a->corners[3]);
668-
double capstone_ab_size = (length(b->corners[0], b->corners[3]) + length(a->corners[0], a->corners[3]))/2.0;
669-
double ver_grid = 7.0 * ab / capstone_ab_size;
671+
quirc_float_t ab = length(b->corners[0], a->corners[3]);
672+
quirc_float_t capstone_ab_size = (length(b->corners[0], b->corners[3]) + length(a->corners[0], a->corners[3]))/2.0;
673+
quirc_float_t ver_grid = 7.0 * ab / capstone_ab_size;
670674

671-
double bc = length(b->corners[0], c->corners[1]);
672-
double capstone_bc_size = (length(b->corners[0], b->corners[1]) + length(c->corners[0], c->corners[1]))/2.0;
673-
double hor_grid = 7.0 * bc / capstone_bc_size;
675+
quirc_float_t bc = length(b->corners[0], c->corners[1]);
676+
quirc_float_t capstone_bc_size = (length(b->corners[0], b->corners[1]) + length(c->corners[0], c->corners[1]))/2.0;
677+
quirc_float_t hor_grid = 7.0 * bc / capstone_bc_size;
674678

675-
double grid_size_estimate = (ver_grid + hor_grid) / 2;
679+
quirc_float_t grid_size_estimate = (ver_grid + hor_grid) / 2;
676680

677681
int ver = (int)((grid_size_estimate - 17.0 + 2.0) / 4.0);
678682

@@ -703,7 +707,7 @@ static int fitness_cell(const struct quirc *q, int index, int x, int y)
703707

704708
for (v = 0; v < 3; v++)
705709
for (u = 0; u < 3; u++) {
706-
static const double offsets[] = {0.3, 0.5, 0.7};
710+
static const quirc_float_t offsets[] = {0.3, 0.5, 0.7};
707711
struct quirc_point p;
708712

709713
perspective_map(qr->c, x + offsets[u],
@@ -806,7 +810,7 @@ static void jiggle_perspective(struct quirc *q, int index)
806810
struct quirc_grid *qr = &q->grids[index];
807811
int best = fitness_all(q, index);
808812
int pass;
809-
double adjustments[8];
813+
quirc_float_t adjustments[8];
810814
int i;
811815

812816
for (i = 0; i < 8; i++)
@@ -816,9 +820,9 @@ static void jiggle_perspective(struct quirc *q, int index)
816820
for (i = 0; i < 16; i++) {
817821
int j = i >> 1;
818822
int test;
819-
double old = qr->c[j];
820-
double step = adjustments[j];
821-
double new;
823+
quirc_float_t old = qr->c[j];
824+
quirc_float_t step = adjustments[j];
825+
quirc_float_t new;
822826

823827
if (i & 1)
824828
new = old + step;
@@ -998,7 +1002,7 @@ static void record_qr_grid(struct quirc *q, int a, int b, int c)
9981002

9991003
struct neighbour {
10001004
int index;
1001-
double distance;
1005+
quirc_float_t distance;
10021006
};
10031007

10041008
struct neighbour_list {
@@ -1015,7 +1019,7 @@ static void test_neighbours(struct quirc *q, int i,
10151019
const struct neighbour *hn = &hlist->n[j];
10161020
for (int k = 0; k < vlist->count; k++) {
10171021
const struct neighbour *vn = &vlist->n[k];
1018-
double squareness = fabs(1.0 - hn->distance / vn->distance);
1022+
quirc_float_t squareness = fabs(1.0 - hn->distance / vn->distance);
10191023
if (squareness < 0.2)
10201024
record_qr_grid(q, hn->index, i, vn->index);
10211025
}
@@ -1037,7 +1041,7 @@ static void test_grouping(struct quirc *q, unsigned int i)
10371041
*/
10381042
for (j = 0; j < q->num_capstones; j++) {
10391043
struct quirc_capstone *c2 = &q->capstones[j];
1040-
double u, v;
1044+
quirc_float_t u, v;
10411045

10421046
if (i == j)
10431047
continue;

lib/quirc_internal.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,20 @@ typedef uint16_t quirc_pixel_t;
4646
#error "QUIRC_MAX_REGIONS > 65534 is not supported"
4747
#endif
4848

49+
#ifdef QUIRC_FLOAT_TYPE
50+
/* Quirc uses double precision floating point internally by default.
51+
* On platforms with a single precision FPU but no double precision FPU,
52+
* this can be changed to float by defining QUIRC_FLOAT_TYPE.
53+
*
54+
* When setting QUIRC_FLOAT_TYPE to 'float', consider also defining QUIRC_USE_TGMATH.
55+
* This will use the type-generic math functions (tgmath.h, C99 or later) instead of the normal ones,
56+
* which will allow the compiler to use the correct overloaded functions for the type.
57+
*/
58+
typedef QUIRC_FLOAT_TYPE quirc_float_t;
59+
#else
60+
typedef double quirc_float_t;
61+
#endif
62+
4963
struct quirc_region {
5064
struct quirc_point seed;
5165
int count;
@@ -58,7 +72,7 @@ struct quirc_capstone {
5872

5973
struct quirc_point corners[4];
6074
struct quirc_point center;
61-
double c[QUIRC_PERSPECTIVE_PARAMS];
75+
quirc_float_t c[QUIRC_PERSPECTIVE_PARAMS];
6276

6377
int qr_grid;
6478
};
@@ -76,7 +90,7 @@ struct quirc_grid {
7690

7791
/* Grid size and perspective transform */
7892
int grid_size;
79-
double c[QUIRC_PERSPECTIVE_PARAMS];
93+
quirc_float_t c[QUIRC_PERSPECTIVE_PARAMS];
8094
};
8195

8296
struct quirc_flood_fill_vars {

0 commit comments

Comments
 (0)