基于Python的QRcode二维码实验_(生成&识别)

一、机器视觉之QRcode

问:什么是QRcode呢?
答:二维码(2-dimensional bar code),是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的。它能将数字、英文字母、汉字、日文字母、特殊符号(如空格,%,/ 等)、二进制等信息记录到一个正方形的图片中。
因此,在转换的过程中,离不开编码压缩方式。在许多种类的二维条码中,常用的码制有:Data Matrix,Maxi Code,Aztec,QR Code,Vericode,PDF417,Ultracode,Code 49,Code 16K等。
二维码在现实生活中的应用越来与普遍,归功于 QR code 码制的流行。我们常说的二维码就是它,所以,二维码又被称为 QR code。
QR code 是一种矩阵式二维条码(又称棋盘式二维条码)。它是在一个矩形空间通过黑、白像素在矩阵中的不同分布进行编码。在矩阵相应元素位置上,用点(方点、圆点或其他形状)的出现表示二进制“1”,点的不出现表示二进制的“0”,点的排列组合确定了矩阵式二维条码所代表的意义。
我们的目的是要使用 Python 生成 QR 码,那我们需要先了解二维码(QR 码)的结构。根据标准(ISO/IEC 18004),我们可以了解到 QR 码结构如下:
在这里插入图片描述
二维码的绘制大概过程如下:
在二维码的左上角、左下角、右上角绘制位置探测图形,位置探测图形一定是一个 7x7 的矩阵;
(1)绘制校正图形,校正图形一定是一个 5x5 的矩阵;
(2)绘制两条连接三个位置探测图形的定位图形;
(3)在上述图片的基础上,继续绘制格式信息;
(4)接着绘制版本信息;
(5)填充数据码和纠错码到二维码图中;
(6)最后绘制蒙版图案。因为按照上述方式填充内容,可能会出现大面积空白或黑块的情况,导致扫描识别十分困难。所以需要对整个图像与蒙版进行蒙版操作(Masking),蒙版操作即为异或 XOR 操作。在这一步,我们可以将数据排列成各种图片。

问:主要运用qrcode库文件、这是个什么东东呢?
答: 这里给一篇博客有详细叙述:Python生成二维码

开源库import qrcode具体使用方法:
编码:

#原始二维码编码
import qrcode
img = qrcode.make('helloworld')
#带图片的编码方式
qr = qrcode.QRCode(
    version=5,
    error_correction=qrcode.constants.ERROR_CORRECT_H,
    box_size=8,
    border=4)

解码:

#调用decode()的解码函数
def decode_qr_code(code_img_path):
    if not os.path.exists(code_img_path):
        raise FileExistsError(code_img_path)
    # Here, set only recognize QR Code and ignore other type of code
    return pyzbar.decode(Image.open(code_img_path), symbols=[pyzbar.ZBarSymbol.QRCODE])

二、基于Python的QRcodetest

环境:python3.7+zbar+qrcode

(一)配置环境

打开cmd、pip分别安装以下库文件:(zxing也是一个强大的二维码开源库文件,建议安装)

pip install opencv-python
pip install numpy
pip install pillow
pip install myqr
pip install qrcode
pip install zxing

tips:记得安装完成后,如果是eclipse要重新启动一次才能加载进来

(二)生成自己的二维码

1 MyQr制作gif二维码:

同目录下放置一张gif格式图片
在这里插入图片描述

在这里插入图片描述 在这里插入图片描述

源码:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from MyQR import myqr
myqr.run(
    # 在命令后输入链接或者句子作为参数,然后在程序的当前目录中产生相应的二维码图片文件,默认命名为“qrcode.png”
    words='helloworld',
    version=1,  # 设置容错率为最高默认边长是取决于你输入的信息的长度和使用的纠错等级;而默认纠错等级是最高级的H
    level='H',  # 控制纠错水平,范围是L、M、Q、H,从左到右依次升高
    picture='test.gif',  # 用来将QR码图像与一张同目录下的图片相结合,产生一张黑白图片,格式可以是.jpg, .png, .bmp, .gif
    colorized=True,  # 可以使产生的图片由黑白(False)变为彩色(True)的
    contrast=1.0,  # 用以调节图片的对比度,1.0 表示原始图片,更小的值表示更低对比度,更大反之。默认为1.0。
    brightness=1.0,  # 用来调节图片的亮度
)

2 qrcode制作带图片的二维码:
新建工程QRcodeTest;新建PyDev包,命名为MakeMyQRcode:
在这里插入图片描述

因为我想做出一个漂亮简单一点的code,所以首先在目录文件下贴入一张图片,命名为QRcodeCenter,like this(左:成果图,右:准备中心图片):
在这里插入图片描述 在这里插入图片描述

源码:

'''
==============================
test1:生成二维码及查看
==============================
'''
from PIL import Image
import qrcode

qr = qrcode.QRCode(
    version=5, error_correction=qrcode.constants.ERROR_CORRECT_H, box_size=8, border=4)
qr.add_data("这里是二维码信息!")
qr.make(fit=True)

img = qr.make_image()
img = img.convert("RGBA")

icon = Image.open("QRcodeCenter.jpg")  # 这里是二维码中心的图片

img_w, img_h = img.size
factor = 4
size_w = int(img_w / factor)
size_h = int(img_h / factor)

icon_w, icon_h = icon.size
if icon_w > size_w:
    icon_w = size_w
if icon_h > size_h:
    icon_h = size_h
icon = icon.resize((icon_w, icon_h), Image.ANTIALIAS)

w = int((img_w - icon_w) / 2)
h = int((img_h - icon_h) / 2)
icon = icon.convert("RGBA")
img.paste(icon, (w, h), icon)
img.show()   # 显示图片,可以通过save保存

(三)识别二维码

在工程QRcodeTest;新建PyDev包,命名为ScanQRcode:
在这里插入图片描述
运行结果:
在这里插入图片描述 在这里插入图片描述
源码:

# -*- coding:utf-8 -*-

'''
====================================
test2:生成二维码保存及对二维码解码输出
====================================
'''
import os
import qrcode
from PIL import Image
from pyzbar import pyzbar


def make_qr_code(content, save_path=None):
    qr_code_maker = qrcode.QRCode(version=5,
                                  error_correction=qrcode.constants.ERROR_CORRECT_M,
                                  box_size=8,
                                  border=4,
                                  )
    qr_code_maker.add_data(data=content)
    qr_code_maker.make(fit=True)
    img = qr_code_maker.make_image(fill_color="black", back_color="white")
    if save_path:
        img.save(save_path)
    else:
        img.show()  # 中间图不显示


def make_qr_code_with_icon(content, icon_path, save_path=None):
    if not os.path.exists(icon_path):
        raise FileExistsError(icon_path)

    # First, generate an usual QR Code image
    qr_code_maker = qrcode.QRCode(version=5,
                                  error_correction=qrcode.constants.ERROR_CORRECT_H,
                                  box_size=8,
                                  border=4,
                                  )
    qr_code_maker.add_data(data=content)
    qr_code_maker.make(fit=True)
    qr_code_img = qr_code_maker.make_image(
        fill_color="black", back_color="white").convert('RGBA')

    # Second, load icon image and resize it
    icon_img = Image.open(icon_path)
    code_width, code_height = qr_code_img.size
    icon_img = icon_img.resize(
        (code_width // 4, code_height // 4), Image.ANTIALIAS)

    # Last, add the icon to original QR Code
    qr_code_img.paste(icon_img, (code_width * 3 // 8, code_width * 3 // 8))

    if save_path:
        qr_code_img.save(save_path)  # 保存二维码图片
        qr_code_img.show()  # 显示二维码图片
    else:
        print("save error!")


def decode_qr_code(code_img_path):
    if not os.path.exists(code_img_path):
        raise FileExistsError(code_img_path)

    # Here, set only recognize QR Code and ignore other type of code
    return pyzbar.decode(Image.open(code_img_path), symbols=[pyzbar.ZBarSymbol.QRCODE])


if __name__ == "__main__":
    print("============QRcodetest===============")
    print("         1、Make a QRcode            ")
    print("         2、Scan a QRcode            ")
    print("=====================================")
    print("1、请输入编码信息:")
    code_Data = input('>>:').strip()
    print("正在编码:")
    # ==生成带中心图片的二维码
    make_qr_code_with_icon(
        code_Data, "QRcodeCenter.jpg", "qrcode.png")  # 内容,center图片,生成二维码图片
    print("图片已保存,名称为:qrcode.png")
    results = decode_qr_code("qrcode.png")
    print("2、正在解码:")
    if len(results):
        print("解码结果是:")
        print(results[0].data.decode("utf-8"))
    else:
        print("Can not recognize.")

三、调用opencv库摄像头识别图像

(一)用opencv找出(条形码&二维码)位置

opencv抠图教程
按照教程一步步调试运行(这里用一张条形码和一张二维码进行测试):

  • QRcodetest项目下新建ScanQRcode.py
    在这里插入图片描述
  • 并保存两张图片在项目目录下:分别为qrcode.pngtest2.jpg
    在这里插入图片描述
    运行测试:(不支持二维码)
    qrcode.png:
    在这里插入图片描述
    test2.jpg:
    在这里插入图片描述
    遇到问题:
    都只识别了部分条码,抠图也不是很成功!而且不能识别二维码!
    在这里插入图片描述

源码:

# -*- coding: UTF-8 -*-
'''
==============================
test3:找出图片中的条形码或二维码
(ps.仅识别条形码成功)
==============================
'''
import numpy as np
import argparse
import cv2

print("请输入解码图片完整名称:")
code_name = input('>>:').strip()
print("正在识别:")
#image = cv2.imread("test2.jpg")
image = cv2.imread(code_name)
# 灰度
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 使用opencv自带的Sobel算子进行过滤
gradX = cv2.Sobel(gray, ddepth=cv2.cv2.CV_32F, dx=1, dy=0, ksize=-1)
gradY = cv2.Sobel(gray, ddepth=cv2.cv2.CV_32F, dx=0, dy=1, ksize=-1)

# 将过滤得到的X方向像素值减去Y方向的像素值
gradient = cv2.subtract(gradX, gradY)
# 先缩放元素再取绝对值,最后转换格式为8bit型
gradient = cv2.convertScaleAbs(gradient)
# 均值滤波取二值化
blurred = cv2.blur(gradient, (9, 9))
(_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)

# 腐蚀和膨胀的函数
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
closed = cv2.erode(closed, None, iterations=4)
closed = cv2.dilate(closed, None, iterations=4)

# 找到边界findContours函数
(_, cnts, _) = cv2.findContours(closed.copy(),
                                cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 计算出包围目标的最小矩形区域
c = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
rect = cv2.minAreaRect(c)
box = np.int0(cv2.boxPoints(rect))

#======显示=======
cv2.drawContours(image, [box], -1, (0, 255, 0), 3)
cv2.imshow("ScanQRcodeTest", image)
cv2.waitKey(0)

(二)调用解码函数进行解码

  • QRcodetest项目下新建ScanInvedio.py
    在这里插入图片描述
    运行测试:(不支持条形码)

因为我自身电脑摄像头设置,颜色有点问题,请忽略

在这里插入图片描述 在这里插入图片描述

源码:

'''
================================
test4:识别摄像头中的条形码或二维码
(ps.仅识别二维码码成功)
================================
'''
import cv2
import pyzbar.pyzbar as pyzbar

def decodeDisplay(image):
    barcodes = pyzbar.decode(image)
    for barcode in barcodes:
        # 提取二维码的边界框的位置
        # 画出图像中条形码的边界框
        (x, y, w, h) = barcode.rect
        cv2.rectangle(image, (x, y), (x + w, y + h), (225, 225, 225), 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,
                    .5, (225, 225, 225), 2)

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


def detect():
    camera = cv2.VideoCapture(0)

    while True:
        # 读取当前帧
        ret, frame = camera.read()
        # 转为灰度图像
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        im = decodeDisplay(gray)

        cv2.waitKey(5)
        cv2.imshow("camera", im)
        # 如果按键q则跳出本次循环
        if cv2.waitKey(10) & 0xFF == ord('q'):
            break
    camera.release()
    cv2.destroyAllWindows()
    
if __name__ == '__main__':
    detect()

大功告成!

猜你喜欢

转载自blog.csdn.net/cungudafa/article/details/85871871