环境:Win 10、Spyder4.2.5、Python3.8

在上一篇博客中,主要采用OpenCV库自带的二维码、条形码检测与识别模块,实验结果显示检出的精度很低,这一方面是由于图片是静态的,不能进行缩放,而正常手机二维码和条形码的扫描,手机使用者可以调整摄像头到二维码的距离来提高检测和识别精度。在这节中主要针对采用Pyzar库实现二维码和条形码的检测和识别,并通过摄像头进行实时识别效果显示。

1.安装pyzar库:

pyzbar是python2或python3通过调用 zbar 库中函数实现一维条码和QR码的识别,在Python 2.7和 Python 3.4 to 3.6已做过测试。

安装:

Mac OS X:

brew install zbar

Linux:

sudo apt-get install libzbar0

Windows:

pip install pyzbar
pip install pyzbar[scripts]
安装过程中遇到的问题:
安装 pyzbar和安装其他的库之前都需要先更新pip,然后进行包和库的安装,否则会无法正常安装,如果pip无法正常更新,可以将网络代理服务器
关掉,然后再进行更新。

设置完后,则可正常更新pip。

2.利用摄像头实现条形码和二维码的识别

# -*- coding: utf-8 -*-
"""
Created on Sat Feb 26 14:38:04 2022

@author: Victor
"""

# coding:utf8

import cv2
import pyzbar.pyzbar as pyzbar
import numpy as np


def decodeDisplay(image):
    barcodes = pyzbar.decode(image)
    rects_list = []
    polygon_points_list = []
    QR_info = []

    # 这里循环,因为画面中可能有多个二维码
    for barcode in barcodes:
        # 提取条形码的边界框的位置
        # 画出图像中条形码的边界框
        (x, y, w, h) = barcode.rect
        rects_list.append((x, y, w, h))
        cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
        polygon_points = barcode.polygon
        # print(f"polygon_points: {polygon_points}")  # polygon_points: [Point(x=217, y=174), Point(x=257, y=353), Point(x=433, y=316), Point(x=394, y=140)]
        # print(f"polygon_points: {polygon_points[0]}")  # polygon_points: Point(x=217, y=174)
        point_x, point_y = polygon_points[0]
        # print(f"point_x, point_y: {point_x, point_y}")  # point_x, point_y: (217, 174)

        extract_polygon_points = np.zeros((4, 2), dtype=np.int)
        for idx, points in enumerate(polygon_points):
            point_x, point_y = points  # 默认得到的point_x, point_y是float64类型
            extract_polygon_points[idx] = [point_x, point_y]

        print(extract_polygon_points.shape)  # (4, 2)

        # 不reshape成 (4,1 2)也是可以的
        extract_polygon_points = extract_polygon_points.reshape((-1, 1, 2))
        polygon_points_list.append(extract_polygon_points)

        # 要加上中括号,否则只会绘制四个点
        # cv2.polylines(image, extract_polygon_points, isClosed=True, color=(255, 0, 255), thickness=2)

        # 绘制多边形
        cv2.polylines(image, [extract_polygon_points], isClosed=True, color=(255, 0, 255), thickness=2,
                      lineType=cv2.LINE_AA)

        # 条形码数据为字节对象,所以如果我们想在输出图像上画出来,就需要先将它转换成字符串
        barcodeData = barcode.data.decode("utf-8")
        barcodeType = barcode.type

        # 绘出图像上条形码的数据和条形码类型
        text = "{} ({})".format(barcodeData, barcodeType)
        QR_info.append(text)
        cv2.putText(image, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,
                    .5, (0, 0, 125), 2)

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


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

    while True:
        # 读取当前帧
        ret, frame = cap.read()
        # 转换为灰度图是为了检测到二维码,如果是BGR图很大概率是检测不到二维码
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        im, rects_list, polygon_points_list, QR_info = decodeDisplay(gray)

        # 把检测到二维码的信息再绘制到BGR彩色图像上
        for data in zip(rects_list, polygon_points_list, QR_info):
            print(f"data: {data}")
            x, y, w, h = data[0]
            polygon_points = data[1]
            text = data[2]
            cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
            cv2.polylines(frame, [polygon_points], isClosed=True, color=(255, 0, 255), thickness=2,
                          lineType=cv2.LINE_AA)
            cv2.putText(frame, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,
                        .5, (0, 0, 125), 2)

        # 因为一个是单通道的灰度图,一个是BGR三通道的彩色图,因此不能够拼接在一起显示,这里就用两个窗口显示
        cv2.imshow("camera", im)
        cv2.imshow("frame", frame)

        # 按q键退出画面显示
        k = cv2.waitKey(1)
        if k == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    detect()

实验效果如下图所示,能够实现大部分条码的识别,但也有一些条码未能识别出来:

3.图像的批量读取、灰度化和保存

在进行数据集图像的处理过程(机器学习建模)中,常用会遇到批量读取某个文件夹中的某种或几种格式的图片,然后进行分析处理,最后将处理结果保存到固定文件夹的情况,则下面的代码会经常被用到:

# -*- coding: utf-8 -*-
"""
Created on Fri Feb 10:30 2022
@author: Victor
"""
import cv2
import glob
import numpy as np
save_path = 'C:\\Users\\whd\\Desktop\\test\\'
# 获取固定路径下的所有jpg格式图片
path = glob.glob(r"C:\Users\whd\Desktop\test\ImagesSets\*.jpg")
for i in range(len(path)):
      Original_Image = cv2.imread(path[i])
    # 转换为灰度图像
      Gray_Image = cv2.cvtColor(Original_Image, cv2.COLOR_BGR2GRAY)
      cv2.imwrite(save_path + str(i) + '.jpg', Gray_Image)

4.关于Python的路径问题再探讨

在编程的过程中,经常会遇到因为读取或存储图片的路径格式问题导致运行失败,在第一篇博客中已经遇到了路径中存在中文字符导致图片读取不正常的情况。在调试的过程中发现python的路径问题是比较普遍的,有的时候不是通过简单的再路径前面添加一个字母 r,防止'\'转义,另外对于python,路径中不能以'\'结尾,即使前面加了‘r’也会报错,错误信息如下:

 错误原因:python的字符串不能以'\'结尾,因为在python中, 如果完整的字符串太长的时候,一行写不下想换行,但又要维持它是一个字符串的时候 可以用反斜杠来换行。 

  • 解决方法:
使用双反斜杠save_path =  'C:\\Users\\whd\\Desktop\\test\\'。
还有另外的几种处理方法,详见 python SyntaxError: EOL while scanning string literal