rm校赛2025
赛规回顾
主办方提供一个usb摄像头、一张视觉识别标签。选手需要将摄像头连接电脑,捕捉视觉标签并加以识别。识别结果决定了同队的机器人往哪边的(左/右)核心区发送弹丸。
视觉标签
视觉识别标签主要有以下几个部分构成:定位方块、指示方块、指向三角形。其中指向三角形与指示方块颜色一致代码这一标签指示的方向是正确的,反之为错误的。 视觉标识尺寸为 150*150,材质为 A4 纸彩印,视觉识别标签的具体图形如下:
右方向正确标签:

左方向正确标签:

右方向错误标签:

左方向错误标签:

Tips: 若参赛双方均不参加视觉侦查挑战,则跳过该阶段,直接进入对抗阶段。
视觉计算平台获取到标识信息后,对其进行处理,若为错误标识,则错误标识 所示方向的另一方为正确标识;若为正确标识,则标识所示方向即为正确方向。
视觉侦查挑战的成功与否由黄色弹丸在该阶段结束后的位置正确与否进行判断,以下例举几个情景:
a. 抽中左方错误标识,机器人向右方核心区投射弹丸,并且弹丸成功进入对 方右侧核心区,判定为挑战成功;
b. 抽中右方正确标识,机器人向右方核心区投射弹丸,但机器人未投射或投 射弹丸未进入对方右侧核心区,则判定为挑战失败。
**简单来说,如果中间的方块与三角形同色,则方向为三角形指向;异色,则为三角形指向的反向。**不管标签正确与否,最终都需要给下位机发送一个方向/ 角度数据。
USB摄像头
识别思路
- 识别三个定位块(如必要按左上、右上、右下的顺序做透视变换)
- 对摄像机拍摄到的整个画面roi处理,聚焦于我们感兴趣的视觉标签。
- 根据某些算法依次找到三个定位块,并计算其宽高、中心点、角度误差等数据。
- 捏住三个中心点,做透视变换,把(潜在可能倒着、斜着放的)图片回正,并再次roi,即可聚焦于标签中央区域。
- 对中间的指向块、三角形,比较它们的平均hsv值,若相差较大即可判为异色;否则同色。
- 根据指向三角形的三个顶点和直角方向判断最终指向。
实操记录
一开始觉得这跟识别二维码蛮像的,因为都有三个定位方块。于是试图找现成识别二维码的源码。结果发现在opencv里已经被封装成一个类了
QRCodeDetector
,源码太长太臭,看不懂。看的同济TJ-SuperPower战队 视觉培训(BV1dGHZeiEi2)快速认识了一下ubuntu、cmake和opencv,主要是opencv。了解了识别装甲板的最简化流程:读入 > bgr转灰度 > threshold二值化 > findContours找轮廓点 > minAreaRect轮廓点最小外接矩形 > 识别出两个灯条 > 中间的白色数字交给深度学习解决。
主播第一步先是识别了静态的视觉标签。
此时判断异色的逻辑还是:分别用红色、蓝色的两个mask掩码原图,这样就有了两张红蓝掩码图,如果这两张图上各存在一个轮廓,判异色;如果只有一张有轮廓,另一张没有,判同色。但在实际的摄像头下,这种方法行不通,一是红、蓝色的hue范围具体是多少无法得知;二是用“掩码图上有无轮廓”作为依据实在简陋。
第一版没有用到
minAreaRect
函数勾画外接矩形,而是全程使用approxPolyDP
拟合形状。不知道两者孰优孰劣第一版没有意识到错误的标签其实是指向反向的,因此遇到错误标签会直接输出“Incorrect image”。
代码在项目的
main2.cpp
中。如果要编译,可将CMakeLists.txt
中
1
add_executable(main main.cpp ...
这一行的
main.cpp
改成main2.cpp
。自从主播到了场地,形势便又发生了变化。面临的困难有:a. 需要熟悉usb摄像头 b. 实际标签上安装了灯管,但捕获的图像不经过处理根本亮的看不清 c. 拍摄的图像远不及原图清晰 d. 需要熟悉串口通信发送端的任务
对于usb摄像头,以下是一些常用操作记录(虚拟机版本 vmware ubuntu22.04.5):
列出本机连接的摄像头设备(一般本机内置摄像头是/dev/video0,但奇怪 主播的usb摄像头反而是这个)
1
ls /dev/video*
使用cheese摄像头软件捕获(需事先安装包
sudo apt install cheese
)1
cheese
使用ffplay捕获(需事先安装包
sudo apt install ffmpeg
)1
ffplay /dev/videoX
使用 guvcview捕获(需事先安装包
sudo apt install guvcview
)1
guvcview
使用 v4l-utils查看视频参数等(需事先安装包
sudo apt install v4l-utils
)1
2
3
4
5v4l2-ctl --list-devices # 列出所有摄像头设备
v4l2-ctl --list-formats-ext # 查看摄像头设备支持的格式
v4l2-ctl -d /dev/videoX -l # 查看指定设备的参数
v4l2-ctl -d /dev/videoX --set-ctrl=<参数名>=<值> # 设置指定设备的指定参数值
v4l2-ctl -d /dev/videoX --get-ctrl=<参数名> # 查看指定设备的指定参数值
熟悉了连接linux机等操作后,主播却发现捕获的图像始终都不能正常显示,乱码,如下:
不止guvcview,cheese和ffmpeg也不管用。淘宝客服也不造。瞎折腾了一番,最终主播发现 把虚拟机usb协议改成3.1有用(默认是usb2.0,但是摄像头参数上明写着usb2.0,挠头):
下一个挑战是灯光导致的过曝问题。可通过调节相机曝光度解决,首先需要关闭自动曝光,再调节具体的值。以下是两种方法:
法一:图形化界面
guvcview
摄像机不在身边,找了张网图,曝光在
Image Controls > 拉到最底下 exposure相关的条目
。法二:命令行工具
v4l-utils
先查看参数,记住自动曝光和曝光值的参数名称
1
v4l2-ctl -d /dev/video0 -l
显示如下,名字可能不同
1
2
3
4
5
6# ...
exposure_auto (menu) : min=0 max=3 default=3 value=3
0: Manual Mode
1: Auto Mode
exposure_absolute (int) : min=5 max=5000 value=313 step=1
# ...再设置值,关闭自动曝光(3改成1):
1
v4l2-ctl -d /dev/video0 --set-ctrl=exposure_auto=1
调节曝光度值(实际默认值为313,主播调到了100以下,大约在80~100这个范围)
1
v4l2-ctl -d /dev/video0 --set-ctrl=exposure_absolute=90
以及实际拍摄质量远比原图恶劣的问题。解决思路是尽量不依靠具体值(如:方块面积、宽高,颜色等),而是依靠多个元素之间的关系,放在代码中表现在:
- 定位方块是正方形,宽高比应在容忍值之内(.2)。
- 三个定位方块应大小一致,取宽度比较应在容忍值内。
- 三个定位方块的倾斜角度应一致,取两两夹角应在容忍值内(5°)。
- 三个定位方块的中心应构成一个等腰直角三角形。这点很重要。
- 指向方块和三角形的mean hsv应大致相似,在容忍值内。
- ……
串口通信主机发送的任务。主播从电控组那儿拿到一个usb串口模块,以及机械组说只需要发送一个方向信息,角度他们已经提前计算好了,倒省了不少力气。最终代码在
tasks/serialsender.cpp
中。
程序参数
虚拟机环境:vmware Ubuntu22.04.5
编译环境:vscode 1.99.3, g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, OpenCV 4.5.4, cmake 3.22.1
编译方法
ctrl+shift+P
调出命令面板,选择 CMake:Configure,再选择g++编译- f7编译
- 运行
./build/main [参数1] [参数2] ...
运行截图