【CanMV K210】视觉识别 AprilTag 标签检测与位姿信息

在 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() 完成标签检测。程序会先配置可识别的标签家族,例如 TAG16H5TAG25H7TAG36H11ARTOOLKIT,然后在每一帧图像中查找符合这些家族规则的标签。检测到标签后,程序可以读取 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 为核心。程序导入 sensorimagetimemathlcd 模块,完成 LCD 初始化、摄像头初始化、AprilTag 家族配置、标签检测、图像标记、LCD 显示和串口输出。

软件环境 作用 检查重点
CanMV IDE 编辑、运行和调试 K210 程序 能识别开发板串口,并能运行基础摄像头示例
CanMV 固件 提供 sensorimagelcd 等模块 固件环境需要支持 AprilTag 检测接口
摄像头驱动环境 图像采集基础 sensor.reset() 不应报错
LCD 显示环境 显示识别结果 lcd.init()lcd.display(img) 能正常工作
串口终端 查看标签信息和 FPS 能看到 Tag FamilyTag 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 FamilyTag ID
FPS 过低 启用标签家族过多、串口打印过多、绘制内容较多 减少检测家族,降低打印频率,保持 QQVGA 分辨率
左上角文字覆盖画面 标签信息始终绘制在固定位置 后续可改为绘制到标签附近,或只保留串口输出
串口只有 FPS,没有标签信息 程序运行正常,但当前画面没有识别到标签 把标签放入画面中央,调整距离、光照和标签方向

AprilTag 的扩展价值主要体现在定位、导航和标识识别。当前代码已经能够获得标签家族、ID、中心坐标和旋转角,后续可以把这些信息转换成机器人动作、云台调整、设备对位或任务触发条件。比如标签中心偏左时控制云台左转,标签中心偏右时控制云台右转;识别到指定 ID 后执行对应任务;检测到标签旋转角变化后判断目标姿态。

应用场景 实现思路 可扩展能力
机器人定位 在场地中放置 AprilTag,机器人识别标签 ID 和位置 可扩展为室内定位、路径节点识别和任务点确认
视觉导航 根据标签中心坐标判断目标在画面中的偏移方向 可联动小车、电机或舵机实现自动对准
货架标签识别 每个货架位置放置不同 ID 的标签 可用于仓储教学、货架编号识别和物料定位
自动对位 根据标签中心位置和旋转角调整设备姿态 可扩展为机械臂抓取前定位或充电座对位
增强现实标记 使用标签作为画面叠加内容的参考点 可扩展为图像叠加、教学演示或交互标记
课程识别演示 使用不同标签展示 ID、坐标和旋转角变化 适合讲解机器视觉、坐标系和目标检测流程
任务触发 不同标签 ID 对应不同控制逻辑 可扩展为识别 ID 后启动电机、蜂鸣器或屏幕提示

从工程角度看,建议保持"采集、识别、判断、显示、执行"的分层。摄像头采集负责提供图像,AprilTag 检测负责提供标签信息,状态判断负责决定是否触发动作,显示和串口负责调试反馈。后续把串口输出替换成小车控制、云台控制、蜂鸣器提示或网络上传时,不需要重写摄像头和识别部分,只需要在识别结果之后增加业务逻辑。

总结

本实验通过 CanMV K210 完成了 AprilTag 视觉标签识别,核心内容包括 LCD 初始化、摄像头采集、标签家族配置、AprilTag 检测、标签 ID 读取、中心坐标读取、旋转角换算、图像标记和串口帧率输出。它展示了 K210 视觉实验中从图像采集到识别结果显示的一条完整链路。

AprilTag 实验适合作为机器视觉课程中的基础识别案例。它比单纯显示摄像头画面更进一步,因为程序不仅能看到图像,还能从图像中提取稳定的标签信息。后续课程可以继续扩展机器人定位、视觉导航、自动对位、货架标签识别、云台跟踪和任务触发等方向。只要理解摄像头采集、标签检测和结果输出之间的关系,更多 CanMV K210 视觉项目都可以沿着同一套思路继续搭建。

相关推荐
AI精钢1 小时前
修复 AI Gateway 图片 MIME 类型错误:用魔数检测替代扩展名猜测
网络·人工智能·python·gateway·aigc
菩提树下的凡夫1 小时前
新一代人工智能---AI智能体
人工智能
云烟成雨TD2 小时前
Spring AI Alibaba 1.x 系列【49】状态图运行时引擎:CompiledGraph 源码解析
java·人工智能·spring
i嘻嘻8322 小时前
餐厅送餐机器人行业研究报告
人工智能
城事漫游Molly2 小时前
研究设计核心 Toolkit:从“知道方法”到“真正会设计”
大数据·人工智能·算法·ai写作·论文笔记
love在水一方2 小时前
【导读】基于层次化多模态场景图的快慢推理视觉语言导航
人工智能
一只幸运猫.2 小时前
核心概念层——深入理解 Agent 是什么
大数据·数据库·人工智能
大囚长3 小时前
意识与物质的一体两面
人工智能
●VON3 小时前
小米突然发短信:送你100万亿Token!有人已收到,有人还没?手把手教你白嫖
数据库·人工智能·skills