图像扫描的工作都是由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); }