ZBar源码分析——Image-Scanner模块_3
ZBar源码分析——Image Scanner模块(三)
[TOC]
一、Image Scanner
Image Scanner,顾名思义是实现对读入图像进行扫描的功能模块。
ZBar实现Image Scanner的核心主要由img_scanner.c和scanner.c两个文件组成。
其中,img_scanner.c中的核心函数是zbar_scan_image(),而scanner.c中的核心函数是zbar_scan_y()。经过简单分析得到,zbar_scan_image主要负责ZBar对读入图像的扫描工作,函数主要根据设定的扫描密度(density)控制像素点读取(按Z字形读取,这也是ZBar名称的由来),scanner.c文件内的zbar_scan_y()来完成滤波,阈值,确定边缘,转化成宽度流。
前面的代码分析对img_scanner.c的核心函数zbar_scan_image()函数以及几个函数进行过分析,本次代码分析则继续对该函数对于特征的使用和处理进行分析。
二、代码分析
数据结构解析
1 | typedef struct recycle_bucket_s { |
这里定义了两个数据结构用于代码调用。
recycle_bucket_s为特征回收数据结构,在结构体中定义了特征指针和索引数据。
zbar_image_scanner_s为ZBar扫描器数据结构,存放当前扫描器的状态、用户反馈数据、被回收的特征数据以及扫描器配置数据。
zbar_scanner_t *scn | 与扫描器关联的线性强度扫描仪 |
zbar_decoder_t *dcode | 与扫描器关联的关联符号解码器 |
qr_reader *qr | 二维码阅读器 |
const void *userdata | 应用数据 |
unsigned long time | 扫描开始时间 |
zbar_image_t *img | 当前扫描图像 |
int dx, dy, du, umin, v | 当前扫描位置 |
zbar_symbol_set_t *syms | 曾经被解码得到的结果 |
int enable_cache | 当前结果缓存状态 |
unsigned config | 配置标志 |
int configs[NUM_SCN_CFGS] | 有值配置 |
int sym_configs[1][NUM_SYMS] | 符号配置 |
扫描器特征回收
扫描器在对二维图像进行扫描时,将识别到的特征进行记录和保存,当当前扫描部分结束时,需要对特征进行回收。
1 | void _zbar_image_scanner_recycle_syms (zbar_image_scanner_t *iscn, |
回收步骤:
遍历扫描器存放的特征数据结构,若当前特征与当前扫描器链接且被引用,则直接在特征列表中截断,不允许在链表中继续链接,然后断开链接。
1 | if(sym->refcnt && _zbar_refcnt(&sym->refcnt, -1)) { |
若未被引用,则不能在链表中进行操作,这部分数据在扫描器中的存储结构比较尴尬:可能在后续扫描过程中被引用,即被其他扫描器结构引用。
在回收时,需要调用回收桶数据结构,将这部分数据存放到回收桶中,这与Windows系统中的回收站功能类似,只是将这部分数据结构从扫描器中移除,在某个地方存放起来,需要时仍可以调用。
该函数也提供了将回收桶中的数据彻底移除的方式。
1 | for(i = 0; i < RECYCLE_BUCKETS; i++) |
扫描器图像回收
当扫描器要对链接的图像进行回收时,就需要借助特征回收函数。另一方面,该函数被设定为内联函数,说明这个函数在ZBar执行过程中频繁被调用。
1 | inline void zbar_image_scanner_recycle_image (zbar_image_scanner_t *iscn, |
ZBar在回收(循环)图像时采用的方式是:遍历所有图像特征,根据特征标识符选择复活一组图像特征,然后销毁一组图像特征,实现内存空间有效利用,不占用过多内存空间。
扫描器新增特征
前面分析了扫描器对特征的回收和断开链接的过程,与之相对的,扫描器同样也需要加入新的特征的功能。
1 | void _zbar_image_scanner_add_sym(zbar_image_scanner_t *iscn, |
这里对特征的数据结构zbar_symbol_s
进行补充分析:
zbar_symbol_type_t type | 符号类型 |
unsigned int configs | 符号布尔配置位掩码 |
unsigned int modifiers | 符号修饰符位掩码 |
unsigned int data_alloc | 数据的分配大小 |
unsigned int datalen | 二进制符号数据的长度 |
char *data | 符号数据 |
unsigned pts_alloc | pts的分配大小 |
unsigned npts | 位置多边形中的点数 |
point_t *pts | 位置多边形中的点列表 |
zbar_orientation_t orient | 粗方向 |
refcnt_t refcnt | 引用计数 |
zbar_symbol_t *next | 结果(或同级)链接列表 |
zbar_symbol_set_t *syms | 分量 |
unsigned long time | 相对符号捕获时间 |
int cache_count | 缓存状态 |
int quality | 相对符号可靠性度量 |
以及特征集zbar_symbol_set_s的数据结构:
refcnt_t refcnt |
索引标识 |
int nsyms | 已过滤特征的数量 |
zbar_symbol_t *head | 第一个解码特征结果 |
zbar_symbol_t *tail | 最后一个未过滤的特征结果 |
在扫描器中添加新特征时,需要对特征的缓存状态和在特征集合中的位置进行判断,有以下几种情况:
(1)特征已被缓存或者当前特征不在集合的尾部,则直接在特征集合中插入新特征。
(2)特征未被缓存且者当前特征在集合的尾部,则改变集合尾部指针指向,在尾部添加新特征。
(3)对于未缓存的特征,加入集合中还需要对索引和对已过滤特征进行变更。
三、总结
本次代码分析对扫描器关于特征的回收和新增,以及特征和图像间的处理方式进行分析,下次将对扫描器配置和缓存部分展开分析。