返回顶部

二维码的生成与解析

商品条形码是二维码吗?

实际上条形码包括【一维条形码】和【二维条形码】。

我们常说的条形码就是【一维条形码】,而我们说的二维码则是【二维条形码】。我们最常见的二维码是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()

因为第二步的操作也编写成了函数,所以需要在下面调用才会执行。怎么样,是不是挺简单的?你也赶快动手实践  

一下吧~

因此你只需要记住那几个函数即可。为了方便你记忆,老师给你整理了下面这张图,请收好:

 

posted @ 2020-12-15 11:29  Crazymagic  阅读(2720)  评论(0编辑  收藏  举报