如何利用 opencv 简单解释二维码的组成

起因

今天 rockets 问我, 是否能够将二维码里面的色块用 0 和 1 表示出来.

分析

我脑海里分析了一下,不知道是不是可以用 opencv 实现,就打开电脑尝试了一下,似乎是可以的.
思路, 首先通过 qrcode 生成一个图片,然后保存一下,通过opencv 导入图片,然后再判断 10x10 大小的块中是否全是白色,如果是白色,就写一个 1
,如果是黑色,就写个 0. 然后遍历整个图片的 shape.

Talk is cheap, show me the code


import qrcode
import cv2
import numpy as np

url = 'https://www.dfrobot.com/product-2480.html'
file_name = 'qrcode.png'

def generate_image(url):
    qr = qrcode.QRCode()
    qr.add_data(url)
    qr.make(fit=False)
    img = qr.make_image(fill_color="black", back_color="white")
    img.save(file_name)

generate_image(url)
img1 = cv2.imread(file_name)
scale_percent = 80
width = int(img1.shape[1] * scale_percent / 100)
height = int(img1.shape[0] * scale_percent / 100)
dim = (width, height)

resized_img = cv2.resize(img1, dim, interpolation=cv2.INTER_AREA)
# gray_img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
for i in range(0, int(resized_img.shape[0]), 10):
    for j in range(0, int(resized_img.shape[1]), 10):
        if np.mean(resized_img[i:i+10, j:j+10]) == 255:
            cv2.putText(resized_img, '0', (i, j), cv2.FONT_HERSHEY_SIMPLEX, .2, (255, 0, 0))
        else:
            cv2.putText(resized_img, '1', (i, j), cv2.FONT_HERSHEY_SIMPLEX, .2, (255, 0, 0))

cv2.imshow('resized_img', resized_img)
cv2.waitKey(0)

执行效果:

重点

np.mean(图片数组) == 255的判断部分,可以判断图片是不是白色.

重构了一下,优化后:

import qrcode
import cv2
import numpy as np

# 定义生成 qrcode 的 url 链接和生成的文件名
url = 'https://www.dfrobot.com/product-2480.html'
file_name = 'qrcode.png'

def generate_image(url):
    """"
    生成二维码并保存
    """
    qr = qrcode.QRCode()
    qr.add_data(url)
    qr.make(fit=False)
    img = qr.make_image(fill_color="black", back_color="white")
    img.save(file_name)

def process_image(filename):
    """
    :param filename: 放入生成的二维码
    :return: 显示图
    """
    img1 = cv2.imread(file_name)
    scale_percent = 80
    width = int(img1.shape[1] * scale_percent / 100)
    height = int(img1.shape[0] * scale_percent / 100)
    dim = (width, height)
    resized_img = cv2.resize(img1, dim, interpolation=cv2.INTER_AREA)
    for i in range(0, int(resized_img.shape[0]), 10):
        for j in range(0, int(resized_img.shape[1]), 10):
            if np.mean(resized_img[i:i+5, j:j+5]) == 255:
                cv2.putText(resized_img, '0', (i+5, j+5), cv2.FONT_HERSHEY_SIMPLEX, .2, (255, 0, 0))
            else:
                cv2.putText(resized_img, '1', (i+5, j+5), cv2.FONT_HERSHEY_SIMPLEX, .2, (255, 0, 0))

    cv2.imshow('resized_img', resized_img)
    cv2.waitKey(0)

if __name__ == "__main__":
    generate_image(url)
    process_image(file_name)

优化后结果:

感觉还是不太对.

继续优化试试看.

import qrcode
import cv2
import numpy as np

# 定义生成 qrcode 的 url 链接和生成的文件名
url = 'https://www.dfrobot.com/product-2480.html'
file_name = 'qrcode.png'

def generate_image(url):
    """"
    生成二维码并保存
    """
    qr = qrcode.QRCode()
    qr.add_data(url)
    qr.make(fit=False)
    img = qr.make_image(fill_color="black", back_color="white")
    img.save(file_name)

def process_image(filename):
    """
    :param filename: 放入生成的二维码
    :return: 显示图
    """
    img1 = cv2.imread(file_name)
    scale_percent = 200
    width = int(img1.shape[1] * scale_percent / 100)
    height = int(img1.shape[0] * scale_percent / 100)
    dim = (width, height)
    resized_img = cv2.resize(img1, dim, interpolation=cv2.INTER_AREA)
    resized_img = cv2.cvtColor(resized_img, cv2.COLOR_BGR2GRAY)
    for i in range(0, int(resized_img.shape[0]), 10):
        for j in range(0, int(resized_img.shape[1]), 10):
            if np.mean(resized_img[i:i+3, j:j+3]) == 255:
                cv2.putText(resized_img, '1', (i + 5, j + 5), cv2.FONT_HERSHEY_SIMPLEX, .2, (0, 0, 255))
            else:
                cv2.putText(resized_img, '0', (i + 5, j + 5), cv2.FONT_HERSHEY_SIMPLEX, .2, (255, 0, 0))

    cv2.imshow('img', resized_img)
    cv2.waitKey(0)

if __name__ == "__main__":
    generate_image(url)
    process_image(file_name)

输出结果: