二维码识别
1.实现目的
如何配置摄像头传感器、捕获图像、识别二维码以及在屏幕上显示结果。
2.实验原理
二维码(如 QR Code)是一种可以编码数字、字母、汉字甚至图片的二维条码,信息密度高、容错能力强。
2.1 定位二维码区域
原理:
二维码有明显的结构特征:
- 三个定位标志(Finder Patterns),位于二维码的三个角;
- 一个对齐标志(Alignment Pattern),用于纠正图像扭曲;
- 静区(Quiet Zone),二维码周围的空白区域。
实现方法:
- 边缘检测 + 轮廓分析:查找典型的同心正方形结构;
- 图形几何关系验证:判断三个定位点的位置是否呈直角三角形;
- 比例分析:定位标志的黑白块比例近似为 1:1:3:1:1。
一旦成功检测到这些特征,就可以推算出二维码的位置、角度、大小。
2.2. 数据解码(Decode)
编码格式(以 QR Code 为例):
- 格式信息:记录纠错等级、掩码信息;
- 版本信息:二维码的尺寸;
- 数据区域:实际存储的数据内容;
- 纠错码:用于修复二维码部分破损的数据。
解码过程:
- 应用掩码反变换;
- 解码字符模式(Numeric, Alphanumeric, Byte, Kanji 等);
- 使用 Reed-Solomon 纠错算法恢复损坏的数据;
- 还原为字符串或二进制数据。
3.代码解析
图像捕获
img = sensor.snapshot()
二维码检测
for code in img.find_qrcodes():
rect = code.rect()
img.draw_rectangle([v for v in rect], color=(255, 0, 0), thickness = 5)
img.draw_string_advanced(rect[0], rect[1], 32, code.payload())
print(code)
img.find_qrcodes()
:检测图像中的所有二维码,并返回一个二维码对象列表。
code.rect()
:获取二维码的位置(矩形框的坐标)。
img.draw_rectangle()
:在二维码区域绘制一个红色矩形框。
img.draw_string_advanced()
:在二维码矩形框旁边绘制二维码的有效载荷(二维码内容)。
print(code)
:打印二维码的信息
显示图像
Display.show_image(img)
将处理后的图像显示到屏幕上。
4.示例代码
'''
本程序遵循GPL V3协议, 请遵循协议
实验平台: DshanPI CanMV
开发板文档站点 : https://eai.100ask.net/
百问网学习平台 : https://www.100ask.net
百问网官方B站 : https://space.bilibili.com/275908810
百问网官方淘宝 : https://100ask.taobao.com
'''
import time, os, gc, sys
from media.sensor import * # 摄像头模块
from media.display import * # 显示屏模块
from media.media import * # 媒体管理模块
# 定义图像检测的宽度和高度
DETECT_WIDTH = 800
DETECT_HEIGHT = 480
sensor = None
try:
# 构造一个默认配置的摄像头对象
sensor = Sensor(width = DETECT_WIDTH, height = DETECT_HEIGHT)
# 重置摄像头
sensor.reset()
# 设置图像水平镜像(如有需要可打开)
# sensor.set_hmirror(False)
# 设置图像垂直翻转(如有需要可打开)
# sensor.set_vflip(False)
# 设置通道0输出图像的分辨率
sensor.set_framesize(width = DETECT_WIDTH, height = DETECT_HEIGHT)
# 设置通道0输出图像的像素格式为 RGB565
sensor.set_pixformat(Sensor.RGB565)
# 使用 HDMI 输出(VGA 分辨率)
# Display.init(Display.LT9611, width = 640, height = 480, to_ide = True)
# 使用 HDMI 输出(1080P 分辨率)
# Display.init(Display.LT9611, width = 1920, height = 1080, to_ide = True)
# 使用 LCD 屏幕作为显示输出
Display.init(Display.ST7701, to_ide = True)
# 使用 IDE 虚拟显示输出(高刷新率)
# Display.init(Display.VIRT, width = DETECT_WIDTH, height = DETECT_HEIGHT, fps = 100)
# 初始化媒体管理器(用于帧缓冲、DMA 等资源管理)
MediaManager.init()
# 启动摄像头采集图像
sensor.run()
# 创建 FPS 计时器
fps = time.clock()
while True:
fps.tick() # 开始新一帧计时
# 检查是否触发退出点(用于热插拔、断电退出等)
os.exitpoint()
# 获取当前帧图像
img = sensor.snapshot()
# 扫描图像中的二维码
for code in img.find_qrcodes():
rect = code.rect() # 获取二维码所在的矩形区域
# 在图像上画出二维码边框,红色,线宽为 5
img.draw_rectangle([v for v in rect], color=(255, 0, 0), thickness = 5)
# 在二维码左上角绘制二维码内容(字符串)
img.draw_string_advanced(rect[0], rect[1], 32, code.payload())
# 打印二维码信息到串口
print(code)
# 将图像结果显示在屏幕上
Display.show_image(img)
# 主动触发垃圾回收,避免内存碎片
gc.collect()
# 打印当前帧率
print(fps.fps())
except KeyboardInterrupt as e:
# 捕获 Ctrl+C 手动终止程序
print(f"user stop")
except BaseException as e:
# 捕获其他异常并打印信息
print(f"Exception '{e}'")
finally:
# 程序退出前释放资源
# 停止摄像头
if isinstance(sensor, Sensor):
sensor.stop()
# 关闭显示器
Display.deinit()
# 设置退出点状态为允许睡眠
os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
# 延时,确保显示器和摄像头完全释放资源
time.sleep_ms(100)
# 释放媒体管理器资源(如帧缓冲池)
MediaManager.deinit()
5.实验结果
点击运行代码,可以在显示屏上看到二维码识别的结果。