A streamlined version (for embedded use) of Jeff Brown's ZBar library. Visit <http://zbar.sourceforge.net> for more details.
Dependents: BarcodeReader_F103
scanner.c@1:4f5c042a2d34, 2020-01-10 (annotated)
- Committer:
- hudakz
- Date:
- Fri Jan 10 22:06:18 2020 +0000
- Revision:
- 1:4f5c042a2d34
- Parent:
- 0:e33621169e44
Streamlined barcode reader library.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 0:e33621169e44 | 1 | /*------------------------------------------------------------------------ |
hudakz | 0:e33621169e44 | 2 | * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> |
hudakz | 0:e33621169e44 | 3 | * |
hudakz | 0:e33621169e44 | 4 | * This file is part of the ZBar Bar Code Reader. |
hudakz | 0:e33621169e44 | 5 | * |
hudakz | 0:e33621169e44 | 6 | * The ZBar Bar Code Reader is free software; you can redistribute it |
hudakz | 0:e33621169e44 | 7 | * and/or modify it under the terms of the GNU Lesser Public License as |
hudakz | 0:e33621169e44 | 8 | * published by the Free Software Foundation; either version 2.1 of |
hudakz | 0:e33621169e44 | 9 | * the License, or (at your option) any later version. |
hudakz | 0:e33621169e44 | 10 | * |
hudakz | 0:e33621169e44 | 11 | * The ZBar Bar Code Reader is distributed in the hope that it will be |
hudakz | 0:e33621169e44 | 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
hudakz | 0:e33621169e44 | 13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
hudakz | 0:e33621169e44 | 14 | * GNU Lesser Public License for more details. |
hudakz | 0:e33621169e44 | 15 | * |
hudakz | 0:e33621169e44 | 16 | * You should have received a copy of the GNU Lesser Public License |
hudakz | 0:e33621169e44 | 17 | * along with the ZBar Bar Code Reader; if not, write to the Free |
hudakz | 0:e33621169e44 | 18 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
hudakz | 0:e33621169e44 | 19 | * Boston, MA 02110-1301 USA |
hudakz | 0:e33621169e44 | 20 | * |
hudakz | 0:e33621169e44 | 21 | * http://sourceforge.net/projects/zbar |
hudakz | 0:e33621169e44 | 22 | *------------------------------------------------------------------------*/ |
hudakz | 0:e33621169e44 | 23 | |
hudakz | 0:e33621169e44 | 24 | #include <config.h> |
hudakz | 0:e33621169e44 | 25 | #include <stdlib.h> /* malloc, free, abs */ |
hudakz | 0:e33621169e44 | 26 | #include <string.h> /* memset */ |
hudakz | 0:e33621169e44 | 27 | |
hudakz | 0:e33621169e44 | 28 | #include <zbar.h> |
hudakz | 0:e33621169e44 | 29 | //#include "svg.h" |
hudakz | 0:e33621169e44 | 30 | |
hudakz | 0:e33621169e44 | 31 | #ifdef DEBUG_SCANNER |
hudakz | 0:e33621169e44 | 32 | # define DEBUG_LEVEL (DEBUG_SCANNER) |
hudakz | 0:e33621169e44 | 33 | #endif |
hudakz | 0:e33621169e44 | 34 | #include "debug.h" |
hudakz | 0:e33621169e44 | 35 | |
hudakz | 0:e33621169e44 | 36 | #ifndef ZBAR_FIXED |
hudakz | 0:e33621169e44 | 37 | # define ZBAR_FIXED 5 |
hudakz | 0:e33621169e44 | 38 | #endif |
hudakz | 0:e33621169e44 | 39 | #define ROUND (1 << (ZBAR_FIXED - 1)) |
hudakz | 0:e33621169e44 | 40 | |
hudakz | 0:e33621169e44 | 41 | /* FIXME add runtime config API for these */ |
hudakz | 0:e33621169e44 | 42 | #ifndef ZBAR_SCANNER_THRESH_MIN |
hudakz | 0:e33621169e44 | 43 | # define ZBAR_SCANNER_THRESH_MIN 4 |
hudakz | 0:e33621169e44 | 44 | #endif |
hudakz | 0:e33621169e44 | 45 | |
hudakz | 0:e33621169e44 | 46 | #ifndef ZBAR_SCANNER_THRESH_INIT_WEIGHT |
hudakz | 0:e33621169e44 | 47 | # define ZBAR_SCANNER_THRESH_INIT_WEIGHT .44 |
hudakz | 0:e33621169e44 | 48 | #endif |
hudakz | 0:e33621169e44 | 49 | #define THRESH_INIT ((unsigned)((ZBAR_SCANNER_THRESH_INIT_WEIGHT \ |
hudakz | 0:e33621169e44 | 50 | * (1 << (ZBAR_FIXED + 1)) + 1) / 2)) |
hudakz | 0:e33621169e44 | 51 | |
hudakz | 0:e33621169e44 | 52 | #ifndef ZBAR_SCANNER_THRESH_FADE |
hudakz | 0:e33621169e44 | 53 | # define ZBAR_SCANNER_THRESH_FADE 8 |
hudakz | 0:e33621169e44 | 54 | #endif |
hudakz | 0:e33621169e44 | 55 | |
hudakz | 0:e33621169e44 | 56 | #ifndef ZBAR_SCANNER_EWMA_WEIGHT |
hudakz | 0:e33621169e44 | 57 | # define ZBAR_SCANNER_EWMA_WEIGHT .78 |
hudakz | 0:e33621169e44 | 58 | #endif |
hudakz | 0:e33621169e44 | 59 | #define EWMA_WEIGHT ((unsigned)((ZBAR_SCANNER_EWMA_WEIGHT \ |
hudakz | 0:e33621169e44 | 60 | * (1 << (ZBAR_FIXED + 1)) + 1) / 2)) |
hudakz | 0:e33621169e44 | 61 | |
hudakz | 0:e33621169e44 | 62 | /* scanner state */ |
hudakz | 0:e33621169e44 | 63 | struct zbar_scanner_s { |
hudakz | 0:e33621169e44 | 64 | zbar_decoder_t *decoder; /* associated bar width decoder */ |
hudakz | 0:e33621169e44 | 65 | unsigned y1_min_thresh; /* minimum threshold */ |
hudakz | 0:e33621169e44 | 66 | |
hudakz | 0:e33621169e44 | 67 | unsigned x; /* relative scan position of next sample */ |
hudakz | 0:e33621169e44 | 68 | int y0[4]; /* short circular buffer of average intensities */ |
hudakz | 0:e33621169e44 | 69 | |
hudakz | 0:e33621169e44 | 70 | int y1_sign; /* slope at last crossing */ |
hudakz | 0:e33621169e44 | 71 | unsigned y1_thresh; /* current slope threshold */ |
hudakz | 0:e33621169e44 | 72 | |
hudakz | 0:e33621169e44 | 73 | unsigned cur_edge; /* interpolated position of tracking edge */ |
hudakz | 0:e33621169e44 | 74 | unsigned last_edge; /* interpolated position of last located edge */ |
hudakz | 0:e33621169e44 | 75 | unsigned width; /* last element width */ |
hudakz | 0:e33621169e44 | 76 | }; |
hudakz | 0:e33621169e44 | 77 | |
hudakz | 0:e33621169e44 | 78 | zbar_scanner_t *zbar_scanner_create (zbar_decoder_t *dcode) |
hudakz | 0:e33621169e44 | 79 | { |
hudakz | 0:e33621169e44 | 80 | zbar_scanner_t *scn = malloc(sizeof(zbar_scanner_t)); |
hudakz | 0:e33621169e44 | 81 | scn->decoder = dcode; |
hudakz | 0:e33621169e44 | 82 | scn->y1_min_thresh = ZBAR_SCANNER_THRESH_MIN; |
hudakz | 0:e33621169e44 | 83 | zbar_scanner_reset(scn); |
hudakz | 0:e33621169e44 | 84 | return(scn); |
hudakz | 0:e33621169e44 | 85 | } |
hudakz | 0:e33621169e44 | 86 | |
hudakz | 0:e33621169e44 | 87 | void zbar_scanner_destroy (zbar_scanner_t *scn) |
hudakz | 0:e33621169e44 | 88 | { |
hudakz | 0:e33621169e44 | 89 | free(scn); |
hudakz | 0:e33621169e44 | 90 | } |
hudakz | 0:e33621169e44 | 91 | |
hudakz | 0:e33621169e44 | 92 | zbar_symbol_type_t zbar_scanner_reset (zbar_scanner_t *scn) |
hudakz | 0:e33621169e44 | 93 | { |
hudakz | 0:e33621169e44 | 94 | memset(&scn->x, 0, sizeof(zbar_scanner_t) + (void*)scn - (void*)&scn->x); |
hudakz | 0:e33621169e44 | 95 | scn->y1_thresh = scn->y1_min_thresh; |
hudakz | 0:e33621169e44 | 96 | if(scn->decoder) |
hudakz | 0:e33621169e44 | 97 | zbar_decoder_reset(scn->decoder); |
hudakz | 0:e33621169e44 | 98 | return(ZBAR_NONE); |
hudakz | 0:e33621169e44 | 99 | } |
hudakz | 0:e33621169e44 | 100 | |
hudakz | 0:e33621169e44 | 101 | unsigned zbar_scanner_get_width (const zbar_scanner_t *scn) |
hudakz | 0:e33621169e44 | 102 | { |
hudakz | 0:e33621169e44 | 103 | return(scn->width); |
hudakz | 0:e33621169e44 | 104 | } |
hudakz | 0:e33621169e44 | 105 | |
hudakz | 0:e33621169e44 | 106 | unsigned zbar_scanner_get_edge (const zbar_scanner_t *scn, |
hudakz | 0:e33621169e44 | 107 | unsigned offset, |
hudakz | 0:e33621169e44 | 108 | int prec) |
hudakz | 0:e33621169e44 | 109 | { |
hudakz | 0:e33621169e44 | 110 | unsigned edge = scn->last_edge - offset - (1 << ZBAR_FIXED) - ROUND; |
hudakz | 0:e33621169e44 | 111 | prec = ZBAR_FIXED - prec; |
hudakz | 0:e33621169e44 | 112 | if(prec > 0) |
hudakz | 0:e33621169e44 | 113 | return(edge >> prec); |
hudakz | 0:e33621169e44 | 114 | else if(!prec) |
hudakz | 0:e33621169e44 | 115 | return(edge); |
hudakz | 0:e33621169e44 | 116 | else |
hudakz | 0:e33621169e44 | 117 | return(edge << -prec); |
hudakz | 0:e33621169e44 | 118 | } |
hudakz | 0:e33621169e44 | 119 | |
hudakz | 0:e33621169e44 | 120 | zbar_color_t zbar_scanner_get_color (const zbar_scanner_t *scn) |
hudakz | 0:e33621169e44 | 121 | { |
hudakz | 0:e33621169e44 | 122 | return((scn->y1_sign <= 0) ? ZBAR_SPACE : ZBAR_BAR); |
hudakz | 0:e33621169e44 | 123 | } |
hudakz | 0:e33621169e44 | 124 | |
hudakz | 0:e33621169e44 | 125 | static inline unsigned calc_thresh (zbar_scanner_t *scn) |
hudakz | 0:e33621169e44 | 126 | { |
hudakz | 0:e33621169e44 | 127 | /* threshold 1st to improve noise rejection */ |
hudakz | 0:e33621169e44 | 128 | unsigned thresh = scn->y1_thresh; |
hudakz | 0:e33621169e44 | 129 | if((thresh <= scn->y1_min_thresh) || !scn->width) { |
hudakz | 0:e33621169e44 | 130 | dprintf(1, " tmin=%d", scn->y1_min_thresh); |
hudakz | 0:e33621169e44 | 131 | return(scn->y1_min_thresh); |
hudakz | 0:e33621169e44 | 132 | } |
hudakz | 0:e33621169e44 | 133 | /* slowly return threshold to min */ |
hudakz | 0:e33621169e44 | 134 | unsigned dx = (scn->x << ZBAR_FIXED) - scn->last_edge; |
hudakz | 0:e33621169e44 | 135 | unsigned long t = thresh * dx; |
hudakz | 0:e33621169e44 | 136 | t /= scn->width; |
hudakz | 0:e33621169e44 | 137 | t /= ZBAR_SCANNER_THRESH_FADE; |
hudakz | 0:e33621169e44 | 138 | dprintf(1, " thr=%d t=%ld x=%d last=%d.%d (%d)", |
hudakz | 0:e33621169e44 | 139 | thresh, t, scn->x, scn->last_edge >> ZBAR_FIXED, |
hudakz | 0:e33621169e44 | 140 | scn->last_edge & ((1 << ZBAR_FIXED) - 1), dx); |
hudakz | 0:e33621169e44 | 141 | if(thresh > t) { |
hudakz | 0:e33621169e44 | 142 | thresh -= t; |
hudakz | 0:e33621169e44 | 143 | if(thresh > scn->y1_min_thresh) |
hudakz | 0:e33621169e44 | 144 | return(thresh); |
hudakz | 0:e33621169e44 | 145 | } |
hudakz | 0:e33621169e44 | 146 | scn->y1_thresh = scn->y1_min_thresh; |
hudakz | 0:e33621169e44 | 147 | return(scn->y1_min_thresh); |
hudakz | 0:e33621169e44 | 148 | } |
hudakz | 0:e33621169e44 | 149 | |
hudakz | 0:e33621169e44 | 150 | static inline zbar_symbol_type_t process_edge (zbar_scanner_t *scn, |
hudakz | 0:e33621169e44 | 151 | int y1) |
hudakz | 0:e33621169e44 | 152 | { |
hudakz | 0:e33621169e44 | 153 | if(!scn->y1_sign) |
hudakz | 0:e33621169e44 | 154 | scn->last_edge = scn->cur_edge = (1 << ZBAR_FIXED) + ROUND; |
hudakz | 0:e33621169e44 | 155 | else if(!scn->last_edge) |
hudakz | 0:e33621169e44 | 156 | scn->last_edge = scn->cur_edge; |
hudakz | 0:e33621169e44 | 157 | |
hudakz | 0:e33621169e44 | 158 | scn->width = scn->cur_edge - scn->last_edge; |
hudakz | 0:e33621169e44 | 159 | dprintf(1, " sgn=%d cur=%d.%d w=%d (%s)\n", |
hudakz | 0:e33621169e44 | 160 | scn->y1_sign, scn->cur_edge >> ZBAR_FIXED, |
hudakz | 0:e33621169e44 | 161 | scn->cur_edge & ((1 << ZBAR_FIXED) - 1), scn->width, |
hudakz | 0:e33621169e44 | 162 | ((y1 > 0) ? "SPACE" : "BAR")); |
hudakz | 0:e33621169e44 | 163 | scn->last_edge = scn->cur_edge; |
hudakz | 0:e33621169e44 | 164 | |
hudakz | 0:e33621169e44 | 165 | #if DEBUG_SVG > 1 |
hudakz | 0:e33621169e44 | 166 | svg_path_moveto(SVG_ABS, scn->last_edge - (1 << ZBAR_FIXED) - ROUND, 0); |
hudakz | 0:e33621169e44 | 167 | #endif |
hudakz | 0:e33621169e44 | 168 | |
hudakz | 0:e33621169e44 | 169 | /* pass to decoder */ |
hudakz | 0:e33621169e44 | 170 | if(scn->decoder) |
hudakz | 0:e33621169e44 | 171 | return(zbar_decode_width(scn->decoder, scn->width)); |
hudakz | 0:e33621169e44 | 172 | return(ZBAR_PARTIAL); |
hudakz | 0:e33621169e44 | 173 | } |
hudakz | 0:e33621169e44 | 174 | |
hudakz | 0:e33621169e44 | 175 | inline zbar_symbol_type_t zbar_scanner_flush (zbar_scanner_t *scn) |
hudakz | 0:e33621169e44 | 176 | { |
hudakz | 0:e33621169e44 | 177 | if(!scn->y1_sign) |
hudakz | 0:e33621169e44 | 178 | return(ZBAR_NONE); |
hudakz | 0:e33621169e44 | 179 | |
hudakz | 0:e33621169e44 | 180 | unsigned x = (scn->x << ZBAR_FIXED) + ROUND; |
hudakz | 0:e33621169e44 | 181 | |
hudakz | 0:e33621169e44 | 182 | if(scn->cur_edge != x || scn->y1_sign > 0) { |
hudakz | 0:e33621169e44 | 183 | dprintf(1, "flush0:"); |
hudakz | 0:e33621169e44 | 184 | zbar_symbol_type_t edge = process_edge(scn, -scn->y1_sign); |
hudakz | 0:e33621169e44 | 185 | scn->cur_edge = x; |
hudakz | 0:e33621169e44 | 186 | scn->y1_sign = -scn->y1_sign; |
hudakz | 0:e33621169e44 | 187 | return(edge); |
hudakz | 0:e33621169e44 | 188 | } |
hudakz | 0:e33621169e44 | 189 | |
hudakz | 0:e33621169e44 | 190 | scn->y1_sign = scn->width = 0; |
hudakz | 0:e33621169e44 | 191 | if(scn->decoder) |
hudakz | 0:e33621169e44 | 192 | return(zbar_decode_width(scn->decoder, 0)); |
hudakz | 0:e33621169e44 | 193 | return(ZBAR_PARTIAL); |
hudakz | 0:e33621169e44 | 194 | } |
hudakz | 0:e33621169e44 | 195 | |
hudakz | 0:e33621169e44 | 196 | zbar_symbol_type_t zbar_scanner_new_scan (zbar_scanner_t *scn) |
hudakz | 0:e33621169e44 | 197 | { |
hudakz | 0:e33621169e44 | 198 | zbar_symbol_type_t edge = ZBAR_NONE; |
hudakz | 0:e33621169e44 | 199 | while(scn->y1_sign) { |
hudakz | 0:e33621169e44 | 200 | zbar_symbol_type_t tmp = zbar_scanner_flush(scn); |
hudakz | 0:e33621169e44 | 201 | if(tmp < 0 || tmp > edge) |
hudakz | 0:e33621169e44 | 202 | edge = tmp; |
hudakz | 0:e33621169e44 | 203 | } |
hudakz | 0:e33621169e44 | 204 | |
hudakz | 0:e33621169e44 | 205 | /* reset scanner and associated decoder */ |
hudakz | 0:e33621169e44 | 206 | memset(&scn->x, 0, sizeof(zbar_scanner_t) + (void*)scn - (void*)&scn->x); |
hudakz | 0:e33621169e44 | 207 | scn->y1_thresh = scn->y1_min_thresh; |
hudakz | 0:e33621169e44 | 208 | if(scn->decoder) |
hudakz | 0:e33621169e44 | 209 | zbar_decoder_new_scan(scn->decoder); |
hudakz | 0:e33621169e44 | 210 | return(edge); |
hudakz | 0:e33621169e44 | 211 | } |
hudakz | 0:e33621169e44 | 212 | |
hudakz | 0:e33621169e44 | 213 | zbar_symbol_type_t zbar_scan_y (zbar_scanner_t *scn, |
hudakz | 0:e33621169e44 | 214 | int y) |
hudakz | 0:e33621169e44 | 215 | { |
hudakz | 0:e33621169e44 | 216 | /* FIXME calc and clip to max y range... */ |
hudakz | 0:e33621169e44 | 217 | /* retrieve short value history */ |
hudakz | 0:e33621169e44 | 218 | register int x = scn->x; |
hudakz | 0:e33621169e44 | 219 | register int y0_1 = scn->y0[(x - 1) & 3]; |
hudakz | 0:e33621169e44 | 220 | register int y0_0 = y0_1; |
hudakz | 0:e33621169e44 | 221 | if(x) { |
hudakz | 0:e33621169e44 | 222 | /* update weighted moving average */ |
hudakz | 0:e33621169e44 | 223 | y0_0 += ((int)((y - y0_1) * EWMA_WEIGHT)) >> ZBAR_FIXED; |
hudakz | 0:e33621169e44 | 224 | scn->y0[x & 3] = y0_0; |
hudakz | 0:e33621169e44 | 225 | } |
hudakz | 0:e33621169e44 | 226 | else |
hudakz | 0:e33621169e44 | 227 | y0_0 = y0_1 = scn->y0[0] = scn->y0[1] = scn->y0[2] = scn->y0[3] = y; |
hudakz | 0:e33621169e44 | 228 | register int y0_2 = scn->y0[(x - 2) & 3]; |
hudakz | 0:e33621169e44 | 229 | register int y0_3 = scn->y0[(x - 3) & 3]; |
hudakz | 0:e33621169e44 | 230 | /* 1st differential @ x-1 */ |
hudakz | 0:e33621169e44 | 231 | register int y1_1 = y0_1 - y0_2; |
hudakz | 0:e33621169e44 | 232 | { |
hudakz | 0:e33621169e44 | 233 | register int y1_2 = y0_2 - y0_3; |
hudakz | 0:e33621169e44 | 234 | if((abs(y1_1) < abs(y1_2)) && |
hudakz | 0:e33621169e44 | 235 | ((y1_1 >= 0) == (y1_2 >= 0))) |
hudakz | 0:e33621169e44 | 236 | y1_1 = y1_2; |
hudakz | 0:e33621169e44 | 237 | } |
hudakz | 0:e33621169e44 | 238 | |
hudakz | 0:e33621169e44 | 239 | /* 2nd differentials @ x-1 & x-2 */ |
hudakz | 0:e33621169e44 | 240 | register int y2_1 = y0_0 - (y0_1 * 2) + y0_2; |
hudakz | 0:e33621169e44 | 241 | register int y2_2 = y0_1 - (y0_2 * 2) + y0_3; |
hudakz | 0:e33621169e44 | 242 | |
hudakz | 0:e33621169e44 | 243 | dprintf(1, "scan: x=%d y=%d y0=%d y1=%d y2=%d", |
hudakz | 0:e33621169e44 | 244 | x, y, y0_1, y1_1, y2_1); |
hudakz | 0:e33621169e44 | 245 | |
hudakz | 0:e33621169e44 | 246 | zbar_symbol_type_t edge = ZBAR_NONE; |
hudakz | 0:e33621169e44 | 247 | /* 2nd zero-crossing is 1st local min/max - could be edge */ |
hudakz | 0:e33621169e44 | 248 | if((!y2_1 || |
hudakz | 0:e33621169e44 | 249 | ((y2_1 > 0) ? y2_2 < 0 : y2_2 > 0)) && |
hudakz | 0:e33621169e44 | 250 | (calc_thresh(scn) <= abs(y1_1))) |
hudakz | 0:e33621169e44 | 251 | { |
hudakz | 0:e33621169e44 | 252 | /* check for 1st sign change */ |
hudakz | 0:e33621169e44 | 253 | char y1_rev = (scn->y1_sign > 0) ? y1_1 < 0 : y1_1 > 0; |
hudakz | 0:e33621169e44 | 254 | if(y1_rev) |
hudakz | 0:e33621169e44 | 255 | /* intensity change reversal - finalize previous edge */ |
hudakz | 0:e33621169e44 | 256 | edge = process_edge(scn, y1_1); |
hudakz | 0:e33621169e44 | 257 | |
hudakz | 0:e33621169e44 | 258 | if(y1_rev || (abs(scn->y1_sign) < abs(y1_1))) { |
hudakz | 0:e33621169e44 | 259 | scn->y1_sign = y1_1; |
hudakz | 0:e33621169e44 | 260 | |
hudakz | 0:e33621169e44 | 261 | /* adaptive thresholding */ |
hudakz | 0:e33621169e44 | 262 | /* start at multiple of new min/max */ |
hudakz | 0:e33621169e44 | 263 | scn->y1_thresh = (abs(y1_1) * THRESH_INIT + ROUND) >> ZBAR_FIXED; |
hudakz | 0:e33621169e44 | 264 | dprintf(1, "\tthr=%d", scn->y1_thresh); |
hudakz | 0:e33621169e44 | 265 | if(scn->y1_thresh < scn->y1_min_thresh) |
hudakz | 0:e33621169e44 | 266 | scn->y1_thresh = scn->y1_min_thresh; |
hudakz | 0:e33621169e44 | 267 | |
hudakz | 0:e33621169e44 | 268 | /* update current edge */ |
hudakz | 0:e33621169e44 | 269 | int d = y2_1 - y2_2; |
hudakz | 0:e33621169e44 | 270 | scn->cur_edge = 1 << ZBAR_FIXED; |
hudakz | 0:e33621169e44 | 271 | if(!d) |
hudakz | 0:e33621169e44 | 272 | scn->cur_edge >>= 1; |
hudakz | 0:e33621169e44 | 273 | else if(y2_1) |
hudakz | 0:e33621169e44 | 274 | /* interpolate zero crossing */ |
hudakz | 0:e33621169e44 | 275 | scn->cur_edge -= ((y2_1 << ZBAR_FIXED) + 1) / d; |
hudakz | 0:e33621169e44 | 276 | scn->cur_edge += x << ZBAR_FIXED; |
hudakz | 0:e33621169e44 | 277 | dprintf(1, "\n"); |
hudakz | 0:e33621169e44 | 278 | } |
hudakz | 0:e33621169e44 | 279 | } |
hudakz | 0:e33621169e44 | 280 | else |
hudakz | 0:e33621169e44 | 281 | dprintf(1, "\n"); |
hudakz | 0:e33621169e44 | 282 | /* FIXME add fall-thru pass to decoder after heuristic "idle" period |
hudakz | 0:e33621169e44 | 283 | (eg, 6-8 * last width) */ |
hudakz | 0:e33621169e44 | 284 | scn->x = x + 1; |
hudakz | 0:e33621169e44 | 285 | return(edge); |
hudakz | 0:e33621169e44 | 286 | } |
hudakz | 0:e33621169e44 | 287 | |
hudakz | 0:e33621169e44 | 288 | /* undocumented API for drawing cutesy debug graphics */ |
hudakz | 0:e33621169e44 | 289 | void zbar_scanner_get_state (const zbar_scanner_t *scn, |
hudakz | 0:e33621169e44 | 290 | unsigned *x, |
hudakz | 0:e33621169e44 | 291 | unsigned *cur_edge, |
hudakz | 0:e33621169e44 | 292 | unsigned *last_edge, |
hudakz | 0:e33621169e44 | 293 | int *y0, |
hudakz | 0:e33621169e44 | 294 | int *y1, |
hudakz | 0:e33621169e44 | 295 | int *y2, |
hudakz | 0:e33621169e44 | 296 | int *y1_thresh) |
hudakz | 0:e33621169e44 | 297 | { |
hudakz | 0:e33621169e44 | 298 | register int y0_0 = scn->y0[(scn->x - 1) & 3]; |
hudakz | 0:e33621169e44 | 299 | register int y0_1 = scn->y0[(scn->x - 2) & 3]; |
hudakz | 0:e33621169e44 | 300 | register int y0_2 = scn->y0[(scn->x - 3) & 3]; |
hudakz | 0:e33621169e44 | 301 | if(x) *x = scn->x - 1; |
hudakz | 0:e33621169e44 | 302 | if(cur_edge) *cur_edge = scn->cur_edge; |
hudakz | 0:e33621169e44 | 303 | if(last_edge) *last_edge = scn->last_edge; |
hudakz | 0:e33621169e44 | 304 | if(y0) *y0 = y0_1; |
hudakz | 0:e33621169e44 | 305 | if(y1) *y1 = y0_1 - y0_2; |
hudakz | 0:e33621169e44 | 306 | if(y2) *y2 = y0_0 - (y0_1 * 2) + y0_2; |
hudakz | 0:e33621169e44 | 307 | /* NB not quite accurate (uses updated x) */ |
hudakz | 0:e33621169e44 | 308 | zbar_scanner_t *mut_scn = (zbar_scanner_t*)scn; |
hudakz | 0:e33621169e44 | 309 | if(y1_thresh) *y1_thresh = calc_thresh(mut_scn); |
hudakz | 0:e33621169e44 | 310 | dprintf(1, "\n"); |
hudakz | 0:e33621169e44 | 311 | } |