树莓派4b + python3 + pyzbar + opencv + 摄像头 扫描识别二维码(寻找最大的二维码)

前言

最近需要做一个扫码乘车的功能,于是使用树莓派的摄像头扫描二维码来做一个demo 。 网上有部分人用的是zbar这个库,但是我安装后,发现并不能在Python3上使用,这就有点不太好了。经过我的多番寻找,发现有个叫pyzbar的库,可以结合opencv,可以做一个视频动态二维码扫描。

参考博客地址:

python3 + opencv +pyzbar 摄像头检测二维码并获取二维码内容_zx66zx的博客-CSDN博客(这个博主的代码可以直接用)

本文内容:

1.实现树莓派的二维码扫描

2.添加了如何选取最大的二维码功能


1.首先安装opencv和pyzbar

opencv的安装,这里就不再赘述,没有在树莓派上安装opencv的,可以参考我的这篇博客,其中引用了另一个博主的安装教程:树莓派4B安装OpenCV过程(转载)_Solitary_Han的博客-CSDN博客

pyzbar的安装,直接树莓派终端上使用如下命令即可

pip3 install pyzbar

2.代码及注释 

我使用的是树莓派的csi摄像头,而不是usb摄像头,具体usb摄像头或者树莓派csi摄像头一开始怎么调试,怎么获取视频源,可以参考这篇文章树莓派OpenCV系列教程2:摄像头的基本使用 - 树莓派OpenCV教程 微雪课堂

 代码功能如下:

在循环内,每隔0.5秒,获取一帧图像,然后调用pyzbar,识别二维码,然后把二维码信息打印在图像上,并且将图像显示出来

import time
import cv2
import numpy as np
# import zbar
import pyzbar.pyzbar as pyzbar

# main函数
if __name__ == '__main__':
    # openCV 字体
    font = cv2.FONT_HERSHEY_SIMPLEX 
    #定义图像源
    cap = cv2.VideoCapture(0)  # 0: use CSI camera,1:use USB camera
    cap.set(3,480) # set Width
    cap.set(4,360) # set Height
    if(not cap.isOpened()):
        print("[camera.py:cam]:can't open this camera")
    
    while(True):
        # 读入图片
        ret, img = cap.read() 
        # 转灰度
        img_ROI_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        # 解码 返回了识别到的多个二维码对象
        barcodes = pyzbar.decode(img_ROI_gray) 

        # 对于每个识别到的二维码区域
        for barcode in barcodes:

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

            # 打印字符在图片上
            cv2.putText(img, text , (20,100),font,1,(0,255,0),4) 
            # 向终端打印条形码数据和条形码类型
            print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData))

        # 显示
        #cv2.imshow('img_ROI', img_ROI_gray)
        cv2.imshow('image', img)
        if (cv2.waitKey(1)) == ord('q'):
            break
        # 进程停止0.5秒,为了降低图像识别的帧率,提升性能
        time.sleep(0.5)
    # 释放资源
    cap.release()
    cv2.destroyAllWindows() 

3.效果

效果图如下:pyzbar可以解析中文,比如我命令行窗口就输出了中文,但是opencv往图像上写字好像不支持中文

树莓派4b + python3 + pyzbar + opencv + 摄像头 扫描识别二维码(寻找最大的二维码)_第1张图片

性能分析:

不知道为什么,奇卡无比。我用opencv做人脸识别都要比这个视频延迟低。具体原因我后续再找找吧。


4.识别最大的二维码

我的实现思路非常简单,无非是先扫描一遍,获取解析的二维码数据,然后再遍历每个二维码数据,寻找面积最大的二维码

解析图像中的二维码数据的函数pyzbar.decode(img)方法的返回值是一个装着识别对象的列表,我们打印出来看,如下图:

该图中,有两个识别到的二维码对象,其中对象的一个重要参数就是rect,他标识这二维码在图像中的像素位置(左上角坐标),和二维码区域的宽和高。我就是利用这个宽和高,计算得出最大的二维码。

改进后的代码如下:

import time
import cv2
import numpy as np
# import zbar
import pyzbar.pyzbar as pyzbar


if __name__ == '__main__':

    font = cv2.FONT_HERSHEY_SIMPLEX # openCV 字体

    cap = cv2.VideoCapture(0)  # 0: use CSI camera,1:use USB camera
    cap.set(3,480) # set Width
    cap.set(4,360) # set Height
    if(not cap.isOpened()):
        print("[camera.py:cam]:can't open this camera")
    
    while(True):
        # 读入图片
        ret, img = cap.read() 
        # 转灰度
        img_ROI_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 解码
        barcodes = pyzbar.decode(img_ROI_gray) # 返回识别到的多个二维码对象的列表

        area = 0 # 面积
        max_barcode = None # 最大的二维码
        # 选出面积最大的二维码
        for barcode in barcodes:
            (x,y,w,h) = barcode.rect  # 坐标格式:[横坐标,纵坐标,长度,宽度]  单位:像素
            if (area <= w*h):
                area = w*h
                max_barcode = barcode
        # 处理最大的二维码信息
        if (max_barcode != None):
            # 条形码数据为字节对象,所以如果我们想在输出图像上
            # 画出来,就需要先将它转换成字符串
            barcodeData = max_barcode.data.decode("utf-8")
            barcodeType = max_barcode.type
            text = "{} ({})".format(barcodeData, barcodeType)
            # 获取二维码坐标
            (x,y,w,h) = max_barcode.rect  # 坐标格式:[横坐标,纵坐标,长度,宽度]  单位:像素
            print("location: ", max_barcode.rect)
            cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
            # 打印字符在图片上
            cv2.putText(img, text , (20,100),font,1,(0,255,0),4) 
            # 向终端打印条形码数据和条形码类型
            print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData))

        # 显示
        cv2.imshow('image', img)
        if (cv2.waitKey(1)) == ord('q'):
            break
        time.sleep(1) # 隔一秒,读一次图片
    # 释放资源
    cap.release()
    cv2.destroyAllWindows() 

有任何疑问可以在评论区提出哦,点个赞再走呗(* ̄︶ ̄)

你可能感兴趣的:(树莓派,图像识别)