Updated quirc to v1.1 (2019); patched to remove compiler warnings

This commit is contained in:
Dylan G
2020-06-03 02:13:07 +01:00
parent ca9da9d297
commit d358dd134e
6 changed files with 345 additions and 415 deletions

View File

@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
@@ -98,8 +99,8 @@ static void perspective_map(const double *c,
double x = (c[0]*u + c[1]*v + c[2]) / den;
double y = (c[3]*u + c[4]*v + c[5]) / den;
ret->x = rint(x);
ret->y = rint(y);
ret->x = (int) rint(x);
ret->y = (int) rint(y);
}
static void perspective_unmap(const double *c,
@@ -121,234 +122,113 @@ static void perspective_unmap(const double *c,
* Span-based floodfill routine
*/
#define FLOOD_FILL_MAX_DEPTH 4096
typedef void (*span_func_t)(void *user_data, int y, int left, int right);
#if 0 // recursive flood fill
#define FLOOD_FILL_MAX_DEPTH 4096
struct flood_fill_params{
struct quirc *q;
int from;
int to;
span_func_t func;
void *user_data;
};
static struct flood_fill_params ffp;
static void flood_fill_rec(int x, int y, int depth)
static void flood_fill_seed(struct quirc *q, int x, int y, int from, int to,
span_func_t func, void *user_data,
int depth)
{
int left = x;
int right = x;
int i;
quirc_pixel_t *row = ffp.q->pixels + y * ffp.q->w;
quirc_pixel_t *row = q->pixels + y * q->w;
if (!depth)
if (depth >= FLOOD_FILL_MAX_DEPTH)
return;
while (left > 0 && row[left - 1] == ffp.from)
while (left > 0 && row[left - 1] == from)
left--;
while (right < ffp.q->w - 1 && row[right + 1] == ffp.from)
while (right < q->w - 1 && row[right + 1] == from)
right++;
/* Fill the extent */
for (i = left; i <= right; i++)
row[i] = ffp.to;
row[i] = to;
if (ffp.func)
ffp.func(ffp.user_data, y, left, right);
if (func)
func(user_data, y, left, right);
/* Seed new flood-fills */
if (y > 0) {
row = ffp.q->pixels + (y - 1) * ffp.q->w;
row = q->pixels + (y - 1) * q->w;
for (i = left; i <= right; i++)
if (row[i] == ffp.from)
flood_fill_rec(i, y - 1, depth - 1);
if (row[i] == from)
flood_fill_seed(q, i, y - 1, from, to,
func, user_data, depth + 1);
}
if (y < ffp.q->h - 1) {
row = ffp.q->pixels + (y + 1) * ffp.q->w;
if (y < q->h - 1) {
row = q->pixels + (y + 1) * q->w;
for (i = left; i <= right; i++)
if (row[i] == ffp.from)
flood_fill_rec(i, y + 1, depth - 1);
if (row[i] == from)
flood_fill_seed(q, i, y + 1, from, to,
func, user_data, depth + 1);
}
}
static void flood_fill_seed(struct quirc *q, int x, int y, int from, int to,
span_func_t func, void *user_data)
{
ffp.q = q;
ffp.from = from;
ffp.to = to;
ffp.func = func;
ffp.user_data = user_data;
flood_fill_rec(x, y, FLOOD_FILL_MAX_DEPTH);
}
#else // stacked flood fill
#define FILL_STACK_CHUNK_SIZE 0x400
struct fill_stack_chunk{
int x[FILL_STACK_CHUNK_SIZE];
int y[FILL_STACK_CHUNK_SIZE];
struct fill_stack_chunk *prev;
};
struct fill_stack{
struct fill_stack_chunk *last_chunk;
int index;
};
static void fill_stack_init(struct fill_stack *s){
s->last_chunk = NULL;
}
static int fill_stack_is_empty(struct fill_stack *s){
return s->last_chunk == NULL;
}
static void fill_stack_push(struct fill_stack *s, int x, int y){
struct fill_stack_chunk *c;
if(s->last_chunk != NULL && s->index < FILL_STACK_CHUNK_SIZE - 1){
c = s->last_chunk;
s->index++;
}else{
c = (struct fill_stack_chunk*)malloc(sizeof(struct fill_stack_chunk));
if(c == NULL){
return;
}
c->prev = s->last_chunk;
s->last_chunk = c;
s->index = 0;
}
c->x[s->index] = x;
c->y[s->index] = y;
}
static void fill_stack_pop(struct fill_stack *s, int *px, int *py){
struct fill_stack_chunk *c = s->last_chunk;
if(c == NULL){
return;
}
*px = c->x[s->index];
*py = c->y[s->index];
if(s->index > 0){
s->index--;
}else{
s->last_chunk = c->prev;
s->index = FILL_STACK_CHUNK_SIZE - 1;
free(c);
}
}
static void flood_fill_seed(struct quirc *q, int start_x, int start_y, int from, int to,
span_func_t func, void *user_data)
{
struct fill_stack s;
fill_stack_init(&s);
fill_stack_push(&s, start_x, start_y);
do{
int x = 0, y = 0;
fill_stack_pop(&s, &x, &y);
int left = x, right = x, i;
quirc_pixel_t *row = q->pixels + y * q->w;
while (left > 0 && row[left - 1] == from)
left--;
while (right < q->w - 1 && row[right + 1] == from)
right++;
/* Fill the extent */
for (i = left; i <= right; i++)
row[i] = to;
if (func)
func(user_data, y, left, right);
/* Seed new flood-fills */
if (y > 0) {
row = q->pixels + (y - 1) * q->w;
for (i = left; i <= right; i++)
if (row[i] == from)
fill_stack_push(&s, i, y - 1);
}
if (y < q->h - 1) {
row = q->pixels + (y + 1) * q->w;
for (i = left; i <= right; i++)
if (row[i] == from)
fill_stack_push(&s, i, y + 1);
}
}while(!fill_stack_is_empty(&s));
}
#endif
/************************************************************************
* Adaptive thresholding
*/
#define THRESHOLD_S_DEN 8
#define THRESHOLD_T 5
static void threshold(struct quirc *q)
static uint8_t otsu(const struct quirc *q)
{
int x, y;
int avg_w = 0;
int avg_u = 0;
int threshold_s = q->w / THRESHOLD_S_DEN;
quirc_pixel_t *row = q->pixels;
int numPixels = q->w * q->h;
for (y = 0; y < q->h; y++) {
int row_average[q->w];
memset(row_average, 0, sizeof(row_average));
for (x = 0; x < q->w; x++) {
int w, u;
if (y & 1) {
w = x;
u = q->w - 1 - x;
} else {
w = q->w - 1 - x;
u = x;
}
avg_w = (avg_w * (threshold_s - 1)) /
threshold_s + row[w];
avg_u = (avg_u * (threshold_s - 1)) /
threshold_s + row[u];
row_average[w] += avg_w;
row_average[u] += avg_u;
}
for (x = 0; x < q->w; x++) {
if (row[x] < row_average[x] *
(100 - THRESHOLD_T) / (200 * threshold_s))
row[x] = QUIRC_PIXEL_BLACK;
else
row[x] = QUIRC_PIXEL_WHITE;
}
row += q->w;
// Calculate histogram
const int HISTOGRAM_SIZE = 256;
unsigned int histogram[HISTOGRAM_SIZE];
memset(histogram, 0, (HISTOGRAM_SIZE) * sizeof(unsigned int));
uint8_t* ptr = q->image;
int length = numPixels;
while (length--) {
uint8_t value = *ptr++;
histogram[value]++;
}
// Calculate weighted sum of histogram values
int sum = 0;
for (int i = 0; i < HISTOGRAM_SIZE; ++i) {
sum += i * histogram[i];
}
// Compute threshold
int sumB = 0;
int q1 = 0;
double max = 0;
uint8_t threshold = 0;
for (int i = 0; i < HISTOGRAM_SIZE; ++i) {
// Weighted background
q1 += histogram[i];
if (q1 == 0)
continue;
// Weighted foreground
const int q2 = numPixels - q1;
if (q2 == 0)
break;
sumB += i * histogram[i];
const double m1 = (double)sumB / q1;
const double m2 = ((double)sum - sumB) / q2;
const double m1m2 = m1 - m2;
const double variance = m1m2 * m1m2 * q1 * q2;
if (variance >= max) {
threshold = i;
max = variance;
}
}
return threshold;
}
static void area_count(void *user_data, int y, int left, int right)
{
(void)y;
(void)y;
((struct quirc_region *)user_data)->count += right - left + 1;
}
@@ -381,7 +261,7 @@ static int region_code(struct quirc *q, int x, int y)
box->seed.y = y;
box->capstone = -1;
flood_fill_seed(q, x, y, pixel, region, area_count, box);
flood_fill_seed(q, x, y, pixel, region, area_count, box, 0);
return region;
}
@@ -451,7 +331,7 @@ static void find_region_corners(struct quirc *q,
psd.scores[0] = -1;
flood_fill_seed(q, region->seed.x, region->seed.y,
rcode, QUIRC_PIXEL_BLACK,
find_one_corner, &psd);
find_one_corner, &psd, 0);
psd.ref.x = psd.corners[0].x - psd.ref.x;
psd.ref.y = psd.corners[0].y - psd.ref.y;
@@ -469,7 +349,7 @@ static void find_region_corners(struct quirc *q,
flood_fill_seed(q, region->seed.x, region->seed.y,
QUIRC_PIXEL_BLACK, rcode,
find_other_corners, &psd);
find_other_corners, &psd, 0);
}
static void record_capstone(struct quirc *q, int ring, int stone)
@@ -542,7 +422,7 @@ static void finder_scan(struct quirc *q, int y)
{
quirc_pixel_t *row = q->pixels + y * q->w;
int x;
int last_color;
int last_color = 0;
int run_length = 0;
int run_count = 0;
int pb[5];
@@ -888,7 +768,7 @@ static int fitness_all(const struct quirc *q, int index)
/* Check alignment patterns */
ap_count = 0;
while (info->apat[ap_count])
while ((ap_count < QUIRC_MAX_ALIGNMENT) && info->apat[ap_count])
ap_count++;
for (i = 1; i + 1 < ap_count; i++) {
@@ -974,7 +854,7 @@ static void rotate_capstone(struct quirc_capstone *cap,
struct quirc_point copy[4];
int j;
int best = 0;
int best_score = 0;
int best_score = INT_MAX;
for (j = 0; j < 4; j++) {
struct quirc_point *p = &cap->corners[j];
@@ -1082,10 +962,10 @@ static void record_qr_grid(struct quirc *q, int a, int b, int c)
flood_fill_seed(q, reg->seed.x, reg->seed.y,
qr->align_region, QUIRC_PIXEL_BLACK,
NULL, NULL);
NULL, NULL, 0);
flood_fill_seed(q, reg->seed.x, reg->seed.y,
QUIRC_PIXEL_BLACK, qr->align_region,
find_leftmost_to_line, &psd);
find_leftmost_to_line, &psd, 0);
}
}
@@ -1191,17 +1071,18 @@ static void test_grouping(struct quirc *q, int i)
test_neighbours(q, i, &hlist, &vlist);
}
static void pixels_setup(struct quirc *q)
static void pixels_setup(struct quirc *q, uint8_t threshold)
{
if (sizeof(*q->image) == sizeof(*q->pixels)) {
if (QUIRC_PIXEL_ALIAS_IMAGE) {
q->pixels = (quirc_pixel_t *)q->image;
} else {
int x, y;
for (y = 0; y < q->h; y++) {
for (x = 0; x < q->w; x++) {
q->pixels[y * q->w + x] = q->image[y * q->w + x];
}
}
}
uint8_t* source = q->image;
quirc_pixel_t* dest = q->pixels;
int length = q->w * q->h;
while (length--) {
uint8_t value = *source++;
*dest++ = (value < threshold) ? QUIRC_PIXEL_BLACK : QUIRC_PIXEL_WHITE;
}
}
@@ -1223,8 +1104,8 @@ void quirc_end(struct quirc *q)
{
int i;
pixels_setup(q);
threshold(q);
uint8_t threshold = otsu(q);
pixels_setup(q, threshold);
for (i = 0; i < q->h; i++)
finder_scan(q, i);