在 CanMV K210 入门和综合项目中,AprilTag 视觉标签识别是一个很适合拆解的实验。它不是只验证摄像头能不能显示画面,而是把摄像头初始化、图像采集、标签检测、结果绘制、LCD 显示和串口输出串成一个完整流程。通过这个案例,可以理解机器视觉项目中"采集图像、分析图像、输出结果"的基本工作方式。
AprilTag 经常被口头称为二维码标签,但它和普通 QR 二维码的用途不同。普通二维码更偏向存储文本、链接或数据内容,AprilTag 更偏向视觉定位、机器人导航、目标标识和相机姿态参考。本实验不会读取普通二维码中的文字内容,而是识别 AprilTag 的标签家族、标签 ID、中心位置、矩形区域和旋转角度。
| 学习目标 | 说明 |
|---|---|
| 理解 AprilTag 识别 | 认识 AprilTag 与普通二维码的区别,理解标签 ID、标签家族和旋转角信息 |
| 掌握摄像头采集流程 | 使用 sensor.reset()、sensor.snapshot() 完成图像初始化与采集 |
| 掌握标签检测接口 | 使用 img.find_apriltags() 检测画面中的 AprilTag 标签 |
| 学会结果可视化 | 在图像上绘制矩形框、中心十字和文本信息,并通过 LCD 显示 |
| 建立视觉项目思路 | 为机器人定位、视觉导航、货架识别和自动对位实验打基础 |
本实验使用 CanMV K210 运行 4.4_April_Tags.py。程序通过摄像头采集图像并调用 AprilTag 检测接口,识别标签 ID、标签家族和旋转角度,同时在画面中绘制红色矩形框、绿色中心十字和标签信息。串口会输出标签家族、标签 ID、旋转角度和当前帧率,便于观察代码结果和硬件现象之间的对应关系。
文章目录
理论基础
AprilTag 是一种视觉基准标签。摄像头看到标签后,程序可以从图像中检测出标签边界、中心位置、标签 ID 和旋转信息。对于机器人、移动平台、自动对位设备和教学视觉项目来说,这类标签的价值不在于存储大量内容,而在于提供一个稳定、容易识别的视觉参照物。
本实验代码使用 img.find_apriltags() 完成标签检测。程序会先配置可识别的标签家族,例如 TAG16H5、TAG25H7、TAG36H11 和 ARTOOLKIT,然后在每一帧图像中查找符合这些家族规则的标签。检测到标签后,程序可以读取 tag.family()、tag.id()、tag.rect()、tag.cx()、tag.cy() 和 tag.rotation() 等信息。
需要注意的是,本实验读取的是 AprilTag 的基础识别信息,包括标签家族、标签 ID、中心坐标、矩形区域和画面内旋转角度。严格意义上的三维位姿估计还需要相机标定参数、标签实际尺寸和空间坐标换算。本实验更适合作为 AprilTag 识别入门,用于理解标签检测和画面标记流程。
摄像头模块
采集实时画面
sensor 初始化
RGB565 / QQVGA / 翻转设置
snapshot 获取图像帧
find_apriltags
检测 AprilTag 标签
读取标签信息
家族 / ID / 中心 / 旋转角
图像标记
矩形框 / 中心十字 / 文本
LCD 显示识别结果
串口输出
标签信息与 FPS
标签家族配置
TAG16H5 / TAG36H11 / ARTOOLKIT
环境条件
光照 / 距离 / 角度 / 清晰度
这条流程可以从视觉处理角度理解。摄像头负责采集画面,sensor 模块负责初始化和取图,image 模块负责 AprilTag 检测,程序再把检测结果绘制到图像上,最后通过 LCD 和串口输出。影响识别效果的因素主要包括标签是否清晰、光照是否充足、摄像头是否对焦、标签距离是否合适,以及代码中启用的标签家族是否和实际标签一致。
标签家族是 AprilTag 实验中的重要概念。不同家族的标签内部格子数量和编码规则不同,识别距离、误识别概率和可用 ID 数量也不同。代码中同时启用了多个家族,便于实验时识别不同类型的标签;如果后续项目只使用一种标签家族,可以只保留对应家族,减少不必要的检测负担。
硬件设施
本实验围绕 CanMV K210、摄像头模块、LCD 显示屏和 AprilTag 标签展开。代码没有使用 GPIO、蜂鸣器、电机、传感器或 I2C 外设,因此硬件重点不在接线排查,而在摄像头是否正常采集、LCD 是否正常显示、AprilTag 标签是否清晰,以及标签家族是否和程序配置一致。
实际发布时,可以在这里放入 CanMV K210、摄像头和 LCD 的实物连接图。检查时重点关注摄像头排线方向、LCD 屏幕连接状态和开发板供电情况。
| 硬件 / 软件 | 作用 | 说明 |
|---|---|---|
| CanMV K210 开发板 | 实验运行平台 | 执行 MicroPython 程序,完成图像采集、标签检测和显示输出 |
| 摄像头模块 | 图像采集 | 通过 sensor.snapshot() 获取实时画面 |
| LCD 显示屏 | 结果显示 | 显示摄像头画面、矩形框、中心点和标签信息 |
| AprilTag 标签 | 识别对象 | 用于提供标签家族、ID、位置和旋转角等视觉信息 |
sensor 模块 |
摄像头控制 | 完成摄像头初始化、像素格式设置、分辨率设置和图像采集 |
image 模块 |
图像处理 | 提供 find_apriltags()、绘制矩形、绘制十字和文本显示能力 |
lcd 模块 |
屏幕显示 | 初始化 LCD,并把处理后的图像显示到屏幕上 |
time 模块 |
帧率统计 | 通过 time.clock() 统计 FPS |
math 模块 |
角度换算 | 将弧度制旋转角转换为角度制输出 |
本实验不需要额外接传感器线,也不需要手动映射 GPIO。摄像头和 LCD 属于视觉实验的核心硬件,如果画面无法显示,应优先检查摄像头排线、LCD 初始化、固件支持和供电状态,而不是去排查普通 GPIO 引脚。
| 接口 / 资源 | 代码对象 | 对应硬件与说明 |
|---|---|---|
| 摄像头接口 | sensor.reset() |
初始化摄像头模块 |
| 图像采集 | sensor.snapshot() |
获取实时图像帧 |
| 图像格式 | sensor.set_pixformat(sensor.RGB565) |
设置图像为 RGB565 格式,便于 LCD 显示彩色画面 |
| 图像分辨率 | sensor.set_framesize(sensor.QQVGA) |
使用 QQVGA 分辨率,降低内存压力和识别负担 |
| 图像翻转 | sensor.set_vflip(True) |
根据摄像头安装方向进行垂直翻转 |
| LCD 接口 | lcd.init() / lcd.display(img) |
初始化屏幕并显示处理后的图像 |
| AprilTag 标签 | img.find_apriltags() |
在图像中查找标签 |
AprilTag 标签可以打印在纸上,也可以显示在屏幕上进行测试。标签需要尽量保持清晰、平整,并放在摄像头能够完整看到的位置。标签太小、距离太远、画面过暗或角度过大,都可能导致识别失败。
实验运行时,LCD 上应能看到摄像头画面。当画面中出现 AprilTag 标签时,程序会在标签区域绘制红色矩形框,在标签中心绘制绿色十字,并在左上角显示标签家族、ID 和旋转角信息。串口终端会同步打印识别结果和帧率。
| 实验现象 | 正常表现 | 异常提示 |
|---|---|---|
| 程序启动 | LCD 显示摄像头实时画面 | 黑屏时检查 LCD 初始化、摄像头排线和开发板供电 |
| 标签进入画面 | 标签周围出现红色矩形框 | 没有框选时检查标签家族、距离、光照和清晰度 |
| 标签中心识别 | 标签中心出现绿色十字 | 中心偏移明显时检查摄像头角度和标签是否完整入画 |
| 串口输出 | 输出标签家族、ID、旋转角和 FPS | 串口无输出时确认程序是否进入主循环 |
| 旋转标签 | 串口中的 rotation 数值发生变化 | 数值不稳定时检查画面抖动和标签清晰度 |
| FPS 输出 | 串口持续打印帧率 | 帧率过低时减少启用的标签家族或降低无关绘制输出 |
软件代码
本实验的软件部分以 4.4_April_Tags.py 为核心。程序导入 sensor、image、time、math 和 lcd 模块,完成 LCD 初始化、摄像头初始化、AprilTag 家族配置、标签检测、图像标记、LCD 显示和串口输出。
| 软件环境 | 作用 | 检查重点 |
|---|---|---|
| CanMV IDE | 编辑、运行和调试 K210 程序 | 能识别开发板串口,并能运行基础摄像头示例 |
| CanMV 固件 | 提供 sensor、image、lcd 等模块 |
固件环境需要支持 AprilTag 检测接口 |
| 摄像头驱动环境 | 图像采集基础 | sensor.reset() 不应报错 |
| LCD 显示环境 | 显示识别结果 | lcd.init() 和 lcd.display(img) 能正常工作 |
| 串口终端 | 查看标签信息和 FPS | 能看到 Tag Family、Tag ID 和帧率输出 |
| AprilTag 标签 | 识别目标 | 标签家族需要和代码启用的家族一致 |
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ----湖南创乐博智能科技有限公司----
# 文件名:4.4_April_Tags.py
# 版本:V2.0
# author: zhulin
# 说明:CanMv K210 April-Tags二维码识别实验
#####################################################
import sensor, image, time, math
import lcd
#lcd显示屏初始化
lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA) # 如果分辨率更大,我们的内存会耗尽...
sensor.skip_frames(time = 2000)
sensor.set_vflip(True)
clock = time.clock()
# 注意!与find_qrcodes不同,find_apriltags方法不需要对图像进行镜头校正
# apriltag代码最多支持可以同时处理6种tag家族。
# 返回的tag标记对象,将有其tag标记家族及其在tag标记家族内的id。
tag_families = 0
tag_families |= image.TAG16H5 # 注释掉,禁用这个家族
tag_families |= image.TAG25H7 # 注释掉,禁用这个家族
tag_families |= image.TAG25H9 # 注释掉,禁用这个家族
tag_families |= image.TAG36H10 # 注释掉,禁用这个家族
tag_families |= image.TAG36H11 # 注释掉以禁用这个家族(默认家族)
tag_families |= image.ARTOOLKIT # 注释掉,禁用这个家族
#标签系列有什么区别? 那么,例如,TAG16H5家族实际上是一个4x4的方形标签。
#所以,这意味着可以看到比6x6的TAG36H11标签更长的距离。
#然而,较低的H值(H5对H11),意味着4x4标签的假阳性率远高于6x6标签。
#所以,除非你有理由使用其他标签系列,否则使用默认族TAG36H11。
def family_name(tag):
if(tag.family() == image.TAG16H5):
return "TAG16H5"
if(tag.family() == image.TAG25H7):
return "TAG25H7"
if(tag.family() == image.TAG25H9):
return "TAG25H9"
if(tag.family() == image.TAG36H10):
return "TAG36H10"
if(tag.family() == image.TAG36H11):
return "TAG36H11"
if(tag.family() == image.ARTOOLKIT):
return "ARTOOLKIT"
while(True):
clock.tick()
img = sensor.snapshot()
for tag in img.find_apriltags(families=tag_families): # 如果没有给出家族,默认TAG36H11。
img.draw_rectangle(tag.rect(), color = (255, 0, 0))
img.draw_cross(tag.cx(), tag.cy(), color = (0, 255, 0))
print_args = (family_name(tag), tag.id(), (180 * tag.rotation()) / math.pi)
img.draw_string(2,2, str(print_args), color=(0,128,0), scale=1)
print("Tag Family %s, Tag ID %d, rotation %f (degrees)" % print_args)
lcd.display(img) # 在LCD显示屏上进行显示
print(clock.fps()) # 打印出帧率
程序可以分成四个层级。初始化层负责启动 LCD 和摄像头,并设置图像格式、分辨率和翻转方向;配置层负责启用 AprilTag 家族;识别层负责在每一帧图像中查找标签;输出层负责在图像上绘制标记,并通过 LCD 和串口显示识别结果。
tag_families 是本实验的重要配置。代码中把多个标签家族通过按位或方式组合在一起,表示检测时允许识别这些家族的标签。启用的家族越多,适配范围越广,但检测负担也会增加。实际项目如果只使用 TAG36H11,可以只保留这一种家族配置,让识别流程更集中。
| 函数 / 语句 | 功能 | 对应现象 |
|---|---|---|
lcd.init() |
初始化 LCD 显示屏 | 屏幕准备显示摄像头画面 |
sensor.reset() |
初始化摄像头 | 摄像头开始进入采集准备状态 |
sensor.set_pixformat(sensor.RGB565) |
设置彩色图像格式 | LCD 能显示彩色摄像头画面 |
sensor.set_framesize(sensor.QQVGA) |
设置 QQVGA 分辨率 | 降低内存压力,提高运行稳定性 |
sensor.set_vflip(True) |
垂直翻转画面 | 修正摄像头安装方向造成的上下颠倒 |
img.find_apriltags() |
检测 AprilTag 标签 | 画面中出现标签时返回标签对象 |
tag.id() |
读取标签 ID | 串口输出当前识别到的标签编号 |
tag.cx() / tag.cy() |
读取标签中心坐标 | 绿色十字绘制在标签中心 |
tag.rect() |
读取标签矩形区域 | 红色矩形框住标签位置 |
tag.rotation() |
读取标签旋转角 | 串口输出角度制旋转信息 |
lcd.display(img) |
显示处理后的图像 | LCD 显示框选和文字标记结果 |
clock.fps() |
输出帧率 | 串口持续显示当前处理速度 |
实际运行效果可以在这里放入 LCD 识别截图。画面中应能看到被框选的 AprilTag 标签、中心十字和左上角的标签信息。串口终端中则会显示标签家族、标签 ID、旋转角和 FPS。
扩展应用
AprilTag 识别实验的调试重点集中在摄像头画面、标签家族、光照条件、标签清晰度和运行帧率。出现问题时,应先确认摄像头能正常显示画面,再确认标签是否完整进入画面,最后再检查标签家族配置和检测参数。
| 问题现象 | 可能原因 | 处理思路 |
|---|---|---|
| LCD 没有画面 | 摄像头排线松动、LCD 初始化异常、程序未正常运行 | 检查摄像头和 LCD 连接,先运行基础摄像头显示程序 |
| 画面上下颠倒 | 摄像头安装方向与代码设置不一致 | 调整 sensor.set_vflip(True),必要时加入或修改水平翻转设置 |
| 标签无法识别 | 标签家族不匹配、标签太小、距离过远、画面模糊 | 确认标签家族与代码一致,拉近距离,保证标签清晰完整 |
| 识别结果频繁丢失 | 光照不足、摄像头抖动、标签角度过大 | 增强光照,固定摄像头和标签,减少大角度倾斜 |
| 标签 ID 不符合预期 | 使用了不同家族或不同编号的标签 | 更换正确标签,或查看串口输出中的 Tag Family 和 Tag ID |
| FPS 过低 | 启用标签家族过多、串口打印过多、绘制内容较多 | 减少检测家族,降低打印频率,保持 QQVGA 分辨率 |
| 左上角文字覆盖画面 | 标签信息始终绘制在固定位置 | 后续可改为绘制到标签附近,或只保留串口输出 |
| 串口只有 FPS,没有标签信息 | 程序运行正常,但当前画面没有识别到标签 | 把标签放入画面中央,调整距离、光照和标签方向 |
AprilTag 的扩展价值主要体现在定位、导航和标识识别。当前代码已经能够获得标签家族、ID、中心坐标和旋转角,后续可以把这些信息转换成机器人动作、云台调整、设备对位或任务触发条件。比如标签中心偏左时控制云台左转,标签中心偏右时控制云台右转;识别到指定 ID 后执行对应任务;检测到标签旋转角变化后判断目标姿态。
| 应用场景 | 实现思路 | 可扩展能力 |
|---|---|---|
| 机器人定位 | 在场地中放置 AprilTag,机器人识别标签 ID 和位置 | 可扩展为室内定位、路径节点识别和任务点确认 |
| 视觉导航 | 根据标签中心坐标判断目标在画面中的偏移方向 | 可联动小车、电机或舵机实现自动对准 |
| 货架标签识别 | 每个货架位置放置不同 ID 的标签 | 可用于仓储教学、货架编号识别和物料定位 |
| 自动对位 | 根据标签中心位置和旋转角调整设备姿态 | 可扩展为机械臂抓取前定位或充电座对位 |
| 增强现实标记 | 使用标签作为画面叠加内容的参考点 | 可扩展为图像叠加、教学演示或交互标记 |
| 课程识别演示 | 使用不同标签展示 ID、坐标和旋转角变化 | 适合讲解机器视觉、坐标系和目标检测流程 |
| 任务触发 | 不同标签 ID 对应不同控制逻辑 | 可扩展为识别 ID 后启动电机、蜂鸣器或屏幕提示 |
从工程角度看,建议保持"采集、识别、判断、显示、执行"的分层。摄像头采集负责提供图像,AprilTag 检测负责提供标签信息,状态判断负责决定是否触发动作,显示和串口负责调试反馈。后续把串口输出替换成小车控制、云台控制、蜂鸣器提示或网络上传时,不需要重写摄像头和识别部分,只需要在识别结果之后增加业务逻辑。
总结
本实验通过 CanMV K210 完成了 AprilTag 视觉标签识别,核心内容包括 LCD 初始化、摄像头采集、标签家族配置、AprilTag 检测、标签 ID 读取、中心坐标读取、旋转角换算、图像标记和串口帧率输出。它展示了 K210 视觉实验中从图像采集到识别结果显示的一条完整链路。
AprilTag 实验适合作为机器视觉课程中的基础识别案例。它比单纯显示摄像头画面更进一步,因为程序不仅能看到图像,还能从图像中提取稳定的标签信息。后续课程可以继续扩展机器人定位、视觉导航、自动对位、货架标签识别、云台跟踪和任务触发等方向。只要理解摄像头采集、标签检测和结果输出之间的关系,更多 CanMV K210 视觉项目都可以沿着同一套思路继续搭建。