最近搞了搞条码识别相关的东西,今天总结一下。
我们常用的条码识别工具有zxing、zbar等等。zxing的使用比较简单,一个函数直接调用就可以了,但是目前我发现它只能识别一张图中的一个条码,如果你要读多个条码那是不行的。这里贴一下使用方法:
Bitmap code_bmp = roi.ToBitmap();
BarcodeReader reader = new BarcodeReader();
reader.Options.CharacterSet = "UTF-8";
reader.Options.PureBarcode = false;
using (Bitmap bmp = code_bmp)
{
Result result = reader.Decode(bmp);
inf = result.Text.ToString();
}
然后就是zbar,python有pyzbar这个包,亲测是比较好用的,它可以同时识别一张图上的多个条码,而且还可以给出每个条码的位置信息。这是我在网上找到的代码,并且也自己试了一下:
frame = cv2.imread('/test/9.bmp')
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
barcodes = pyzbar.decode(gray)
for barcode in barcodes:
# 提取条形码的边界框的位置
# 画出图像中条形码的边界框
(x, y, w, h) = barcode.rect
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 255, 0), 2)
# 条形码数据为字节对象,所以如果我们想在输出图像上
# 画出来,就需要先将它转换成字符串
barcodeData = barcode.data.decode("utf-8")
# 绘出图像上条形码的数据和条形码类型
barcodeType = barcode.type
# 把cv2格式的图片转成PIL格式的图片然后在上标注二维码和条形码的内容
img_PIL = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
font = ImageFont.truetype('STFANGSO.TTF', 25)
# 字体颜色
fillColor = (0, 255, 0)
# 文字输出位置
position = (x, y - 25)
# 输出内容
strl = barcodeData
# 需要先把输出的中文字符转换成Unicode编码形式(str.decode("utf-8))
# 创建画笔
draw = ImageDraw.Draw(img_PIL)
draw.text(position, strl, font=font, fill=fillColor)
# 使用PIL中的save方法保存图片到本地
img_PIL.save('结果图.jpg', 'jpeg')
# 向终端打印条形码数据和条形码类型
print("扫描结果==》 类别: {0} 内容: {1}".format(barcodeType, barcodeData))
测试了一些图片,可以同时解析条码和QR二维码。但是会出现一些漏检的情况。
我需要在C#上实现这个功能,去找了相关的库,而且只能在x86平台上运行,目前还不知道怎么搞在x64上,如果有好心的大佬指点一二就好了。为什么没有深究呢?也是因为我测试之后发现准确率不够,因此就放弃了。
后来在网上调研了一些条码定位的方法,在此基础上我根据自己的需求做了一些修改和优化,目前达到了比较好的效果。下面是用OpenCVSharp实现的源码:
这个算法的前提是条码是水平放置的,不能歪斜。因为我们需要计算图像在X和Y方向上的梯度。条码由于它的特征,在Y方向上的梯度几乎是0,X方向上几乎是1,如图:
因此根据这个性质,我们可以滤掉一些条码外的信息,得到一个比较好的条码二值图。但是在对多种条码类型进行测试时,我发现很多码的中间间隔是很稀疏的,因此采用直接二值化再膨胀腐蚀的方法就不太好,不好调参。中间搁置了几天,有一天突然想着把图像伸缩一下会不会好点,结果确实很有效。
伸缩之后,这种条码区域就已经非常的明显了。接下来是要过滤掉一下其他的信息,由于条码上下通常就会印有对应的字符,有的格式还好,码和字隔得很开,用简单的开运算就可以过滤掉,但是有的就隔得很近,很容易粘连在一起。而且条码中间始终会有空隙,所以效果不好。后来想到再不同方向上先做膨胀腐蚀,就可以很好的填充条码中心,并分开字符和条码了。
这样初步可以得到以下结果:
最后再做一次后处理。我们能看到条码基本上是矩形的,我们可以计算它的轮廓以及最小外接矩,通过计算轮廓面积与最小外接矩的面积比,来判断这个区域是否最接近矩形。
最后就是检测结果啦~在很多图像上试验了表明效果还挺好~
目前该方法只适用于条码基本水平的情况,我在尝试使用频谱图先检测出文字方向,把图片校正之后再识别的方法,后续继续更新~
如果大佬有更好的方法,希望多多交流哦~
源码请移步:https://github.com/zhanzhanmiao/BarCode-Location-Recognition