最近一直忙于科研,好久没有更新博客了。今天更新一篇关于使用树莓派进行二维码识别的文章,是笔者树莓派项目开发的第四篇博客,希望能够给大家带来一丝的帮助。
现在二维码活跃在我们身边的大街小巷,基本上每天都会和二维码打交道,共享单车啊,移动支付等。那么如何实现二维码的识别呢,其实我们仔细观察二维码的特征的话,可能会看出一些特征,每一个QR码,都有三个定位块。识别二维码时会先找到定位块,然后开始读取二维码的的编码信息,然后遵循一定的规则对二维码的编码信息进行解码(翻译),解码出的内容就是我们想要的内容了,可以跳转网站,查看文字信息等。二维码识别的原理基于以上的过程,当然现在也有很多开源的二维码识别工具,如zbar和zxing。
硬件:树莓派3B plus 和 usb摄像头
软件: python2.7版本、二维码识别开源工具ZBar和opencv(opencv的安装可参考我的博客)
zbar 官网 http://zbar.sourceforge.net/
ZBar是一个开源软件套件,用于从各种来源读取条形码,例如视频流,图像文件和原始强度传感器。 它支持许多流行的符号(条形码类型),包括EAN-13 / UPC-A,UPC-E,EAN-8,
Code 128,Code 39,Interleaved 2 of 5和QR Code。灵活的分层实现方便了任何应用程序的条形码扫描和解码,可轻松地将条形码扫描小部件集成到您的Qt,GTK +或PyGTK GUI应用程序中,具备python,C++等多种语言API接口。广泛应用于零售、自动文档处理、库存跟踪、移动应用等领域。ZBar的特性如下:
命令行安装:sudo apt-get install python-zbar
直接安装,识别英文一点问题都没有,识别中文不支持。
测试安装成功,进入python 环境: import zbar
源码安装,可识别中文
1、wget命令用来从指定的URL下载zbar源码,命令如下:
wget http://downloads.sourceforge.net/project/zbar/zbar/0.10/zbar-0.10.tar.gz
下载不成功的话,先用电脑下载zbar-0.10.tar.gz,上传到树莓派的pi目录下
2、解压zbar的源文件,解压至pi目录下的zbar-0.10文件夹
tar -zvxf zbar-0.10.tar.gz
3、zbar是基于C语言开发的,安装编译时需要编译器,安装python-gtk和libqt4-dev
sudo apt-get install python-gtk2-dev
4、安装libqt4-dev
sudo apt-get install libqt4-dev
5、进入zbar-0.10文件夹,运行configure 命令如下,此步运行成功生成makefile
./configure --without-imagemagick -disable-video -without-qt -without-gtk -without-x
6、 编译makefile : make
7、 make安装: sudo make install
8、 测试进入python环境:import zbar
注意:第5步安装时要进入/home/pi/zbar-0.10目录,第6、7步安装时可能会出现错误,但是并不影响使用。
ZBar是日本人写的,若要识别带有中文文字的二维码,需要在安装的时候加个小插曲,需要修改一下ZBar源文件里面的函数:修改源文件下zbar-0.10/zbar/qrcode/qrdectxt.c
终端使用nano或者vim编辑器修改zbar-0.10/zbar/qrcode/qrdectxt.c
函数,以下该步骤需要在下载完源码后进行,修改完成后再进行编译和安装。
1、打开qrdectxt.c
,采用nano编辑器
2、找到默认编码的函数,修改编码,将 ISO8859-1,换成 GB18030 将SJIS,换成GB2312
3、找到默认编码定义的list,修改解码编码顺序
4、编译源码,安装ZBar
按照以上的步骤安装基本不会出现问题,如果出现问题仔细检查是否缺少相应的依赖安装即可。
ZBar可以直接对输入的图像提取二维码、扫码和解码,下面是笔者根据zbar的帮助文档改写的一个快速实现二维码识别的Demo,可实现对实施视频流中的二维码或者一维条码的识别,当二维码或者一维码的排放位置相对摄像头比较正时识别效果较好。
#-*- coding: UTF-8 -*-
# Simple QR code recognition
# @author: zdl
# import the necessary packages
#import simple_barcode_detection
import cv2
import numpy as np
import zbar
from PIL import Image
# create a reader
scanner = zbar.ImageScanner()
# configure the reader
scanner.parse_config('enable')
font=cv2.FONT_HERSHEY_SIMPLEX
camera=cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
grabbed, frame = camera.read()
if not grabbed:
break
pil= Image.fromarray(frame).convert('L') # 转成灰度图像
width, height = pil.size
raw = pil.tobytes()
zarimage = zbar.Image(width, height, 'Y800', raw)
scanner.scan(zarimage)
for symbol in zarimage:
# do something useful with results
if not symbol.count:
print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data
cv2.putText(frame,symbol.data,(20,100),font,1,(0,255,0),4)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
但是为提高扫码和解码的效率,我们先使用图像处理算法实现对二维码的定位并提取二维码的图像,将该部分的图像送入ZBar的扫码器中。如何实现对二维码的定位呢,方法如下:
# -*- coding: UTF-8 -*-
# Simple QR code detection
# @author: zdl
# ZBar+python2.7.13
import cv2
import numpy as np
import zbar
# 基于轮廓定位QR位置
def find_code(img):
# 高斯滤波
blur = cv2.GaussianBlur(img,(5,5),0)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret,th = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# 形态学操作
mask=cv2.erode(th,None,iterations=4)
mask=cv2.dilate(mask,None,iterations=4)
# 图像反色
cv2.bitwise_not(mask, mask)
# 寻找轮廓
_,contours,hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 寻找QR码的位置
if len(contours)>0:
cnt = max(contours, key=cv2.contourArea)
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x-15,y-15),(x+w+15,y+h+15),(0,255,0),3)
img_ROI = img[y-15:y+h+15, x-15:x+w+15]
else:
img_ROI = img
return img_ROI
# main函数
if __name__ == '__main__':
# 读入图片
img = cv2.imread('introduce.jpg', 1)
# 定位QR码的位置
img_ROI = find_code(img)
# 初始化scanner
scanner = zbar.ImageScanner()
scanner.parse_config('enable')
font = cv2.FONT_HERSHEY_SIMPLEX # openCV 字体
img_ROI_gray = cv2.cvtColor(img_ROI, cv2.COLOR_BGR2GRAY)
# 扫码
width, height = img_ROI_gray.shape # 获取图片大小
raw = img_ROI_gray.tobytes() # 图像矩阵数据转为字节数据
zarimage = zbar.Image(width, height, 'Y800', raw) # 设置参数
scanner.scan(zarimage) # 扫码
# 解码
for symbol in zarimage:
# do something useful with results
if not symbol.count:
print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data
else:
print 'no'
#cv2.putText(img,symbol.data,(20,100),font,1,(0,255,0),4) # 打印字符在图片上
# DisPlay
cv2.imshow('img_ROI', img_ROI_gray)
cv2.imshow('image', img)
cv2.waitKey(0)
运行效果:
基于本文,我们已经实现了二维码的识别,那么结合树莓派语音合成和树莓派控制方面的知识,是不是可以做点好玩的事情呢。