图像扫描的工作都是由zbar_scan_image完成的,zbar_scan_image主要根据设定的扫描密度(density)控制像素点读取(Z字形),scanner.c文件内的zbar_scan_y()来完成滤波,阈值,确定边缘,转化成宽度流。
int zbar_scan_image (zbar_image_scanner_t *iscn,
zbar_image_t *img)
{
/* timestamp image
* FIXME prefer video timestamp
*/
#if _POSIX_TIMERS > 0
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
iscn->time = (abstime.tv_sec * 1000) + ((abstime.tv_nsec / 500000) + 1) / 2;
#else
struct timeval abstime;
gettimeofday(&abstime, NULL);
iscn->time = (abstime.tv_sec * 1000) + ((abstime.tv_usec / 500) + 1) / 2;
#endif
#ifdef ENABLE_QRCODE
_zbar_qr_reset(iscn->qr);
#endif
/* get grayscale image, convert if necessary */
if(img->format != fourcc('Y','8','0','0') &&
img->format != fourcc('G','R','E','Y'))
return(-1);
iscn->img = img;
/* recycle previous scanner and image results */
zbar_image_scanner_recycle_image(iscn, img);
zbar_symbol_set_t *syms = iscn->syms;
if(!syms) {
syms = iscn->syms = _zbar_symbol_set_create();
STAT(syms_new);
zbar_symbol_set_ref(syms, 1);
}
else
zbar_symbol_set_ref(syms, 2);
img->syms = syms;
unsigned w = img->width;
unsigned h = img->height;
const uint8_t *data = img->data;
zbar_image_write_png(img, "debug.png");
svg_open("debug.svg", 0, 0, w, h);
svg_image("debug.png", w, h);
zbar_scanner_t *scn = iscn->scn;
int density = CFG(iscn, ZBAR_CFG_Y_DENSITY);
if(density > 0) {
svg_group_start("scanner", 0, 1, 1, 0, 0);
const uint8_t *p = data;
int x = 0, y = 0;
iscn->dy = 0;
int border = (((h - 1) % density) + 1) / 2;
if(border > h / 2)
border = h / 2;
movedelta(0, border);
iscn->v = y;
zbar_scanner_new_scan(scn);
while(y < h) {
zprintf(128, "img_x+: %04d,%04d @%p\n", x, y, p);
svg_path_start("vedge", 1. / 32, 0, y + 0.5);
iscn->dx = iscn->du = 1;
iscn->umin = 0;
while(x < w) {
uint8_t d = *p;
movedelta(1, 0);
zbar_scan_y(scn, d);
}
ASSERT_POS;
quiet_border(iscn);
svg_path_end();
movedelta(-1, density);
iscn->v = y;
if(y >= h)
break;
zprintf(128, "img_x-: %04d,%04d @%p\n", x, y, p);
svg_path_start("vedge", -1. / 32, w, y + 0.5);
iscn->dx = iscn->du = -1;
iscn->umin = w;
while(x >= 0) {
uint8_t d = *p;
movedelta(-1, 0);
zbar_scan_y(scn, d);
}
ASSERT_POS;
quiet_border(iscn);
svg_path_end();
movedelta(1, density);
iscn->v = y;
}
svg_group_end();
}
iscn->dx = 0;
density = CFG(iscn, ZBAR_CFG_X_DENSITY);
if(density > 0) {
svg_group_start("scanner", 90, 1, -1, 0, 0);
const uint8_t *p = data;
int x = 0, y = 0;
int border = (((w - 1) % density) + 1) / 2;
if(border > w / 2)
border = w / 2;
movedelta(border, 0);
iscn->v = x;
while(x < w) {
zprintf(128, "img_y+: %04d,%04d @%p\n", x, y, p);
svg_path_start("vedge", 1. / 32, 0, x + 0.5);
iscn->dy = iscn->du = 1;
iscn->umin = 0;
while(y < h) {
uint8_t d = *p;
movedelta(0, 1);
zbar_scan_y(scn, d);
}
ASSERT_POS;
quiet_border(iscn);
svg_path_end();
movedelta(density, -1);
iscn->v = x;
if(x >= w)
break;
zprintf(128, "img_y-: %04d,%04d @%p\n", x, y, p);
svg_path_start("vedge", -1. / 32, h, x + 0.5);
iscn->dy = iscn->du = -1;
iscn->umin = h;
while(y >= 0) {
uint8_t d = *p;
movedelta(0, -1);
zbar_scan_y(scn, d);
}
ASSERT_POS;
quiet_border(iscn);
svg_path_end();
movedelta(density, 1);
iscn->v = x;
}
svg_group_end();
}
iscn->dy = 0;
iscn->img = NULL;
#ifdef ENABLE_QRCODE
_zbar_qr_decode(iscn->qr, iscn, img);
#endif
/* FIXME tmp hack to filter bad EAN results */
if(syms->nsyms && !iscn->enable_cache &&
(density == 1 || CFG(iscn, ZBAR_CFG_Y_DENSITY) == 1)) {
zbar_symbol_t **symp = &syms->head, *sym;
while((sym = *symp)) {
if(sym->type < ZBAR_I25 && sym->type > ZBAR_PARTIAL &&
sym->quality < 3) {
/* recycle */
*symp = sym->next;
syms->nsyms--;
sym->next = NULL;
_zbar_image_scanner_recycle_syms(iscn, sym);
}
else
symp = &sym->next;
}
}
if(syms->nsyms && iscn->handler)
iscn->handler(img, iscn->userdata);
svg_close();
return(syms->nsyms);
}