最近需要做一个扫码乘车的功能,于是使用树莓派的摄像头扫描二维码来做一个demo 。 网上有部分人用的是zbar这个库,但是我安装后,发现并不能在Python3上使用,这就有点不太好了。经过我的多番寻找,发现有个叫pyzbar的库,可以结合opencv,可以做一个视频动态二维码扫描。
参考博客地址:
python3 + opencv +pyzbar 摄像头检测二维码并获取二维码内容_zx66zx的博客-CSDN博客(这个博主的代码可以直接用)
本文内容:
1.实现树莓派的二维码扫描
2.添加了如何选取最大的二维码功能
opencv的安装,这里就不再赘述,没有在树莓派上安装opencv的,可以参考我的这篇博客,其中引用了另一个博主的安装教程:树莓派4B安装OpenCV过程(转载)_Solitary_Han的博客-CSDN博客
pyzbar的安装,直接树莓派终端上使用如下命令即可
pip3 install pyzbar
我使用的是树莓派的csi摄像头,而不是usb摄像头,具体usb摄像头或者树莓派csi摄像头一开始怎么调试,怎么获取视频源,可以参考这篇文章树莓派OpenCV系列教程2:摄像头的基本使用 - 树莓派OpenCV教程 微雪课堂
代码功能如下:
在循环内,每隔0.5秒,获取一帧图像,然后调用pyzbar,识别二维码,然后把二维码信息打印在图像上,并且将图像显示出来
import time
import cv2
import numpy as np
# import zbar
import pyzbar.pyzbar as pyzbar
# main函数
if __name__ == '__main__':
# openCV 字体
font = cv2.FONT_HERSHEY_SIMPLEX
#定义图像源
cap = cv2.VideoCapture(0) # 0: use CSI camera,1:use USB camera
cap.set(3,480) # set Width
cap.set(4,360) # set Height
if(not cap.isOpened()):
print("[camera.py:cam]:can't open this camera")
while(True):
# 读入图片
ret, img = cap.read()
# 转灰度
img_ROI_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 解码 返回了识别到的多个二维码对象
barcodes = pyzbar.decode(img_ROI_gray)
# 对于每个识别到的二维码区域
for barcode in barcodes:
# 条形码数据为字节对象,所以如果我们想在输出图像上
# 画出来,就需要先将它转换成字符串
barcodeData = barcode.data.decode("utf-8")
barcodeType = barcode.type
text = "{} ({})".format(barcodeData, barcodeType)
# 打印字符在图片上
cv2.putText(img, text , (20,100),font,1,(0,255,0),4)
# 向终端打印条形码数据和条形码类型
print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData))
# 显示
#cv2.imshow('img_ROI', img_ROI_gray)
cv2.imshow('image', img)
if (cv2.waitKey(1)) == ord('q'):
break
# 进程停止0.5秒,为了降低图像识别的帧率,提升性能
time.sleep(0.5)
# 释放资源
cap.release()
cv2.destroyAllWindows()
效果图如下:pyzbar可以解析中文,比如我命令行窗口就输出了中文,但是opencv往图像上写字好像不支持中文
不知道为什么,奇卡无比。我用opencv做人脸识别都要比这个视频延迟低。具体原因我后续再找找吧。
我的实现思路非常简单,无非是先扫描一遍,获取解析的二维码数据,然后再遍历每个二维码数据,寻找面积最大的二维码
解析图像中的二维码数据的函数pyzbar.decode(img)方法的返回值是一个装着识别对象的列表,我们打印出来看,如下图:
该图中,有两个识别到的二维码对象,其中对象的一个重要参数就是rect,他标识这二维码在图像中的像素位置(左上角坐标),和二维码区域的宽和高。我就是利用这个宽和高,计算得出最大的二维码。
改进后的代码如下:
import time
import cv2
import numpy as np
# import zbar
import pyzbar.pyzbar as pyzbar
if __name__ == '__main__':
font = cv2.FONT_HERSHEY_SIMPLEX # openCV 字体
cap = cv2.VideoCapture(0) # 0: use CSI camera,1:use USB camera
cap.set(3,480) # set Width
cap.set(4,360) # set Height
if(not cap.isOpened()):
print("[camera.py:cam]:can't open this camera")
while(True):
# 读入图片
ret, img = cap.read()
# 转灰度
img_ROI_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 解码
barcodes = pyzbar.decode(img_ROI_gray) # 返回识别到的多个二维码对象的列表
area = 0 # 面积
max_barcode = None # 最大的二维码
# 选出面积最大的二维码
for barcode in barcodes:
(x,y,w,h) = barcode.rect # 坐标格式:[横坐标,纵坐标,长度,宽度] 单位:像素
if (area <= w*h):
area = w*h
max_barcode = barcode
# 处理最大的二维码信息
if (max_barcode != None):
# 条形码数据为字节对象,所以如果我们想在输出图像上
# 画出来,就需要先将它转换成字符串
barcodeData = max_barcode.data.decode("utf-8")
barcodeType = max_barcode.type
text = "{} ({})".format(barcodeData, barcodeType)
# 获取二维码坐标
(x,y,w,h) = max_barcode.rect # 坐标格式:[横坐标,纵坐标,长度,宽度] 单位:像素
print("location: ", max_barcode.rect)
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
# 打印字符在图片上
cv2.putText(img, text , (20,100),font,1,(0,255,0),4)
# 向终端打印条形码数据和条形码类型
print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData))
# 显示
cv2.imshow('image', img)
if (cv2.waitKey(1)) == ord('q'):
break
time.sleep(1) # 隔一秒,读一次图片
# 释放资源
cap.release()
cv2.destroyAllWindows()