Merge pull request #134 from igrr/feature/customize_fp_type
Add an option to use single-precision floating point in calculations
This commit is contained in:
commit
c8e77ce1d6
3 changed files with 100 additions and 54 deletions
36
README.md
36
README.md
|
@ -102,10 +102,10 @@ the default macros like CFLAGS from sys.mk can cause unintended effects.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
To build the library and associated demos/tests, type `make`. If you need to
|
To build the library and associated demos/tests, type `make`.
|
||||||
decode "large" image files build with `CFLAGS="-DQUIRC_MAX_REGIONS=65534" make`
|
|
||||||
instead. Note that this will increase the memory usage, it is discouraged for
|
Several options can be adjusted at compile time by passing additional arguments
|
||||||
low resource devices (i.e. embedded).
|
to `make`. See [Compile-time options](#compile-time-options) section below for details.
|
||||||
|
|
||||||
Type `make install` to install the library, header file and camera demos.
|
Type `make install` to install the library, header file and camera demos.
|
||||||
|
|
||||||
|
@ -236,6 +236,34 @@ decode attempt with the flipped image data whenever you get an ECC failure:
|
||||||
printf("Data: %s\n", data.payload);
|
printf("Data: %s\n", data.payload);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Compile-time options
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The following compile-time options can be used to adjust the library to a
|
||||||
|
particular use case.
|
||||||
|
|
||||||
|
Each option is a C preprocessor macro. To set an option, add it to CFLAGS
|
||||||
|
using `-DOPTION=VALUE` syntax, for example:
|
||||||
|
```bash
|
||||||
|
make CFLAGS="-DQUIRC_MAX_REGIONS=65534"
|
||||||
|
```
|
||||||
|
|
||||||
|
* `QUIRC_MAX_REGIONS`: If you need to decode "large" image files, set
|
||||||
|
`QUIRC_MAX_REGIONS=65534`. Note that since this will increase the memory
|
||||||
|
usage, it is discouraged for low resource devices (i.e. embedded).
|
||||||
|
|
||||||
|
* `QUIRC_FLOAT_TYPE`: If defined, it sets the type name to use
|
||||||
|
in floating point calculations. For example, on an embedded system
|
||||||
|
with only a single precision FPU, set `QUIRC_FLOAT_TYPE=float` to
|
||||||
|
improve performance.
|
||||||
|
|
||||||
|
* `QUIRC_USE_TGMATH`: if defined, quirc will internally use `<tgmath.h>`
|
||||||
|
header instead of `<math.h>`, ensuring that the math function calls
|
||||||
|
use the same precision as the arguments. Define this option if you are
|
||||||
|
setting `QUIRC_FLOAT_TYPE=float` and the compiler supports C99 or later
|
||||||
|
language standard.
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
---------
|
---------
|
||||||
Copyright (C) 2010-2012 Daniel Beer <<dlbeer@gmail.com>>
|
Copyright (C) 2010-2012 Daniel Beer <<dlbeer@gmail.com>>
|
||||||
|
|
100
lib/identify.c
100
lib/identify.c
|
@ -18,7 +18,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#ifdef QUIRC_USE_TGMATH
|
||||||
|
#include <tgmath.h>
|
||||||
|
#else
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#endif // QUIRC_USE_TGMATH
|
||||||
#include "quirc_internal.h"
|
#include "quirc_internal.h"
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
|
@ -62,21 +66,21 @@ static int line_intersect(const struct quirc_point *p0,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void perspective_setup(double *c,
|
static void perspective_setup(quirc_float_t *c,
|
||||||
const struct quirc_point *rect,
|
const struct quirc_point *rect,
|
||||||
double w, double h)
|
quirc_float_t w, quirc_float_t h)
|
||||||
{
|
{
|
||||||
double x0 = rect[0].x;
|
quirc_float_t x0 = rect[0].x;
|
||||||
double y0 = rect[0].y;
|
quirc_float_t y0 = rect[0].y;
|
||||||
double x1 = rect[1].x;
|
quirc_float_t x1 = rect[1].x;
|
||||||
double y1 = rect[1].y;
|
quirc_float_t y1 = rect[1].y;
|
||||||
double x2 = rect[2].x;
|
quirc_float_t x2 = rect[2].x;
|
||||||
double y2 = rect[2].y;
|
quirc_float_t y2 = rect[2].y;
|
||||||
double x3 = rect[3].x;
|
quirc_float_t x3 = rect[3].x;
|
||||||
double y3 = rect[3].y;
|
quirc_float_t y3 = rect[3].y;
|
||||||
|
|
||||||
double wden = w * (x2*y3 - x3*y2 + (x3-x2)*y1 + x1*(y2-y3));
|
quirc_float_t wden = w * (x2*y3 - x3*y2 + (x3-x2)*y1 + x1*(y2-y3));
|
||||||
double hden = h * (x2*y3 + x1*(y2-y3) - x3*y2 + (x3-x2)*y1);
|
quirc_float_t hden = h * (x2*y3 + x1*(y2-y3) - x3*y2 + (x3-x2)*y1);
|
||||||
|
|
||||||
c[0] = (x1*(x2*y3-x3*y2) + x0*(-x2*y3+x3*y2+(x2-x3)*y1) +
|
c[0] = (x1*(x2*y3-x3*y2) + x0*(-x2*y3+x3*y2+(x2-x3)*y1) +
|
||||||
x1*(x3-x2)*y0) / wden;
|
x1*(x3-x2)*y0) / wden;
|
||||||
|
@ -93,24 +97,24 @@ static void perspective_setup(double *c,
|
||||||
hden;
|
hden;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void perspective_map(const double *c,
|
static void perspective_map(const quirc_float_t *c,
|
||||||
double u, double v, struct quirc_point *ret)
|
quirc_float_t u, quirc_float_t v, struct quirc_point *ret)
|
||||||
{
|
{
|
||||||
double den = c[6]*u + c[7]*v + 1.0;
|
quirc_float_t den = c[6]*u + c[7]*v + 1.0;
|
||||||
double x = (c[0]*u + c[1]*v + c[2]) / den;
|
quirc_float_t x = (c[0]*u + c[1]*v + c[2]) / den;
|
||||||
double y = (c[3]*u + c[4]*v + c[5]) / den;
|
quirc_float_t y = (c[3]*u + c[4]*v + c[5]) / den;
|
||||||
|
|
||||||
ret->x = (int) rint(x);
|
ret->x = (int) rint(x);
|
||||||
ret->y = (int) rint(y);
|
ret->y = (int) rint(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void perspective_unmap(const double *c,
|
static void perspective_unmap(const quirc_float_t *c,
|
||||||
const struct quirc_point *in,
|
const struct quirc_point *in,
|
||||||
double *u, double *v)
|
quirc_float_t *u, quirc_float_t *v)
|
||||||
{
|
{
|
||||||
double x = in->x;
|
quirc_float_t x = in->x;
|
||||||
double y = in->y;
|
quirc_float_t y = in->y;
|
||||||
double den = -c[0]*c[7]*y + c[1]*c[6]*y + (c[3]*c[7]-c[4]*c[6])*x +
|
quirc_float_t den = -c[0]*c[7]*y + c[1]*c[6]*y + (c[3]*c[7]-c[4]*c[6])*x +
|
||||||
c[0]*c[4] - c[1]*c[3];
|
c[0]*c[4] - c[1]*c[3];
|
||||||
|
|
||||||
*u = -(c[1]*(y-c[5]) - c[2]*c[7]*y + (c[5]*c[7]-c[4])*x + c[2]*c[4]) /
|
*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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate weighted sum of histogram values
|
// Calculate weighted sum of histogram values
|
||||||
double sum = 0;
|
quirc_float_t sum = 0;
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
for (i = 0; i <= UINT8_MAX; ++i) {
|
for (i = 0; i <= UINT8_MAX; ++i) {
|
||||||
sum += i * histogram[i];
|
sum += i * histogram[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute threshold
|
// Compute threshold
|
||||||
double sumB = 0;
|
quirc_float_t sumB = 0;
|
||||||
unsigned int q1 = 0;
|
unsigned int q1 = 0;
|
||||||
double max = 0;
|
quirc_float_t max = 0;
|
||||||
uint8_t threshold = 0;
|
uint8_t threshold = 0;
|
||||||
for (i = 0; i <= UINT8_MAX; ++i) {
|
for (i = 0; i <= UINT8_MAX; ++i) {
|
||||||
// Weighted background
|
// Weighted background
|
||||||
|
@ -322,10 +326,10 @@ static uint8_t otsu(const struct quirc *q)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
sumB += i * histogram[i];
|
sumB += i * histogram[i];
|
||||||
const double m1 = sumB / q1;
|
const quirc_float_t m1 = sumB / q1;
|
||||||
const double m2 = (sum - sumB) / q2;
|
const quirc_float_t m2 = (sum - sumB) / q2;
|
||||||
const double m1m2 = m1 - m2;
|
const quirc_float_t m1m2 = m1 - m2;
|
||||||
const double variance = m1m2 * m1m2 * q1 * q2;
|
const quirc_float_t variance = m1m2 * m1m2 * q1 * q2;
|
||||||
if (variance >= max) {
|
if (variance >= max) {
|
||||||
threshold = i;
|
threshold = i;
|
||||||
max = variance;
|
max = variance;
|
||||||
|
@ -582,7 +586,7 @@ static void find_alignment_pattern(struct quirc *q, int index)
|
||||||
int size_estimate;
|
int size_estimate;
|
||||||
int step_size = 1;
|
int step_size = 1;
|
||||||
int dir = 0;
|
int dir = 0;
|
||||||
double u, v;
|
quirc_float_t u, v;
|
||||||
|
|
||||||
/* Grab our previous estimate of the alignment pattern corner */
|
/* Grab our previous estimate of the alignment pattern corner */
|
||||||
memcpy(&b, &qr->align, sizeof(b));
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double length(struct quirc_point a, struct quirc_point b)
|
static quirc_float_t length(struct quirc_point a, struct quirc_point b)
|
||||||
{
|
{
|
||||||
double x = abs(a.x - b.x) + 1;
|
quirc_float_t x = abs(a.x - b.x) + 1;
|
||||||
double y = abs(a.y - b.y) + 1;
|
quirc_float_t y = abs(a.y - b.y) + 1;
|
||||||
return sqrt(x * x + y * y);
|
return sqrt(x * x + y * y);
|
||||||
}
|
}
|
||||||
/* Estimate grid size by determing distance between capstones
|
/* Estimate grid size by determing distance between capstones
|
||||||
|
@ -664,15 +668,15 @@ static void measure_grid_size(struct quirc *q, int index)
|
||||||
struct quirc_capstone *b = &(q->capstones[qr->caps[1]]);
|
struct quirc_capstone *b = &(q->capstones[qr->caps[1]]);
|
||||||
struct quirc_capstone *c = &(q->capstones[qr->caps[2]]);
|
struct quirc_capstone *c = &(q->capstones[qr->caps[2]]);
|
||||||
|
|
||||||
double ab = length(b->corners[0], a->corners[3]);
|
quirc_float_t ab = length(b->corners[0], a->corners[3]);
|
||||||
double capstone_ab_size = (length(b->corners[0], b->corners[3]) + length(a->corners[0], a->corners[3]))/2.0;
|
quirc_float_t capstone_ab_size = (length(b->corners[0], b->corners[3]) + length(a->corners[0], a->corners[3]))/2.0;
|
||||||
double ver_grid = 7.0 * ab / capstone_ab_size;
|
quirc_float_t ver_grid = 7.0 * ab / capstone_ab_size;
|
||||||
|
|
||||||
double bc = length(b->corners[0], c->corners[1]);
|
quirc_float_t bc = length(b->corners[0], c->corners[1]);
|
||||||
double capstone_bc_size = (length(b->corners[0], b->corners[1]) + length(c->corners[0], c->corners[1]))/2.0;
|
quirc_float_t capstone_bc_size = (length(b->corners[0], b->corners[1]) + length(c->corners[0], c->corners[1]))/2.0;
|
||||||
double hor_grid = 7.0 * bc / capstone_bc_size;
|
quirc_float_t hor_grid = 7.0 * bc / capstone_bc_size;
|
||||||
|
|
||||||
double grid_size_estimate = (ver_grid + hor_grid) / 2;
|
quirc_float_t grid_size_estimate = (ver_grid + hor_grid) / 2;
|
||||||
|
|
||||||
int ver = (int)((grid_size_estimate - 17.0 + 2.0) / 4.0);
|
int ver = (int)((grid_size_estimate - 17.0 + 2.0) / 4.0);
|
||||||
|
|
||||||
|
@ -703,7 +707,7 @@ static int fitness_cell(const struct quirc *q, int index, int x, int y)
|
||||||
|
|
||||||
for (v = 0; v < 3; v++)
|
for (v = 0; v < 3; v++)
|
||||||
for (u = 0; u < 3; u++) {
|
for (u = 0; u < 3; u++) {
|
||||||
static const double offsets[] = {0.3, 0.5, 0.7};
|
static const quirc_float_t offsets[] = {0.3, 0.5, 0.7};
|
||||||
struct quirc_point p;
|
struct quirc_point p;
|
||||||
|
|
||||||
perspective_map(qr->c, x + offsets[u],
|
perspective_map(qr->c, x + offsets[u],
|
||||||
|
@ -806,7 +810,7 @@ static void jiggle_perspective(struct quirc *q, int index)
|
||||||
struct quirc_grid *qr = &q->grids[index];
|
struct quirc_grid *qr = &q->grids[index];
|
||||||
int best = fitness_all(q, index);
|
int best = fitness_all(q, index);
|
||||||
int pass;
|
int pass;
|
||||||
double adjustments[8];
|
quirc_float_t adjustments[8];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
|
@ -816,9 +820,9 @@ static void jiggle_perspective(struct quirc *q, int index)
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
int j = i >> 1;
|
int j = i >> 1;
|
||||||
int test;
|
int test;
|
||||||
double old = qr->c[j];
|
quirc_float_t old = qr->c[j];
|
||||||
double step = adjustments[j];
|
quirc_float_t step = adjustments[j];
|
||||||
double new;
|
quirc_float_t new;
|
||||||
|
|
||||||
if (i & 1)
|
if (i & 1)
|
||||||
new = old + step;
|
new = old + step;
|
||||||
|
@ -998,7 +1002,7 @@ fail:
|
||||||
|
|
||||||
struct neighbour {
|
struct neighbour {
|
||||||
int index;
|
int index;
|
||||||
double distance;
|
quirc_float_t distance;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct neighbour_list {
|
struct neighbour_list {
|
||||||
|
@ -1015,7 +1019,7 @@ static void test_neighbours(struct quirc *q, int i,
|
||||||
const struct neighbour *hn = &hlist->n[j];
|
const struct neighbour *hn = &hlist->n[j];
|
||||||
for (int k = 0; k < vlist->count; k++) {
|
for (int k = 0; k < vlist->count; k++) {
|
||||||
const struct neighbour *vn = &vlist->n[k];
|
const struct neighbour *vn = &vlist->n[k];
|
||||||
double squareness = fabs(1.0 - hn->distance / vn->distance);
|
quirc_float_t squareness = fabs(1.0 - hn->distance / vn->distance);
|
||||||
if (squareness < 0.2)
|
if (squareness < 0.2)
|
||||||
record_qr_grid(q, hn->index, i, vn->index);
|
record_qr_grid(q, hn->index, i, vn->index);
|
||||||
}
|
}
|
||||||
|
@ -1037,7 +1041,7 @@ static void test_grouping(struct quirc *q, unsigned int i)
|
||||||
*/
|
*/
|
||||||
for (j = 0; j < q->num_capstones; j++) {
|
for (j = 0; j < q->num_capstones; j++) {
|
||||||
struct quirc_capstone *c2 = &q->capstones[j];
|
struct quirc_capstone *c2 = &q->capstones[j];
|
||||||
double u, v;
|
quirc_float_t u, v;
|
||||||
|
|
||||||
if (i == j)
|
if (i == j)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -46,6 +46,20 @@ typedef uint16_t quirc_pixel_t;
|
||||||
#error "QUIRC_MAX_REGIONS > 65534 is not supported"
|
#error "QUIRC_MAX_REGIONS > 65534 is not supported"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef QUIRC_FLOAT_TYPE
|
||||||
|
/* Quirc uses double precision floating point internally by default.
|
||||||
|
* On platforms with a single precision FPU but no double precision FPU,
|
||||||
|
* this can be changed to float by defining QUIRC_FLOAT_TYPE.
|
||||||
|
*
|
||||||
|
* When setting QUIRC_FLOAT_TYPE to 'float', consider also defining QUIRC_USE_TGMATH.
|
||||||
|
* This will use the type-generic math functions (tgmath.h, C99 or later) instead of the normal ones,
|
||||||
|
* which will allow the compiler to use the correct overloaded functions for the type.
|
||||||
|
*/
|
||||||
|
typedef QUIRC_FLOAT_TYPE quirc_float_t;
|
||||||
|
#else
|
||||||
|
typedef double quirc_float_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct quirc_region {
|
struct quirc_region {
|
||||||
struct quirc_point seed;
|
struct quirc_point seed;
|
||||||
int count;
|
int count;
|
||||||
|
@ -58,7 +72,7 @@ struct quirc_capstone {
|
||||||
|
|
||||||
struct quirc_point corners[4];
|
struct quirc_point corners[4];
|
||||||
struct quirc_point center;
|
struct quirc_point center;
|
||||||
double c[QUIRC_PERSPECTIVE_PARAMS];
|
quirc_float_t c[QUIRC_PERSPECTIVE_PARAMS];
|
||||||
|
|
||||||
int qr_grid;
|
int qr_grid;
|
||||||
};
|
};
|
||||||
|
@ -76,7 +90,7 @@ struct quirc_grid {
|
||||||
|
|
||||||
/* Grid size and perspective transform */
|
/* Grid size and perspective transform */
|
||||||
int grid_size;
|
int grid_size;
|
||||||
double c[QUIRC_PERSPECTIVE_PARAMS];
|
quirc_float_t c[QUIRC_PERSPECTIVE_PARAMS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct quirc_flood_fill_vars {
|
struct quirc_flood_fill_vars {
|
||||||
|
|
Loading…
Reference in a new issue