二维码的生成与解析
商品条形码是二维码吗?
实际上条形码包括【一维条形码】和【二维条形码】。
我们常说的条形码就是【一维条形码】,而我们说的二维码则是【二维条形码】。我们最常见的二维码是QR Code,全称是 Quick Response
我们仔细观察下面的二维码可以发现,二维码实际上是由一系列黑白(或彩色的)方块表示,就像计算机只认识“0”和“1”一样。也正是这些方块的不同组合,表示了各种含义的数据信息
对比来讲【二维码】相比传统的【一维码】存储数据的效率更高,纠错能力也更强,所以目前二维码的应用也更加广泛。
现在你是不是对二维码多了一些了解?那接下来,我们来快速生成一个二维码吧!
二维码的生成
在Python中生成一个二维码非常简单,我们只需要安装几个模块,就可以用几行代码生成一个二维码。
首先,我们需要安装qrcode模块,用pip安装的语句如下:
pip install qrcode
紧接着,因为qrcode模块本身使用到了PIL模块,所以我们还需要安装PIL模块。
在Python3中的安装语句如下:
pip install pillow
安装完成后,我们就可以开始写代码了。想要生成二维码,我们只需要几句代码:
# 导入模块 import qrcode # 填入数据,并创建二维码图片 qr_im = qrcode.make(data='你好啊') # 显示二维码图片 qr_im.show()
上面代码关键的操作是--make函数的使用。最简单的使用就是传入一个data参数,也就是二维码中包含的数据信息。make函数会返回一个图片对象,有了这个图片,我们就可以调用show方法显示它了。
除了显示,我们还可以调用save方法将图片保存到本地,代码如下:
qr_im.save('qrcode.png')
调用save方法后,我们就可以在当前目录找到qrcode.png图片了。
我们发现外面的白色边框比较粗,而且每个小正方形也比较大。
那有什么方法自己设置吗?哈哈,想知道的话就继续往下学习吧!
make函数解析
在上一关我们学习了调用make函数需要传入一个data参数,而且make函数会返回一个图片对象,那你有想过make函数里面做了些什么操作吗?
我们先来看看make函数里面的代码:
def make(data=None, **kwargs): qr = QRCode(**kwargs) qr.add_data(data) return qr.make_image()
为了方便看,我把代码改成下面几句
# 创建二维码对象 qr = QRCode() # 在二维码中添加数据 qr.add_data(data) # 创建二维码图片 qr_im = qr.make_image()
由此可以看出,make函数做了三件事:
-
创建二维码对象;
-
在二维码中添加数据;
-
创建二维码图片,并返回。
因此,我们还可以通过创建QRCode对象的方式来创建二维码。
我们只需要实现上面三个操作即可,具体代码如下:
from qrcode import QRCode # 创建QRCode对象 qr = QRCode() # 在二维码中添加数据 qr.add_data('https://www.baidu.com/') # 创建二维码图片 qr_im = qr.make_image() # 保存二维码图片 qr_im.save('qrcode.png')
上面代码都非常好理解。在添加数据时,调用了add_data方法,这次传入的是一个网址。
之前我们扫码会以【文本】的方式显示添加的数据,这次直接进入了百度的网站。
因此我们可以知道,当我们添加的数据是一个网址时,扫码会直接进入网站。
精确生成一个二维码
了解了make函数具体做的事情后,我们就可以来看看怎样精确地生成一个二维码了。
在创建QRCode对象时,我们可以传入几个参数:
import qrcode qr = qrcode.QRCode( version=1, box_size=5, error_correction=qrcode.ERROR_CORRECT_H, border=1 )
我们来看看这四个参数的含义:
前面两个参数都非常好理解,我们具体看看后两个参数。
首先,你可能就会问,纠错能力是什么?
请思考:在你扫码时,是不是有些损坏了的二维码有时候也能扫出内容?但是,有些二维码破损了一点,就扫不出内容,而有的二维码破损了很多都还能扫出内容。
这种差异就是【纠错能力】不同而导致的。所以,【纠错能力】其实就是容许二维码损坏(错误)的百分比。
在qrcode中定义了四个常量,分别如下:
-
ERROR_CORRECT_L:纠正不超过7%的错误
-
ERROR_CORRECT_M(默认):纠正不超过15%的错误
-
ERROR_CORRECT_Q:纠正不超过25%的错误
-
ERROR_CORRECT_H:就在不超过30%的错误
说了这么多,现在应该知道【纠错能力】是什么了吧!
接下来,我们来看看border参数,也就是白色边框的大小。
在前面我们设置了一个box_size参数,表示最小正方形的边长,而border表示的是有几个白色小正方形。所以实际白色边框的宽度是border*box_size个像素。
知道这些后,下面这段代码你理解起来应该没有问题吧:
import qrcode qr = qrcode.QRCode( version=1, box_size=5, error_correction=qrcode.ERROR_CORRECT_H, border=1 ) qr.add_data('https://www.boxuegu.com/') qr_im = qr.make_image() qr_im.save('qrcode.png')
有时候,我们还可以不设置version参数,这个时候可以调用一个make方法,让它自动设置大小:
import qrcode qr = qrcode.QRCode( box_size=5, error_correction=qrcode.ERROR_CORRECT_H, border=1 ) # 设置为自动设置大小 qr.make(fit=True) qr.add_data('https://www.boxuegu.com/') qr_im = qr.make_image() qr_im.save('im.png')
去掉version参数后,我们调用了make方法,并把fit参数设置为True,这样程序会自动给我们设置合适的大小,完工~
生成二维码的操作我们就学习到这里,接下来,我们再来看看要怎么解析二维码!
二维码的解析
读取图片
要解析二维码我们还需要用到另外两个模块,它们分别是opencv和pyzbar模块。
opencv模块是用来读取图片的,而pyzbar则是解析二维码的关键,安装opencv的语句如下:
pip install opencv-python
安装pyzbar的语句如下:
pip install pyzbar
在解析二维码之前,我们先看看读取图片操作。
在安装好opencv模块后,我们就可以开始读取图片了,代码如下:
# 导入模块 import cv2 # 读取二维码图片 qrcode = cv2.imread('qrcode.png')
虽然模块叫opencv,但是导入的时候我们是导入cv2。
在导入模块后,我们就可以调用cv2模块的imread函数读取图片,执行后会返回一个特殊的图片对象,我们把这个对象交给pyzbar模块处理就能拿到二维码的数据了。
解析二维码的操作也非常简单,具体代码如下:
import cv2 from pyzbar import pyzbar # 读取二维码图片 qrcode = cv2.imread('qrcode.png') # 解析二维码中的数据 data = pyzbar.decode(qrcode) # 解析二维码中的主要数据 text = data[0].data.decode('utf-8') # 输出内容 print(text)
前面读取图片的操作我们已经讲过,那我们来看看解析二维码的操作。
在解析二维码时,我们解析了两次,第一次调用pyzbar.decode函数,传入我们的二维码图片。
这时候解析的结果是一个列表,我们瞄一眼它长什么样子:
[Decoded(data=b'https://www.boxuegu.com/', type='QRCODE', rect=Rect(left=51, top=51, width=368, height=368), polygon=[Point(x=51, y=51), Point(x=51, y=418), Point(x=419, y=419), Point(x=418, y=51)])]
虽然不知道是些什么东西,但可以看出来有很多。
但仔细一看,列表第一个数据不就是二维码的数据吗?哈哈,机灵的你看出了端倪。这也就是我们要进行第二次解析的原因。
最后输出结果如下:
https://www.boxuegu.com/
即我们在创建二维码时,通过add_data方法添加的数据。
现在解析二维码你也学会了,是不是能写个扫码小工具了啊?
先别急,我们还不知道怎么调用摄像头呢!所以我们再来学习一下怎么调用摄像头吧!
调用摄像头
前面我们用到的opencv模块,不仅可以读取图片,还可以调用摄像头,所以,我们不需要再额外安装模块了。
调用摄像头的代码如下:
import cv2 # 调用摄像头 cap = cv2.VideoCapture(0) # 释放摄像头 cap.release()
代码中我们调用了cv2.VideoCapture函数,这个函数是用来读取视频的。不过当我们传入0时,它会直接调用我们的摄像头。在使用完摄像头后,我们调用release方法释放摄像头。
不过上面的代码我们什么都没做,只是调用摄像头后立马释放了。
那要怎么才能【一直调用】摄像头呢?咱继续往下学习~
逐帧读取画面
在上面获取的cap对象中,有一个read方法可以读取到摄像头拍摄到的内容。
代码如下:
import cv2 cap = cv2.VideoCapture(0) # 读取一帧画面 ret, frame = cap.read() cap.release()
read方法会返回两个参数,第一个表示是否有下一帧,第二个则是当前帧的图片对象。
如果想要一直读取摄像头拍摄的图像,我们就需要循环读取,直到read方法返回的ret参数为False,完成上述操作的代码如下:
import cv2 cap = cv2.VideoCapture(0) ret, frame = cap.read() # 循环读取摄像头内容,直到没有下一帧 while ret: # 显示当前帧的图像 cv2.imshow('frame', frame) # 等待10毫秒 cv2.waitKey(10) # 继续读取下一帧图像 ret, frame = cap.read() # 销毁窗口 cv2.destroyAllWindows() cap.release()
循环读取摄像头内容:这里用ret作为循环条件,表示没有下一帧时结束。但是因为摄像头是一直在拍摄画面,所以这里不会结束。
显示当前帧的图像:我们可以调用cv2.imshow函数显示图像,该函数接收两个参数,分别是窗口名称和画面。但是这个函数只会显示一瞬间画面,因此我们还要结合cv2.waitKey函数,等待10毫秒。
继续读取下一帧图像:read方法每次只会读取一帧画面,所以我们需要在循环中一直调用read方法。
销毁窗口:在opencv中我们只要调用了cv2.imshow函数,就需要在最后调用cv2.destroyAllWindows函数,保证窗口真正销毁。
扫码工具的实现
扫码工具的实现非常简单,要想实现扫码功能我们需要有解析二维码的能力,以及调用摄像头的能力。
而这两种操作我们在前几关我们都讲解过了~
那具体流程又是怎样的呢?请看:
第一步,我们要把解析二维码的功能封装成一个函数,方便后面使用。
第二步,我们需要逐帧读取摄像头的画面,对每一帧画面进行解析。
第三步,我们要判断是否解析到了内容。如果解析到了,就停止循环,如果没解析到就继续循环。
好,理解了上面的流程,我们就可以开始写代码了。
首先,我们把解析二维码的操作编写成一个函数,代码如下
def decode_qr(im): data = pyzbar.decode(im) # 解析的结果默认为None text = None # 如果检测到二维码再解析主要数据 if data: text = data[0].data.decode('utf-8') return text
上面的代码相对于第三关中的代码做了一些修改,你有注意到么?
首先,把text设置为None,表示主要数据默认为None。
然后对第一次的解析结果data做判断,如果有数据才解析主要数据。
这样上面函数的功能就成了:传入图片,如果有二维码返回二维码的数据,如果没有返回None。
然后就是逐帧读取画面了:
def scanner(): cap = cv2.VideoCapture(0) ret, frame = cap.read() while ret: # 对当前帧画面进行解析 result = decode_qr(frame) # 如果解析到了结果就输出,没解析到就继续 if result: print(result) break cv2.imshow('decode qrcode', frame) cv2.waitKey(10) ret, frame = cap.read() cap.release() cv2.destroyAllWindows()
上面的代码也在第四关代码基础上进行了一些小的修改,我们来看一下。
在进入循环后,我们对当前读取到的画面进行解析。
如果解析到了内容,程序就会输出结果,然后跳出循环,这样就完成了我们的扫码工作。
扫码工具完整的代码如下:
import cv2 from pyzbar import pyzbar def decode_qr(im): data = pyzbar.decode(im) text = None if data: text = data[0].data.decode('utf-8') return text def scanner(): cap = cv2.VideoCapture(0) ret, frame = cap.read() while ret: result = decode_qr(frame) if result: print(result) break cv2.imshow('decode qrcode', frame) cv2.waitKey(10) ret, frame = cap.read() cap.release() cv2.destroyAllWindows() scanner()
因为第二步的操作也编写成了函数,所以需要在下面调用才会执行。怎么样,是不是挺简单的?你也赶快动手实践
一下吧~
因此你只需要记住那几个函数即可。为了方便你记忆,老师给你整理了下面这张图,请收好: