巧用Python:用摄像头“扫码”
2025-05-10 14:57:16
这一讲我们来看看如何实现用摄像头“扫码”。
最初设想
在制作完生成二维码和条形码的课程之后,我的终极目标是希望为我家越积越多的书籍们做一个图书管理系统,而人工录入的工作实在太繁琐。因此我的设想是就像超市结账时的扫码那样,用摄像头将书籍后面的条形码统统扫一遍,记录下这些书籍的ISBN码。
然而!很傻很天真的我在实践这“宏图伟业”时遇到了麻烦!
摄像头 ≠ 扫码枪
通过平时观察,不难推测扫码枪是有“视力”的,但我忽略了它看东西的远近这一要素,还有它偷偷背地里打光这一事实,回想超市里人家扫码枪都是贴近货物的条形码在扫,还有红光闪现,而连接摄像头后,才意识到我这款摄像头是无法贴近物体扫码的,因为一靠近它的“视线”就模糊了,还有离远一些图像清晰,但采集细密的条形码影像效果仍然不好,直接影响了对实体书扫码的成功率。
在视频教程中,我直接扫描的是在电脑上打开的条形码图片,这种方式摄像头是可以正常扫码的,而对实体书条形码的扫码操作,我将会改为批量扫描包含条形码图片的方式,在之后的视频教程和公众号上,我会陆续公布相应的课程。
感慨万千之后,开始进入正题,来讲讲这节课遇到的知识点。
扫码所需要的库 pyzbar
无论是通过摄像头对采集到的影像实时来进行扫码,还是对已有的图片进行扫码,都需要pyzbar这个库来进行解码。
安装这个库时Windows环境只需:
pip install pyzbar
macOS环境需要用brew来安装:
brew install zbar
如果使用brew命令,不要忘记先运行brew upgrade和brew update,否则安装会遇到问题。
程序开头需要引入程序中会用到的decode方法
from pyzbar.pyzbar import decode
引入OpenCV库cv2
因为我们要用OpenCV的模块来捕获摄像头拍到的信息,所以程序开头要引入cv2这个库:
import cv2
如何安装OpenCV,请参看我的公众号里“OpenCV在macOS上的安装”这篇文章。
用来“捕获”图像的类VideoCapture
为了开启摄像头,我们要用到cv2里面的VideoCapture类
= cv2.VideoCapture(0)
myVC set(3,160)
myVC.set(4,120) myVC.
通过调用对象myVC的set方法,可以改变这个对象中的属性值,这里常量3代表采集图像的宽,4代表高。
当我们接触到一个陌生的类时,要了解它的构造和里面提供的方法、属性时,首要想到的应该是查询这个类的API文档,例如我们可能对OpenCV里面的类和方法并不了解,但可以去查询它的文档来学习:
https://docs.opencv.org/4.5.3/
获得连续影像
通过While无限循环,来不停抓取图像,并通过imshow方法显示在打开窗口中,这里用到了类VideoCapture对象myVC的read()方法,它返回两个值(能返回那么多值,Python真牛),第一个值如果是False,说明它没抓取到图像(我是怎么知道的,也是看文档),第二个值返回的就是抓取到的对象。
while True:
= myVC.read()
check, frame 'My Camera', frame)
cv2.imshow(for barcode in decode(frame):
print(barcode.data.decode('utf-8'))
if(cv2.waitKey(1)==ord('q')):
break
图像中可能不只有一个条形码或二维码,decode方法返回的是一个包含这些数据的列表,因此这里用了for循环来遍历列表中的每一项,这里的每一项,都是一个已命名的元组,要取某一项的具体值,只需在点“.”操作符后面跟具体的参数名称,这里我需要的ISBN值放在了参数data这里,由于它保存的是个字节类型的数据,还需要进一步调用字节对象的decode方法,将它的编码设为“utf-8”。
在无限循环当中,万万不能忘记的是一个可达的退出条件,这里设定的是如果按了q键就跳出循环。
释放占用的摄像头资源
在编程世界里也是要讲规矩的,用完了,就别占着了,所以不要忘记退出前释放摄像头资源并关闭窗口。
myVC.release() cv2.destroyAllWindows()
本节课完整代码
import cv2
from pyzbar.pyzbar import decode
= cv2.VideoCapture(0)
myVC set(3,160)
myVC.set(4,120)
myVC.while True:
= myVC.read()
check, frame 'My Camera', frame)
cv2.imshow(for barcode in decode(frame):
print(barcode.data.decode('utf-8'))
if(cv2.waitKey(1)==ord('q')):
break
myVC.release() cv2.destroyAllWindows()