LCOV - code coverage report
Current view: top level - src/decode - decoder_grid.c (source / functions) Coverage Total Hit
Test: lierre Coverage Report Lines: 96.2 % 290 279
Test Date: 2026-03-06 08:40:14 Functions: 100.0 % 20 20
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * liblierre - decoder_grid.c
       3              :  *
       4              :  * This file is part of liblierre.
       5              :  *
       6              :  * Author: Go Kudo <zeriyoshi@gmail.com>
       7              :  * SPDX-License-Identifier: MIT AND ISC
       8              :  *
       9              :  * This file contains code derived from quirc (https://github.com/dlbeer/quirc).
      10              :  * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
      11              :  * Licensed under the ISC License.
      12              :  */
      13              : 
      14              : #include "../internal/decoder.h"
      15              : 
      16              : #define QR_VERSION_MIN               1
      17              : #define QR_VERSION1_SIZE             17
      18              : #define QR_VERSION_SIZE_INCREMENT    4
      19              : #define QR_VERSION_ESTIMATION_OFFSET 15.0
      20              : #define QR_VERSION2_MIN_SIZE         21
      21              : 
      22              : #define FINDER_PATTERN_SIZE   7
      23              : #define FINDER_PATTERN_CENTER 3
      24              : 
      25              : #define TIMING_PATTERN_POSITION 6
      26              : #define TIMING_PATTERN_OFFSET   7
      27              : #define TIMING_PATTERN_MARGIN   14
      28              : 
      29              : #define PERSPECTIVE_ADJUSTMENT_FACTOR 0.02
      30              : #define PERSPECTIVE_STEP_DECAY        0.5
      31              : #define PERSPECTIVE_REFINEMENT_PASSES 5
      32              : #define PERSPECTIVE_PARAM_ITERATIONS  16
      33              : 
      34              : #define CELL_SAMPLE_COUNT    3
      35              : #define CELL_SAMPLE_OFFSET_1 0.3
      36              : #define CELL_SAMPLE_OFFSET_2 0.5
      37              : #define CELL_SAMPLE_OFFSET_3 0.7
      38              : #define CELL_CENTER_OFFSET   0.5
      39              : 
      40              : #define ROUNDING_OFFSET 0.5
      41              : #define AVERAGE_FACTOR  0.5
      42              : #define AVERAGE_DIVISOR 2.0
      43              : 
      44              : #define ALIGNMENT_RING_RADIUS_1 1
      45              : #define ALIGNMENT_RING_RADIUS_2 2
      46              : #define ALIGNMENT_RING_RADIUS_3 3
      47              : 
      48              : #define ALIGNMENT_SEARCH_AREA_FACTOR 100
      49              : #define ALIGNMENT_SIZE_FACTOR_MIN    2
      50              : #define ALIGNMENT_SIZE_FACTOR_MAX    2
      51              : #define SPIRAL_DIRECTION_COUNT       4
      52              : 
      53              : #define NUM_CORNERS   4
      54              : #define NUM_CAPSTONES 3
      55              : 
      56              : #define SQUARENESS_THRESHOLD 0.2
      57              : 
      58              : const version_info_t lierre_version_db[LIERRE_DECODER_MAX_VERSION + 1] = {
      59              :     {0, {0}, {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}},
      60              :     {26, {0}, {{26, 16, 1}, {26, 19, 1}, {26, 9, 1}, {26, 13, 1}}},
      61              :     {44, {6, 18, 0}, {{44, 28, 1}, {44, 34, 1}, {44, 16, 1}, {44, 22, 1}}},
      62              :     {70, {6, 22, 0}, {{70, 44, 1}, {70, 55, 1}, {35, 13, 2}, {35, 17, 2}}},
      63              :     {100, {6, 26, 0}, {{50, 32, 2}, {100, 80, 1}, {25, 9, 4}, {50, 24, 2}}},
      64              :     {134, {6, 30, 0}, {{67, 43, 2}, {134, 108, 1}, {33, 11, 2}, {33, 15, 2}}},
      65              :     {172, {6, 34, 0}, {{43, 27, 4}, {86, 68, 2}, {43, 15, 4}, {43, 19, 4}}},
      66              :     {196, {6, 22, 38, 0}, {{49, 31, 4}, {98, 78, 2}, {39, 13, 4}, {32, 14, 2}}},
      67              :     {242, {6, 24, 42, 0}, {{60, 38, 2}, {121, 97, 2}, {40, 14, 4}, {40, 18, 4}}},
      68              :     {292, {6, 26, 46, 0}, {{58, 36, 3}, {146, 116, 2}, {36, 12, 4}, {36, 16, 4}}},
      69              :     {346, {6, 28, 50, 0}, {{69, 43, 4}, {86, 68, 2}, {43, 15, 6}, {43, 19, 6}}},
      70              :     {404, {6, 30, 54, 0}, {{80, 50, 1}, {101, 81, 4}, {36, 12, 3}, {50, 22, 4}}},
      71              :     {466, {6, 32, 58, 0}, {{58, 36, 6}, {116, 92, 2}, {42, 14, 7}, {46, 20, 4}}},
      72              :     {532, {6, 34, 62, 0}, {{59, 37, 8}, {133, 107, 4}, {33, 11, 12}, {44, 20, 8}}},
      73              :     {581, {6, 26, 46, 66, 0}, {{64, 40, 4}, {145, 115, 3}, {36, 12, 11}, {36, 16, 11}}},
      74              :     {655, {6, 26, 48, 70, 0}, {{65, 41, 5}, {109, 87, 5}, {36, 12, 11}, {54, 24, 5}}},
      75              :     {733, {6, 26, 50, 74, 0}, {{73, 45, 7}, {122, 98, 5}, {45, 15, 3}, {43, 19, 15}}},
      76              :     {815, {6, 30, 54, 78, 0}, {{74, 46, 10}, {135, 107, 1}, {42, 14, 2}, {50, 22, 1}}},
      77              :     {901, {6, 30, 56, 82, 0}, {{69, 43, 9}, {150, 120, 5}, {42, 14, 2}, {50, 22, 17}}},
      78              :     {991, {6, 30, 58, 86, 0}, {{70, 44, 3}, {141, 113, 3}, {39, 13, 9}, {47, 21, 17}}},
      79              :     {1085, {6, 34, 62, 90, 0}, {{67, 41, 3}, {135, 107, 3}, {43, 15, 15}, {54, 24, 15}}},
      80              :     {1156, {6, 28, 50, 72, 94, 0}, {{68, 42, 17}, {144, 116, 4}, {46, 16, 19}, {50, 22, 17}}},
      81              :     {1258, {6, 26, 50, 74, 98, 0}, {{74, 46, 17}, {139, 111, 2}, {37, 13, 34}, {54, 24, 7}}},
      82              :     {1364, {6, 30, 54, 78, 102, 0}, {{75, 47, 4}, {151, 121, 4}, {45, 15, 16}, {54, 24, 11}}},
      83              :     {1474, {6, 28, 54, 80, 106, 0}, {{73, 45, 6}, {147, 117, 6}, {46, 16, 30}, {54, 24, 11}}},
      84              :     {1588, {6, 32, 58, 84, 110, 0}, {{75, 47, 8}, {132, 106, 8}, {45, 15, 22}, {54, 24, 7}}},
      85              :     {1706, {6, 30, 58, 86, 114, 0}, {{74, 46, 19}, {142, 114, 10}, {46, 16, 33}, {50, 22, 28}}},
      86              :     {1828, {6, 34, 62, 90, 118, 0}, {{73, 45, 22}, {152, 122, 8}, {45, 15, 12}, {53, 23, 8}}},
      87              :     {1921, {6, 26, 50, 74, 98, 122, 0}, {{73, 45, 3}, {147, 117, 3}, {45, 15, 11}, {54, 24, 4}}},
      88              :     {2051, {6, 30, 54, 78, 102, 126, 0}, {{73, 45, 21}, {146, 116, 7}, {45, 15, 19}, {53, 23, 1}}},
      89              :     {2185, {6, 26, 52, 78, 104, 130, 0}, {{75, 47, 19}, {145, 115, 5}, {45, 15, 23}, {54, 24, 15}}},
      90              :     {2323, {6, 30, 56, 82, 108, 134, 0}, {{74, 46, 2}, {145, 115, 13}, {45, 15, 23}, {54, 24, 42}}},
      91              :     {2465, {6, 34, 60, 86, 112, 138, 0}, {{74, 46, 10}, {145, 115, 17}, {45, 15, 19}, {54, 24, 10}}},
      92              :     {2611, {6, 30, 58, 86, 114, 142, 0}, {{74, 46, 14}, {145, 115, 17}, {45, 15, 11}, {54, 24, 29}}},
      93              :     {2761, {6, 34, 62, 90, 118, 146, 0}, {{74, 46, 14}, {145, 115, 13}, {46, 16, 59}, {54, 24, 44}}},
      94              :     {2876, {6, 30, 54, 78, 102, 126, 150, 0}, {{75, 47, 12}, {151, 121, 12}, {45, 15, 22}, {54, 24, 39}}},
      95              :     {3034, {6, 24, 50, 76, 102, 128, 154, 0}, {{75, 47, 6}, {151, 121, 6}, {45, 15, 2}, {54, 24, 46}}},
      96              :     {3196, {6, 28, 54, 80, 106, 132, 158, 0}, {{74, 46, 29}, {152, 122, 17}, {45, 15, 24}, {54, 24, 49}}},
      97              :     {3362, {6, 32, 58, 84, 110, 136, 162, 0}, {{74, 46, 13}, {152, 122, 4}, {45, 15, 42}, {54, 24, 48}}},
      98              :     {3532, {6, 26, 54, 82, 110, 138, 166, 0}, {{75, 47, 40}, {147, 117, 20}, {45, 15, 10}, {54, 24, 43}}},
      99              :     {3706, {6, 30, 58, 86, 114, 142, 170, 0}, {{75, 47, 18}, {148, 118, 19}, {45, 15, 20}, {54, 24, 34}}}};
     100              : 
     101     59376704 : extern void perspective_map(const double *coeffs, double u, double v, decoder_point_t *result)
     102              : {
     103              :     double denominator, x, y;
     104              : 
     105     59376704 :     denominator = 1.0 / (coeffs[6] * u + coeffs[7] * v + 1.0);
     106     59376704 :     x = (coeffs[0] * u + coeffs[1] * v + coeffs[2]) * denominator;
     107     59376704 :     y = (coeffs[3] * u + coeffs[4] * v + coeffs[5]) * denominator;
     108              : 
     109     59376704 :     result->x = (int32_t)(x + ROUNDING_OFFSET);
     110     59376704 :     result->y = (int32_t)(y + ROUNDING_OFFSET);
     111     59376704 : }
     112              : 
     113          882 : extern void perspective_setup(double *coeffs, const decoder_point_t *corners, double width, double height)
     114              : {
     115              :     double x0, y0, x1, y1, x2, y2, x3, y3, width_denominator, height_denominator;
     116              : 
     117          882 :     x0 = corners[0].x;
     118          882 :     y0 = corners[0].y;
     119          882 :     x1 = corners[1].x;
     120          882 :     y1 = corners[1].y;
     121          882 :     x2 = corners[2].x;
     122          882 :     y2 = corners[2].y;
     123          882 :     x3 = corners[3].x;
     124          882 :     y3 = corners[3].y;
     125              : 
     126          882 :     width_denominator = 1.0 / (width * (x2 * y3 - x3 * y2 + (x3 - x2) * y1 + x1 * (y2 - y3)));
     127          882 :     height_denominator = 1.0 / (height * (x2 * y3 + x1 * (y2 - y3) - x3 * y2 + (x3 - x2) * y1));
     128              : 
     129          882 :     coeffs[0] = (x1 * (x2 * y3 - x3 * y2) + x0 * (-x2 * y3 + x3 * y2 + (x2 - x3) * y1) + x1 * (x3 - x2) * y0) *
     130              :                 width_denominator;
     131          882 :     coeffs[1] = -(x0 * (x2 * y3 + x1 * (y2 - y3) - x2 * y1) - x1 * x3 * y2 + x2 * x3 * y1 + (x1 * x3 - x2 * x3) * y0) *
     132              :                 height_denominator;
     133          882 :     coeffs[2] = x0;
     134          882 :     coeffs[3] = (y0 * (x1 * (y3 - y2) - x2 * y3 + x3 * y2) + y1 * (x2 * y3 - x3 * y2) + x0 * y1 * (y2 - y3)) *
     135              :                 width_denominator;
     136          882 :     coeffs[4] = (x0 * (y1 * y3 - y2 * y3) + x1 * y2 * y3 - x2 * y1 * y3 + y0 * (x3 * y2 - x1 * y2 + (x2 - x3) * y1)) *
     137              :                 height_denominator;
     138          882 :     coeffs[5] = y0;
     139          882 :     coeffs[6] = (x1 * (y3 - y2) + x0 * (y2 - y3) + (x2 - x3) * y1 + (x3 - x2) * y0) * width_denominator;
     140          882 :     coeffs[7] = (-x2 * y3 + x1 * y3 + x3 * y2 + x0 * (y1 - y2) - x3 * y1 + (x2 - x1) * y0) * height_denominator;
     141          882 : }
     142              : 
     143         1216 : extern void perspective_unmap(const double *coeffs, const decoder_point_t *image_point, double *grid_u, double *grid_v)
     144              : {
     145              :     double x, y, denominator;
     146              : 
     147         1216 :     x = (double)image_point->x;
     148         1216 :     y = (double)image_point->y;
     149         1216 :     denominator =
     150         1216 :         1.0 / (-coeffs[0] * coeffs[7] * y + coeffs[1] * coeffs[6] * y +
     151         1216 :                (coeffs[3] * coeffs[7] - coeffs[4] * coeffs[6]) * x + coeffs[0] * coeffs[4] - coeffs[1] * coeffs[3]);
     152              : 
     153         1216 :     *grid_u = -(coeffs[1] * (y - coeffs[5]) - coeffs[2] * coeffs[7] * y + (coeffs[5] * coeffs[7] - coeffs[4]) * x +
     154         1216 :                 coeffs[2] * coeffs[4]) *
     155              :               denominator;
     156         1216 :     *grid_v = (coeffs[0] * (y - coeffs[5]) - coeffs[2] * coeffs[6] * y + (coeffs[5] * coeffs[6] - coeffs[3]) * x +
     157         1216 :                coeffs[2] * coeffs[3]) *
     158              :               denominator;
     159         1216 : }
     160              : 
     161          129 : static inline int32_t compute_line_intersection(const decoder_point_t *line1_start, const decoder_point_t *line1_end,
     162              :                                                 const decoder_point_t *line2_start, const decoder_point_t *line2_end,
     163              :                                                 decoder_point_t *intersection)
     164              : {
     165              :     int32_t a, b, c, d, e, f, determinant;
     166              : 
     167          129 :     a = -(line1_end->y - line1_start->y);
     168          129 :     b = line1_end->x - line1_start->x;
     169          129 :     c = -(line2_end->y - line2_start->y);
     170          129 :     d = line2_end->x - line2_start->x;
     171          129 :     e = a * line1_end->x + b * line1_end->y;
     172          129 :     f = c * line2_end->x + d * line2_end->y;
     173              : 
     174          129 :     determinant = a * d - b * c;
     175          129 :     if (!determinant) {
     176            0 :         return 0;
     177              :     }
     178              : 
     179          129 :     intersection->x = (d * e - b * f) / determinant;
     180          129 :     intersection->y = (-c * e + a * f) / determinant;
     181              : 
     182          129 :     return 1;
     183              : }
     184              : 
     185          774 : static inline double compute_point_distance(const decoder_point_t *point_a, const decoder_point_t *point_b)
     186              : {
     187              :     double delta_x, delta_y;
     188              : 
     189          774 :     delta_x = (double)abs(point_a->x - point_b->x) + 1.0;
     190          774 :     delta_y = (double)abs(point_a->y - point_b->y) + 1.0;
     191              : 
     192          774 :     return sqrt(delta_x * delta_x + delta_y * delta_y);
     193              : }
     194              : 
     195          129 : static inline void estimate_grid_size(decoder_t *decoder, int32_t grid_index)
     196              : {
     197              :     grid_t *grid;
     198              :     capstone_t *cap_a, *cap_b, *cap_c;
     199              :     int32_t version;
     200              :     double distance_ab, distance_bc, capstone_ab_size, capstone_bc_size, vertical_modules, horizontal_modules,
     201              :         average_modules;
     202              : 
     203          129 :     grid = &decoder->grids[grid_index];
     204          129 :     cap_a = &decoder->capstones[grid->caps[0]];
     205          129 :     cap_b = &decoder->capstones[grid->caps[1]];
     206          129 :     cap_c = &decoder->capstones[grid->caps[2]];
     207              : 
     208          129 :     distance_ab = compute_point_distance(&cap_b->corners[0], &cap_a->corners[3]);
     209          129 :     capstone_ab_size = (compute_point_distance(&cap_b->corners[0], &cap_b->corners[3]) +
     210          129 :                         compute_point_distance(&cap_a->corners[0], &cap_a->corners[3])) /
     211              :                        AVERAGE_DIVISOR;
     212          129 :     vertical_modules = (double)FINDER_PATTERN_SIZE * distance_ab / capstone_ab_size;
     213              : 
     214          129 :     distance_bc = compute_point_distance(&cap_b->corners[0], &cap_c->corners[1]);
     215          129 :     capstone_bc_size = (compute_point_distance(&cap_b->corners[0], &cap_b->corners[1]) +
     216          129 :                         compute_point_distance(&cap_c->corners[0], &cap_c->corners[1])) /
     217              :                        AVERAGE_DIVISOR;
     218          129 :     horizontal_modules = (double)FINDER_PATTERN_SIZE * distance_bc / capstone_bc_size;
     219              : 
     220          129 :     average_modules = (vertical_modules + horizontal_modules) * AVERAGE_FACTOR;
     221          129 :     version = (int32_t)((average_modules - QR_VERSION_ESTIMATION_OFFSET) / (double)QR_VERSION_SIZE_INCREMENT);
     222              : 
     223          129 :     if (version < QR_VERSION_MIN) {
     224            0 :         version = QR_VERSION_MIN;
     225              :     }
     226              : 
     227          129 :     if (version > LIERRE_DECODER_MAX_VERSION) {
     228            0 :         version = LIERRE_DECODER_MAX_VERSION;
     229              :     }
     230              : 
     231          129 :     grid->grid_size = QR_VERSION_SIZE_INCREMENT * version + QR_VERSION1_SIZE;
     232          129 : }
     233              : 
     234      1063285 : static inline int32_t read_grid_cell(const decoder_t *decoder, int32_t grid_index, int32_t x, int32_t y)
     235              : {
     236              :     const grid_t *grid;
     237              :     decoder_point_t image_point;
     238              : 
     239      1063285 :     grid = &decoder->grids[grid_index];
     240      1063285 :     perspective_map(grid->c, (double)x + CELL_CENTER_OFFSET, (double)y + CELL_CENTER_OFFSET, &image_point);
     241              : 
     242      1061469 :     if (image_point.y < 0 || image_point.y >= decoder->h || image_point.x < 0 || image_point.x >= decoder->w) {
     243            0 :         return 0;
     244              :     }
     245              : 
     246      1064425 :     return decoder->pixels[image_point.y * decoder->w + image_point.x] ? 1 : -1;
     247              : }
     248              : 
     249      6479352 : static inline int32_t compute_cell_fitness(const decoder_t *decoder, int32_t grid_index, int32_t x, int32_t y)
     250              : {
     251              :     static const double sample_offsets[CELL_SAMPLE_COUNT] = {CELL_SAMPLE_OFFSET_1, CELL_SAMPLE_OFFSET_2,
     252              :                                                              CELL_SAMPLE_OFFSET_3};
     253              :     const grid_t *grid;
     254              :     decoder_point_t image_point;
     255              :     int32_t score, sample_x, sample_y;
     256              : 
     257      6479352 :     grid = &decoder->grids[grid_index];
     258      6479352 :     score = 0;
     259              : 
     260     25917408 :     for (sample_y = 0; sample_y < CELL_SAMPLE_COUNT; sample_y++) {
     261     77752224 :         for (sample_x = 0; sample_x < CELL_SAMPLE_COUNT; sample_x++) {
     262     58314168 :             perspective_map(grid->c, (double)x + sample_offsets[sample_x], (double)y + sample_offsets[sample_y],
     263              :                             &image_point);
     264              : 
     265     58314168 :             if (image_point.y < 0 || image_point.y >= decoder->h || image_point.x < 0 || image_point.x >= decoder->w) {
     266       117277 :                 continue;
     267              :             }
     268              : 
     269     58196891 :             if (decoder->pixels[image_point.y * decoder->w + image_point.x]) {
     270     36087148 :                 score++;
     271              :             } else {
     272     22109743 :                 score--;
     273              :             }
     274              :         }
     275              :     }
     276              : 
     277      6479352 :     return score;
     278              : }
     279              : 
     280       384183 : static inline int32_t compute_ring_fitness(const decoder_t *decoder, int32_t grid_index, int32_t center_x,
     281              :                                            int32_t center_y, int32_t radius)
     282              : {
     283              :     int32_t i, score;
     284              : 
     285       384183 :     score = 0;
     286              : 
     287      1630773 :     for (i = 0; i < radius * 2; i++) {
     288      1246590 :         score += compute_cell_fitness(decoder, grid_index, center_x - radius + i, center_y - radius);
     289      1246590 :         score += compute_cell_fitness(decoder, grid_index, center_x - radius, center_y + radius - i);
     290      1246590 :         score += compute_cell_fitness(decoder, grid_index, center_x + radius, center_y - radius + i);
     291      1246590 :         score += compute_cell_fitness(decoder, grid_index, center_x + radius - i, center_y + radius);
     292              :     }
     293              : 
     294       384183 :     return score;
     295              : }
     296              : 
     297       145071 : static inline int32_t compute_alignment_pattern_fitness(const decoder_t *decoder, int32_t grid_index, int32_t center_x,
     298              :                                                         int32_t center_y)
     299              : {
     300       145071 :     return compute_cell_fitness(decoder, grid_index, center_x, center_y) -
     301       290142 :            compute_ring_fitness(decoder, grid_index, center_x, center_y, ALIGNMENT_RING_RADIUS_1) +
     302       145071 :            compute_ring_fitness(decoder, grid_index, center_x, center_y, ALIGNMENT_RING_RADIUS_2);
     303              : }
     304              : 
     305        31347 : static inline int32_t compute_capstone_fitness(const decoder_t *decoder, int32_t grid_index, int32_t x, int32_t y)
     306              : {
     307        31347 :     x += FINDER_PATTERN_CENTER;
     308        31347 :     y += FINDER_PATTERN_CENTER;
     309              : 
     310        31347 :     return compute_cell_fitness(decoder, grid_index, x, y) +
     311        31347 :            compute_ring_fitness(decoder, grid_index, x, y, ALIGNMENT_RING_RADIUS_1) -
     312        62694 :            compute_ring_fitness(decoder, grid_index, x, y, ALIGNMENT_RING_RADIUS_2) +
     313        31347 :            compute_ring_fitness(decoder, grid_index, x, y, ALIGNMENT_RING_RADIUS_3);
     314              : }
     315              : 
     316        10449 : static inline int32_t compute_total_grid_fitness(const decoder_t *decoder, int32_t grid_index)
     317              : {
     318              :     const grid_t *grid;
     319              :     const version_info_t *version_info;
     320              :     int32_t version, score, i, j, alignment_count, expected_value;
     321              : 
     322        10449 :     grid = &decoder->grids[grid_index];
     323        10449 :     version = (grid->grid_size - QR_VERSION1_SIZE) / QR_VERSION_SIZE_INCREMENT;
     324              : 
     325        10449 :     if (version < QR_VERSION_MIN || version > LIERRE_DECODER_MAX_VERSION) {
     326            0 :         return 0;
     327              :     }
     328              : 
     329        10449 :     version_info = &lierre_version_db[version];
     330        10449 :     score = 0;
     331              : 
     332       668736 :     for (i = 0; i < grid->grid_size - TIMING_PATTERN_MARGIN; i++) {
     333       658287 :         expected_value = (i & 1) ? 1 : -1;
     334       658287 :         score += compute_cell_fitness(decoder, grid_index, i + TIMING_PATTERN_OFFSET, TIMING_PATTERN_POSITION) *
     335              :                  expected_value;
     336       658287 :         score += compute_cell_fitness(decoder, grid_index, TIMING_PATTERN_POSITION, i + TIMING_PATTERN_OFFSET) *
     337              :                  expected_value;
     338              :     }
     339              : 
     340        10449 :     score += compute_capstone_fitness(decoder, grid_index, 0, 0);
     341        10449 :     score += compute_capstone_fitness(decoder, grid_index, grid->grid_size - FINDER_PATTERN_SIZE, 0);
     342        10449 :     score += compute_capstone_fitness(decoder, grid_index, 0, grid->grid_size - FINDER_PATTERN_SIZE);
     343              : 
     344        10449 :     alignment_count = 0;
     345        46008 :     while (alignment_count < LIERRE_DECODER_MAX_ALIGNMENT && version_info->apat[alignment_count]) {
     346        35559 :         alignment_count++;
     347              :     }
     348              : 
     349        28512 :     for (i = 1; i + 1 < alignment_count; i++) {
     350        18063 :         score += compute_alignment_pattern_fitness(decoder, grid_index, TIMING_PATTERN_POSITION, version_info->apat[i]);
     351        18063 :         score += compute_alignment_pattern_fitness(decoder, grid_index, version_info->apat[i], TIMING_PATTERN_POSITION);
     352              :     }
     353              : 
     354        37260 :     for (i = 1; i < alignment_count; i++) {
     355       135756 :         for (j = 1; j < alignment_count; j++) {
     356       108945 :             score +=
     357       108945 :                 compute_alignment_pattern_fitness(decoder, grid_index, version_info->apat[i], version_info->apat[j]);
     358              :         }
     359              :     }
     360              : 
     361        10449 :     return score;
     362              : }
     363              : 
     364          129 : static inline void refine_perspective(decoder_t *decoder, int32_t grid_index)
     365              : {
     366              :     grid_t *grid;
     367              :     int32_t best_fitness, pass, i, j, test_fitness;
     368              :     double adjustment_steps[LIERRE_DECODER_PERSPECTIVE_PARAMS], original_value, step, new_value;
     369              : 
     370          129 :     grid = &decoder->grids[grid_index];
     371          129 :     best_fitness = compute_total_grid_fitness(decoder, grid_index);
     372              : 
     373         1161 :     for (i = 0; i < LIERRE_DECODER_PERSPECTIVE_PARAMS; i++) {
     374         1032 :         adjustment_steps[i] = grid->c[i] * PERSPECTIVE_ADJUSTMENT_FACTOR;
     375              :     }
     376              : 
     377          774 :     for (pass = 0; pass < PERSPECTIVE_REFINEMENT_PASSES; pass++) {
     378        10965 :         for (i = 0; i < PERSPECTIVE_PARAM_ITERATIONS; i++) {
     379        10320 :             j = i >> 1;
     380        10320 :             original_value = grid->c[j];
     381        10320 :             step = adjustment_steps[j];
     382        10320 :             new_value = (i & 1) ? original_value + step : original_value - step;
     383              : 
     384        10320 :             grid->c[j] = new_value;
     385        10320 :             test_fitness = compute_total_grid_fitness(decoder, grid_index);
     386              : 
     387        10320 :             if (test_fitness > best_fitness) {
     388          226 :                 best_fitness = test_fitness;
     389              :             } else {
     390        10094 :                 grid->c[j] = original_value;
     391              :             }
     392              :         }
     393              : 
     394         5805 :         for (i = 0; i < LIERRE_DECODER_PERSPECTIVE_PARAMS; i++) {
     395         5160 :             adjustment_steps[i] *= PERSPECTIVE_STEP_DECAY;
     396              :         }
     397              :     }
     398          129 : }
     399              : 
     400          761 : static inline void find_leftmost_point_callback(void *user_data, int32_t y, int32_t left, int32_t right)
     401              : {
     402              :     corner_finder_data_t *finder;
     403              :     int32_t x_coords[2], i, distance;
     404              : 
     405          761 :     finder = (corner_finder_data_t *)user_data;
     406          761 :     x_coords[0] = left;
     407          761 :     x_coords[1] = right;
     408              : 
     409         2283 :     for (i = 0; i < 2; i++) {
     410         1522 :         distance = -finder->reference.y * x_coords[i] + finder->reference.x * y;
     411         1522 :         if (distance < finder->scores[0]) {
     412           14 :             finder->scores[0] = distance;
     413           14 :             finder->corners[0].x = x_coords[i];
     414           14 :             finder->corners[0].y = y;
     415              :         }
     416              :     }
     417          761 : }
     418              : 
     419          108 : static inline void search_alignment_pattern(decoder_t *decoder, int32_t grid_index)
     420              : {
     421              :     static const int32_t direction_dx[SPIRAL_DIRECTION_COUNT] = {1, 0, -1, 0},
     422              :                          direction_dy[SPIRAL_DIRECTION_COUNT] = {0, -1, 0, 1};
     423              :     grid_t *grid;
     424              :     capstone_t *capstone_a, *capstone_c;
     425              :     decoder_point_t point_a, search_point, point_c;
     426              :     region_t *region;
     427              :     int32_t expected_size, step_size, direction, i, region_id;
     428              :     double u, v;
     429              : 
     430          108 :     grid = &decoder->grids[grid_index];
     431          108 :     capstone_a = &decoder->capstones[grid->caps[0]];
     432          108 :     capstone_c = &decoder->capstones[grid->caps[2]];
     433              : 
     434          108 :     search_point = grid->align;
     435              : 
     436          108 :     perspective_unmap(capstone_a->c, &search_point, &u, &v);
     437          108 :     perspective_map(capstone_a->c, u, v + 1.0, &point_a);
     438          108 :     perspective_unmap(capstone_c->c, &search_point, &u, &v);
     439          108 :     perspective_map(capstone_c->c, u + 1.0, v, &point_c);
     440              : 
     441          108 :     expected_size = abs((point_a.x - search_point.x) * -(point_c.y - search_point.y) +
     442          108 :                         (point_a.y - search_point.y) * (point_c.x - search_point.x));
     443              : 
     444          108 :     step_size = 1;
     445          108 :     direction = 0;
     446              : 
     447         2220 :     while (step_size * step_size < expected_size * ALIGNMENT_SEARCH_AREA_FACTOR) {
     448       120989 :         for (i = 0; i < step_size; i++) {
     449       118877 :             region_id = get_or_create_region(decoder, search_point.x, search_point.y);
     450              : 
     451       118877 :             if (region_id >= 0) {
     452        13266 :                 region = &decoder->regions[region_id];
     453        13266 :                 if (region->count >= expected_size / ALIGNMENT_SIZE_FACTOR_MIN &&
     454        12218 :                     region->count <= expected_size * ALIGNMENT_SIZE_FACTOR_MAX) {
     455           98 :                     grid->align_region = region_id;
     456           98 :                     return;
     457              :                 }
     458              :             }
     459              : 
     460       118779 :             search_point.x += direction_dx[direction];
     461       118779 :             search_point.y += direction_dy[direction];
     462              :         }
     463              : 
     464         2112 :         direction = (direction + 1) % SPIRAL_DIRECTION_COUNT;
     465         2112 :         if (!(direction & 1)) {
     466         1052 :             step_size++;
     467              :         }
     468              :     }
     469              : }
     470              : 
     471          129 : static inline void setup_grid_perspective(decoder_t *decoder, int32_t grid_index)
     472              : {
     473              :     grid_t *grid;
     474              :     decoder_point_t corner_points[4];
     475              : 
     476          129 :     grid = &decoder->grids[grid_index];
     477              : 
     478          129 :     corner_points[0] = decoder->capstones[grid->caps[1]].corners[0];
     479          129 :     corner_points[1] = decoder->capstones[grid->caps[2]].corners[0];
     480          129 :     corner_points[2] = grid->align;
     481          129 :     corner_points[3] = decoder->capstones[grid->caps[0]].corners[0];
     482              : 
     483          129 :     perspective_setup(grid->c, corner_points, (double)(grid->grid_size - FINDER_PATTERN_SIZE),
     484          129 :                       (double)(grid->grid_size - FINDER_PATTERN_SIZE));
     485          129 :     refine_perspective(decoder, grid_index);
     486          129 : }
     487              : 
     488          387 : static inline void rotate_capstone_corners(capstone_t *capstone, const decoder_point_t *origin,
     489              :                                            const decoder_point_t *direction)
     490              : {
     491              :     decoder_point_t rotated_corners[NUM_CORNERS], *corner;
     492              :     int32_t j, best_index, score, best_score;
     493              : 
     494          387 :     best_index = 0;
     495          387 :     best_score = INT32_MAX;
     496              : 
     497         1935 :     for (j = 0; j < NUM_CORNERS; j++) {
     498         1548 :         corner = &capstone->corners[j];
     499         1548 :         score = (corner->x - origin->x) * -direction->y + (corner->y - origin->y) * direction->x;
     500              : 
     501         1548 :         if (score < best_score) {
     502         1071 :             best_index = j;
     503         1071 :             best_score = score;
     504              :         }
     505              :     }
     506              : 
     507         1935 :     for (j = 0; j < NUM_CORNERS; j++) {
     508         1548 :         rotated_corners[j] = capstone->corners[(j + best_index) % NUM_CORNERS];
     509              :     }
     510              : 
     511          387 :     lmemcpy(capstone->corners, rotated_corners, sizeof(capstone->corners));
     512          387 :     perspective_setup(capstone->c, capstone->corners, (double)FINDER_PATTERN_SIZE, (double)FINDER_PATTERN_SIZE);
     513          387 : }
     514              : 
     515          129 : static inline void create_qr_grid(decoder_t *decoder, int32_t cap_a, int32_t cap_b, int32_t cap_c)
     516              : {
     517              :     decoder_point_t origin, direction;
     518              :     grid_t *grid;
     519              :     capstone_t *capstone;
     520              :     region_t *region;
     521              :     corner_finder_data_t finder;
     522              :     int32_t i, grid_index, temp;
     523              : 
     524          129 :     if (decoder->num_grids >= LIERRE_DECODER_MAX_GRIDS) {
     525            0 :         return;
     526              :     }
     527              : 
     528          129 :     origin = decoder->capstones[cap_a].center;
     529          129 :     direction.x = decoder->capstones[cap_c].center.x - decoder->capstones[cap_a].center.x;
     530          129 :     direction.y = decoder->capstones[cap_c].center.y - decoder->capstones[cap_a].center.y;
     531              : 
     532          129 :     if ((decoder->capstones[cap_b].center.x - origin.x) * -direction.y +
     533          129 :             (decoder->capstones[cap_b].center.y - origin.y) * direction.x >
     534              :         0) {
     535           13 :         temp = cap_a;
     536           13 :         cap_a = cap_c;
     537           13 :         cap_c = temp;
     538           13 :         direction.x = -direction.x;
     539           13 :         direction.y = -direction.y;
     540              :     }
     541              : 
     542          129 :     grid_index = decoder->num_grids;
     543          129 :     grid = &decoder->grids[decoder->num_grids++];
     544              : 
     545          129 :     lmemset(grid, 0, sizeof(*grid));
     546          129 :     grid->caps[0] = cap_a;
     547          129 :     grid->caps[1] = cap_b;
     548          129 :     grid->caps[2] = cap_c;
     549          129 :     grid->align_region = -1;
     550              : 
     551          516 :     for (i = 0; i < NUM_CAPSTONES; i++) {
     552          387 :         capstone = &decoder->capstones[grid->caps[i]];
     553          387 :         rotate_capstone_corners(capstone, &origin, &direction);
     554          387 :         capstone->qr_grid = grid_index;
     555              :     }
     556              : 
     557          129 :     estimate_grid_size(decoder, grid_index);
     558              : 
     559          129 :     if (!compute_line_intersection(&decoder->capstones[cap_a].corners[0], &decoder->capstones[cap_a].corners[1],
     560          129 :                                    &decoder->capstones[cap_c].corners[0], &decoder->capstones[cap_c].corners[3],
     561              :                                    &grid->align)) {
     562            0 :         for (i = 0; i < NUM_CAPSTONES; i++) {
     563            0 :             decoder->capstones[grid->caps[i]].qr_grid = -1;
     564              :         }
     565              : 
     566            0 :         decoder->num_grids--;
     567              : 
     568            0 :         return;
     569              :     }
     570              : 
     571          129 :     if (grid->grid_size > QR_VERSION2_MIN_SIZE) {
     572          108 :         search_alignment_pattern(decoder, grid_index);
     573              : 
     574          108 :         if (grid->align_region >= 0) {
     575           98 :             region = &decoder->regions[grid->align_region];
     576           98 :             grid->align = region->seed;
     577              : 
     578           98 :             lmemset(&finder, 0, sizeof(finder));
     579           98 :             finder.reference = direction;
     580           98 :             finder.corners = &grid->align;
     581           98 :             finder.scores[0] = -direction.y * grid->align.x + direction.x * grid->align.y;
     582              : 
     583           98 :             flood_fill_seed(decoder, region->seed.x, region->seed.y, (lierre_pixel_t)grid->align_region,
     584              :                             LIERRE_PIXEL_BLACK, NULL, NULL);
     585           98 :             flood_fill_seed(decoder, region->seed.x, region->seed.y, LIERRE_PIXEL_BLACK,
     586           98 :                             (lierre_pixel_t)grid->align_region, find_leftmost_point_callback, &finder);
     587              :         }
     588              :     }
     589              : 
     590          129 :     setup_grid_perspective(decoder, grid_index);
     591              : }
     592              : 
     593          129 : void extract_qr_code(const decoder_t *decoder, int32_t grid_index, qr_code_t *code)
     594              : {
     595              :     const grid_t *grid;
     596              :     int32_t row, col, bit_index;
     597              : 
     598          129 :     lmemset(code, 0, sizeof(*code));
     599              : 
     600          129 :     if (grid_index < 0 || grid_index >= decoder->num_grids) {
     601            1 :         return;
     602              :     }
     603              : 
     604          128 :     grid = &decoder->grids[grid_index];
     605              : 
     606          128 :     perspective_map(grid->c, 0.0, 0.0, &code->corners[0]);
     607          129 :     perspective_map(grid->c, (double)grid->grid_size, 0.0, &code->corners[1]);
     608          128 :     perspective_map(grid->c, (double)grid->grid_size, (double)grid->grid_size, &code->corners[2]);
     609          129 :     perspective_map(grid->c, 0.0, (double)grid->grid_size, &code->corners[3]);
     610              : 
     611          129 :     code->size = grid->grid_size;
     612              : 
     613          129 :     if (code->size > LIERRE_DECODER_MAX_GRID_SIZE) {
     614            0 :         return;
     615              :     }
     616              : 
     617          129 :     bit_index = 0;
     618         5642 :     for (row = 0; row < grid->grid_size; row++) {
     619      1073886 :         for (col = 0; col < grid->grid_size; col++) {
     620      1068373 :             if (read_grid_cell(decoder, grid_index, col, row) > 0) {
     621       540784 :                 code->cell_bitmap[bit_index >> 3] |= (1 << (bit_index & 7));
     622              :             }
     623      1063954 :             bit_index++;
     624              :         }
     625              :     }
     626              : }
     627              : 
     628          122 : extern void test_neighbour_pairs(decoder_t *decoder, int32_t capstone_index,
     629              :                                  const capstone_neighbour_list_t *horizontal_list,
     630              :                                  const capstone_neighbour_list_t *vertical_list)
     631              : {
     632              :     const capstone_neighbour_t *horizontal_neighbour, *vertical_neighbour;
     633              :     int32_t j, k;
     634              :     double squareness;
     635              : 
     636          266 :     for (j = 0; j < horizontal_list->count; j++) {
     637          144 :         horizontal_neighbour = &horizontal_list->entries[j];
     638          329 :         for (k = 0; k < vertical_list->count; k++) {
     639          185 :             vertical_neighbour = &vertical_list->entries[k];
     640          185 :             squareness = fabs(1.0 - horizontal_neighbour->distance / vertical_neighbour->distance);
     641              : 
     642          185 :             if (squareness < SQUARENESS_THRESHOLD) {
     643          129 :                 create_qr_grid(decoder, horizontal_neighbour->index, capstone_index, vertical_neighbour->index);
     644              :             }
     645              :         }
     646              :     }
     647          122 : }
        

Generated by: LCOV version 2.0-1