社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

用OpenCV和Python识别二维码和条形码

景略集智 • 5 年前 • 793 次点击  
阅读 35

用OpenCV和Python识别二维码和条形码

本文首发在集智专栏


导读:计算机视觉专家Adrian Rosebrock近日分享了如何借助OpenCV和Zbar,编写出能够实时识别二维码和条形码的扫描程序,最后部署在树莓派上,成功制作一款实用的条形码&二维码扫描设备。

最近有朋友问我(作者Adrian Rosebrock——译者注)OpenCV里有没有什么模块能直接识别条形码和二维码,很遗憾,答案是没有。但是OpenCV能够加快读取条形码和二维码的过程,包括从硬盘加载图像,从视频流中抓取新的帧,并进行处理。 等我们获取图像或视频帧后,就可以将其传入Python中专用的条形码解码库,比如Zbar。 然后Zbar会对条形码或二维码进行解码。OpenCV可以接着执行进一步的图像处理工作以及展示结果。 听起来有些复杂,其实整个处理过程相当简单明了。程序库Zbar也衍生了很多变体,其中pyzbar是我的最爱。

在本文,我会教你怎样用OpenCV和Zbar读取条形码和二维码。而且,我还会展示怎样将我们制作的这个条形码&二维码扫描仪部署到树莓派上!!

使用OpenCV和ZBar打造一款条形码及二维码扫描仪

本文主要分为四部分。

  • 在第一部分,我会教你如何安装Zbar库(Python绑定)。
  • Zbar库会连同OpenCV一起用于扫描条形码和二维码。
  • 等正确配置好Zbar和OpenCV以后,我会展示如何用它们扫描一张图像上的条形码和二维码。
  • 先识别一张图像上的条形码和二维码练练手后,我们就进入下一阶段:用OpenCV和Zbar实时读取二维码和条形码。
  • 最后,我会展示如何将制作好的实时二维码&条形码扫描仪部署到树莓派上。

安装Zbar(带Python绑定)用于解码条形码&二维码

前段时间Staya Mallick在LearnOpenCV博客上发表了一篇实用教程,讲解如何用Zbar扫描条形码。

本文关于Zbar安装部分基本上是根据这篇博文的指导,但是做了一点改进,主要是围绕安装Python Zbar绑定部分,目的是确保我们能:

使用Python3(官方Zbar Python绑定只支持Python 2.7) 准确地检测和定位图像中二维码及条形码

安装所需的软件,只需简单三步。

第一步:从apt或brew库中安装Zbar

在Ubuntu或树莓派上安装Zbar

$ sudo apt-get install libzbar0
复制代码

在MacOS系统中安装Zbar

使用brew在macOS系统中安装Zbar也很容易(假定你已经安装了Homebrew):

$ brew install zbar
复制代码

第二步:创建一个虚拟环境,安装OpenCV。

这里你有俩个选择: 使用现成的已经安装好了OpenCV的虚拟环境(跳过这一步,看第三步)。 或者创建一个新的独立的虚拟环境,安装OpenCV。

虚拟环境对于Python开发来说是非常实用的做法,我非常鼓励使用虚拟环境。

我选择创建一个新的独立的Python 3 虚拟环境,然后安装了OpenCV,并将环境命名为barcode:

$ mkvirtualenv barcode -p python3
复制代码

注:如果你已经安装好了OpenCV,就可以跳过OpenCV编译过程,只需将你的cv2.so绑定符号链接(sym-link)入你的新Python虚拟环境中的site-pakages目录。

第三步:安装Pyzbar 现在我已经安装了Python 3

虚拟环境,命名为barcode,然后激活了barcode环境,安装pyzbar:

$ workon barcode
$ pip install pyzbar
复制代码

如你不是用的Python 虚拟环境,只需:

$ pip install pyzbar
复制代码

如果想将pyzbar安装到Python版系统中,确保你也使用sudo命令。

用OpenCV解码单张图像上的条形码和二维码

在我们实现能实时读取条形码和二维码之前,我们首先创建一个单张图像扫描仪练练手。

打开一个新文件,命名为barcode_scanner_image.py,插入如下代码:

# 导入所需工具包
from pyzbar import pyzbar
import argparse
import cv2

# 构建参数解析器并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
 help="path to input image")
args = vars(ap.parse_args())
复制代码

在第2-4行代码,我们导入了所需的工具包。

需要按照上一部分的指令安装pyzbar和cv2(OpenCV)。不过,在Python安装中包含了argparse,负责解析命令行参数。

对于该脚本我们有一个必需的命令行参数(--image),在7-10行进行解析。

你会在这部分结尾处看到在传入包含输入图像路径的命令行参数时,如何运行这里的脚本。

现在,我们获取输入图像,运行pyzbar:

# 加载输入图像
image = cv2.imread(args["image"])

# 找到图像中的条形码并进行解码
barcodes = pyzbar.decode(image)
复制代码

在第13行,我们通过图像的路径(包含在我们很方便的args目录中)加载图像。

从这里,我们调取pyzbar.decode来发现和解码图像中的条形码(第16行)。

我们还没完成——现在我们需要解析包含在barcode变量中的信息:

# 循环检测到的条形码
for barcode in barcodes:
 # 提取条形码的边界框的位置
 # 画出图像中条形码的边界框
 (x, y, w, h) = barcode.rect
 cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)

 # 条形码数据为字节对象,所以如果我们想在输出图像上
 # 画出来,就需要先将它转换成字符串
 barcodeData = barcode.data.decode("utf-8")
 barcodeType = barcode.type

 # 绘出图像上条形码的数据和条形码类型
 text = "{} ({})".format(barcodeData, barcodeType)
 cv2.putText(image, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,
  0.5, (0, 0, 255), 2)

 


    
# 向终端打印条形码数据和条形码类型
 print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData))

# 展示输出图像
cv2.imshow("Image", image)
cv2.waitKey(0)
复制代码

从19行开始,我们循环检测到的barcodes。 在这里的循环中,我们继续:

从barcode.rect对象(22行)提取边界框(x,y)坐标,这样能让我们定位和确定当前条形码在输入图像的位置。

围绕着检测到的barcode(第23行),在图像上画出边界框。

将barcode解码为“utf-8”字符串,提取barcode的类型(第27行和28行)。调取.decode(“utf-8”)函数将对象从字节数组转换为字符串,非常关键。你可以通过删除或添加注释,试验一下结果。

在图像上格式化和绘制barcodeData和barcodeType(第31-33行)。

最后,输出同样的数据,朝终端输入信息以进行调试(第36行)。

我们测试一下搭建的OpenCV条形码扫描仪。 从这里,打开你的终端,执行如下命令:

$ python barcode_scanner_image.py --image barcode_example.png
[INFO] Found QRCODE barcode: {"author": "Adrian", "site": "PyImageSearch"}
[INFO] Found QRCODE barcode: https://www.pyimagesearch.com/
[INFO] Found QRCODE barcode: PyImageSearch
[INFO] Found CODE128 barcode: AdrianRosebrock
复制代码

可以在终端中看到,全部4个条形码均被正确的发现和解码!

如图所示,识别出了图像中的条形码和二维码,以红框标出,并显示出了它们包含的信息。

用OpenCV实时读取条形码和二维码

在前面部分中,我们学习了如何为单张图像创建一个Python+OpenCV条形码扫描仪。

我们的条形码和二维码扫描仪效果很好——但是问题来了,我们能实时检测和解码条形码+二维码吗?

我们试试看。打开一个新文件,命名为barcode_scanner_video.py,插入如下代码:

# 导入所需工具包
from imutils.video import VideoStream
from pyzbar import pyzbar
import argparse
import datetime
import imutils
import time
import cv2

# 创建参数解析器,解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-o", "--output", type=str, default="barcodes.csv",
 help="path to output CSV file containing barcodes")
args = vars(ap.parse_args())
复制代码

在第2-8行,我们导入了所需的工具包。 这里回想一下上面的解释,你应该识别pyzbar,argparse和cv2. 我们会使用VideoStream以高效和单线程的方式处理获取的视频帧。如果你的系统中没有安装imutils,只需使用如下命令:

$ pip install imutils
复制代码

我们接着解析一个可选的命令行参数--output,其包含了指向输出结果CSV文件的路径。该文件会包含从视频流中检测到和解析出的条形码的时间戳及载荷。如果该参数没有指定,那么CSV文件就会被我们当前名为“barcodes.csv”的工作目录所替换(第11-14行)。

在这里,我们初始化视频流,打开CSV文件:

# 初始化视频流,让摄像头热热身
print("[INFO] starting video stream...")
# vs = VideoStream(src=0).start()
vs = VideoStream(usePiCamera=True).start()
time.sleep(2.0)

# 打开输出CSV文件,用来写入和初始化迄今发现的所有条形码
csv = open(args["output"], "w")
found = set()
复制代码

在第18-19行,我们初始化和启动了视频流,你可以: 使用自己的USB网络摄像头(无注释行第18行及注释行第19行) 或者如果你是使用树莓派的话(和我一样),可以用PiCamera(无注释行第19行及注释行第18行)。

我选择使用我的树莓派 PiCamera,下部分会说到。

然后我们等上几秒钟,让摄像头热热身(第20行)。

我们会将发现的所有条形码和二维码以CSV文件写入硬盘(确保不要写重复)。这里只是一种记录条形码的例子,当然你可以按照自己的喜好来,比如检测到条形码后,将它们读取为:

  • 将其保存在SQL数据库中
  • 将其发送到服务器
  • 将其上传至云端
  • 发送邮件或文本信息

实际操作随意,我们只是用CSV文件作为示例。

我们在第24行代码打开CSV文件以写入硬盘。如果你修改了代码以添加到文件,你可以只需将第二个参数从“w”改为“a”(但是你后面只能换种方式搜索重复文件)。

我们也初始化一个set用于found条形码。这个set会包含独一无二的条形码,防止出现重复。

我们开始获取和处理视频帧:

# 循环来自视频流的帧
while True:
 # 抓取来自单线程视频流的帧, 
 # 将大小重新调整为最大宽度400像素
 frame = vs.read()
 frame = imutils.resize(frame, width=400)

 # 找到视频中的条形码,并解析所有条形码
 barcodes = pyzbar.decode(frame)
复制代码

在第28行,我们开始循环,继续抓取来自视频流中的frame,并调整大小(第31和32行)。

在这里,我们调取pyzbar.decode以检测和解码frame中的全部条形码和二维码。

我们接着循环检测到的barcodes:

 # 循环检测到的条形码
 for barcode in barcodes:
  # 提取条形码的边界框位置
  # 绘出围绕图像上条形码的边界框
  (x, y, w, h) = barcode.rect
  cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)

  # 条形码数据为字节对象,所以如果我们想把它画出来
  # 需要先把它转换成字符串
  barcodeData = barcode.data.decode("utf-8")
  barcodeType = barcode.type

  # 绘出图像上的条形码数据和类型
  text = "{} ({})".format(barcodeData, barcodeType)
  cv2.putText(frame, text, (x, y - 10),
   cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)

  # 如果条形码文本目前不在CSV文件中, write
  # 就将时间戳+条形码 to disk and update the set
  if barcodeData not in found:
   csv.write("{},{}\n".format(datetime.datetime.now(),
    barcodeData))
   csv.flush()
   found.add(barcodeData)
复制代码

如果看看前面的循环部分,你会发现这里循环和之前的很像。

实际上,第38-52行和前面识别单张图像的脚本是一样的。这部分代码详情解释,参见单张图像条形码检测和扫描部分。

第56-60行代码比较新。在这些行代码中,我们是检查是否发现了独有的(此前没有发现)条形码(第56行)。

如果是这种情况,我们将时间戳和数据写成CSV文件(第57-59行)。此外还可以将barcodeData添加到found集,作为一种处理重复文件的简单方法。

在实时条形码扫描脚本的剩余代码行中,我们展示视频帧,检查是否按退出键,并进行清除:

 # 展示输出帧
 cv2.imshow("Barcode Scanner", frame)
 key = cv2.waitKey(1) & 0xFF

 # 如果按下”q”键就停止循环
 if key == ord("q"):
  break

# 关闭输出CSV文件进行清除
print("[INFO] cleaning up...")
csv.close()
cv2.destroyAllWindows()
vs.stop()
复制代码

在第63行,我们展示输出帧。

然后在第64-68行,我们检查是否按了“q”,执行主循环。

最后,我们在第72-74行执行清除。

在树莓派上部署条形码和二维码扫描仪

我决定使用树莓派、触摸屏和一个充电宝打造一款自己的实时条形码扫描仪。

下图显示的是我的组装成果。如果你也想自己做一个,以下是需要的部件:

  • 树莓派3(你也可以用最新的 3 B+)
  • 树莓派摄像头模块
  • Pi Foundation 7英寸触摸屏
  • RAVPower 22000mAh充电宝

很容易就能组装好。

在这里,打开你树莓派上的终端,用如下命令启动应用(这一步需要一个键盘/鼠标,但是后面就用不着了):

$ python barcode_scanner_video.py
[INFO] starting video stream...
复制代码

等一切准备就绪后,就可以将条形码展示给摄像头了,可以打开barcode.csv文件(或者如果你愿意,也可以在另一个终端上执行tail -f barcodes.csv,查看打开CSV文件时的数据)。

我首先向摄像头展示了一个黑色背景上的二维码,Zbar很轻松的检测到了它:

然后又在我家厨房里用这套装置发现了另一个二维码:

成功了!而且能多角度扫描识别二维码。

现在,我们试试一个包含了json-blob数据的二维码:

最后,我试了试传统的1维条形码:

1维的条形码对于我们这套系统来说略微难些,因为摄像头不支持自动对焦。但是最后还是成功的检测和解码了条形码。

如果你用有自动对焦功能的USB网络摄像头的话,效果要好得多。

结语

在本文,我们讨论了怎样用OpenCV和Python库Zbar打造一款条形码和二维码扫描仪。

将Zbar和OpenCV安装后,我们创建了两个Python脚本:

  • 第一个用于扫描单张图像上的条形码和二维码。
  • 第二个用于实时读取条形码和二维码的信息。 在这两种情况中,我们都使用了OpenCV来加快进程。

最终,我们将创建好的程序部署到树莓派上,并且能成功实时识别条形码和二维码。

可以自己试着去做一条这样的条形码&二维码扫描仪,项目源代码下载

参考资料:www.pyimagesearch.com


0806期《人工智能-从零开始到精通》限时折扣中!

戳这里看详情

谈笑风生 在线编程 了解一下?

(前25位同学还可领取¥200优惠券哦)


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/aK7KqobFvf
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/21173
 
793 次点击