zxing读取一维条码主要涉及4个类,分别是LuminanceSource、Binarizer、BinaryBitmap和OneDReader。第1、2和4是抽象类,根据对象的不同有不同的具体实现。LuminanceSource类用于存放图片数据,binarizer用于二值化图片,BinaryBitmap用于存放二值化图片,OneDReader用于解码。
一维条码解码时,从图片的中间行开始,交替地向上和向下进行扫描,同方向的两次扫描之间的间隔一般为图片的32份之一,以此来提高解码速度。每扫描一行,首先将该行从图片中提取出来,然后进行二值化,再进行解码,如果解码成功,扫描结束,否则继续扫描。这里记录一下二值化和解码的算法。
二值化基于灰度频数直方图(注意是頻数不是频率)来确定阈值。第一,统计获得该行的灰度直方图。第二,找到直方图的最高峰的峰值。第三,找另一高峰的峰值,这里采用的计算方法为score = buckets[x] * distanceToBiggest * distanceToBiggest,score最大的一点就是目标点,其中buckets[x]是灰度级为x的点的数量,distanceToBiggest是该点与直方图最高峰的点的距离。第四,找出上述两点之间的谷底,计算方法为score = (firstPeak-x)* (firstPeak-x)* (secondPeak - x) * (maxBucketCount - buckets[x]); 其中,firstPeak是指上述两个点中灰度值较小的点,secondPeak是指灰度值较大的点,x是指当前点,maxBucketCount 是指直方图的最高峰峰值。第五,以谷底点作为阈值进行二值化。
利用匹配的方法进行解码。首先,找到条形码的起始位置。条形码以黑-白-黑三条等宽的方条开始,即模板为[1,1,1]。因此,在二值化后,找到该行的第一个黑-白-黑间隔的区域,假设该区域中黑-白-黑包含的像素数量分别为[a,b,c],通过匹配[a,b,c]和[1,1,1]来判断该区域是否条码的起始区域。匹配的函数是patternMatchVariance。其原理较为简单:第一,计算出方条的平均宽度w=(a+b+c)/(1+1+1)*v,其中v是一个经验系数,用于提高鲁棒性。第二,求出累积误差的比例e=(|a-1*w|+|b-1*w|+|b-1*w|)/(a+b+c),如果e小于某个经验值,就意味着匹配成功。然后是解码。解码也是以匹配的方式实现的。以ean13型的条码为例,每个单元用7个方条,以黑-白-黑-白的形式出现,模板为[B1,W1,B2,W2],其中B1+W1+B2+W2=7,例如,[3, 2, 1, 1]就代表数字0。解码的方法与上述类似,在条码的起始区域之后,找到黑-白-黑-白的区域,利用上述相同的方法与不同的模板进行匹配,从而得到该区域表示的值。
上述是一维码解码的主要过程,解码时如果解码失败,会将图像旋转一定角度进行从新扫描和解码。