简介:这份资源面向RoboMaster雷达站算法开发者与参赛队员,汇总了雷达站相关数据集与多所高校开源项目,帮助解决数据来源分散、参考实现难找的问题。数据集涵盖大疆官方数据集、Damon2019/RM-DATASET、华农数据集等,其中官方数据集虽视角单一、噪声较多,但在信号处理与数据增强方面仍有参考价值。开源项目部分收录上海交通大学、沈阳航空航天大学、中国石油大学(华东)、华中科技大学等高校的雷达站程序,并涉及YOLOv5模型剪枝、高性能推理加速模块等技术,还包含2024赛季厦门理工与辽宁科技的最新开源方案,通过规则应用降低成本并提升效果。资源包共3个文件,以inscode工程配置、html页面与gitignore为主,压缩包约6KB,结构轻量便于快速查阅与二次开发。目前已有229人学习,适合希望借鉴成熟方案、优化实时推理性能的开发者参考。
1. RM雷达站数据集与开源源码:从雷达到处都是坑说起
做毫米波雷达感知的团队,几乎都绕不开一个尴尬:算法调了三个月,指标在自采数据上好看得不行,一换场景就崩。问题往往不在模型,而在数据——雷达点云和视觉图像的对齐、标注格式的混乱、场景覆盖的偏斜,这些才是真正吃掉工期的地方。RM雷达站数据集与开源源码这个方向,本质上是把「雷达站」这种固定部署场景下的多模态数据采集、标注、训练、推理整条链路做成可复现的工程资产,而不是丢一个压缩包让你自己猜。它适合两类人:一类是想入门毫米波雷达感知但苦于没有规整数据的算法工程师,另一类是手里有雷达硬件、想把数据变成可训练资产的嵌入式与系统开发者。热搜里「鸟类目标检测的数据集」「自动驾驶数据集」「mmrotate训练dota数据集」这些词频繁出现,说明大家对「拿来就能训」的数据集有多饥渴,而雷达站场景恰恰是其中被低估的一块。
2. 雷达站数据集到底长什么样:点云、标注与目录结构
2.1 雷达站场景的数据构成与选型理由
雷达站不是车载,它的视角固定、背景稳定、目标运动模式相对可控,这决定了数据集的设计逻辑和自动驾驶数据集完全不同。常见做法是采集四类原始数据:毫米波雷达点云(距离、方位角、俯仰角、径向速度、RCS)、同步的视觉图像(用于跨模态验证)、时间戳与雷达站标定参数、以及场景元信息(天气、时段、目标类型)。为什么强调标定参数要进数据集?因为雷达站一旦部署,外参基本不变,但如果你换一个站,外参变了,点云和图像的对应关系就全乱了。把标定参数作为数据的一部分存下来,后续做跨站迁移或者多站融合时才有后悔药可吃。
数据格式上,点云我一般用两种:训练用.npy或.bin存原始点,标注用.json或.xml。不要一上来就上 ROS bag,bag 适合录包回放,不适合直接喂给训练框架。目录结构建议按「场景-时段-序列」三级组织,每个序列下放radar/、camera/、label/、meta.json。这样做的原因是:雷达站数据往往按天甚至按小时累积,扁平目录到几万帧之后根本没法维护。
2.2 从原始点云到训练样本的目录组织与标注规范
下面是一个我实际用过的目录模板,直接抄就行:
rm_radar_station/ ├── calib/ │ ├── radar_camera_extrinsic.json │ └── radar_intrinsic.json ├── scenes/ │ ├── scene_gate_01/ │ │ ├── 2024-06-01_08-00/ │ │ │ ├── seq_0001/ │ │ │ │ ├── radar/ │ │ │ │ │ ├── 000001.bin │ │ │ │ │ └── 000002.bin │ │ │ │ ├── camera/ │ │ │ │ │ ├── 000001.jpg │ │ │ │ │ └── 000002.jpg │ │ │ │ ├── label/ │ │ │ │ │ ├── 000001.json │ │ │ │ │ └── 000002.json │ │ │ │ └── meta.json │ │ │ └── seq_0002/ │ │ └── 2024-06-01_14-00/ │ └── scene_yard_02/ └── splits/ ├── train.txt ├── val.txt └── test.txt标注文件用 JSON,每个目标一条记录,字段包括track_id、class_name、bbox_2d(图像上的框)、center_3d(雷达坐标系下的中心)、dimensions、velocity。这里有个血泪经验:track_id一定要在序列内保持连续,跨序列可以重置,但同一序列里跳变会让跟踪类算法直接翻车。meta.json里存雷达站 ID、标定文件路径、采集时段、天气。别小看天气字段,毫米波雷达在雨雾天的点云密度和噪声分布跟晴天差异很大,后面做域适应的时候这就是分层抽样的依据。
2.3 标注格式转换:从自定义 JSON 到 COCO 与 KITTI 风格
很多开源训练框架只认 COCO 或 KITTI 格式,所以你需要一个转换脚本。下面这个 Python 脚本把自定义 JSON 转成 COCO 风格的检测标注,同时保留雷达 3D 信息:
import json import os from pathlib import Path def convert_seq_to_coco(seq_dir, calib, out_json): """ 将单个序列的自定义标注转为 COCO 格式。 seq_dir: 序列根目录,内含 label/ 和 camera/ calib: 标定参数字典 out_json: 输出 COCO json 路径 """ coco = { "images": [], "annotations": [], "categories": [{"id": 1, "name": "person"}, {"id": 2, "name": "vehicle"}] } ann_id = 1 label_dir = Path(seq_dir) / "label" for idx, lbl_file in enumerate(sorted(label_dir.glob("*.json"))): with open(lbl_file, "r") as f: labels = json.load(f) img_name = lbl_file.stem + ".jpg" # 图像宽高从 meta 或固定值读取,这里假设 1920x1080 coco["images"].append({ "id": idx, "file_name": img_name, "width": 1920, "height": 1080 }) for obj in labels: x, y, w, h = obj["bbox_2d"] coco["annotations"].append({ "id": ann_id, "image_id": idx, "category_id": 1 if obj["class_name"] == "person" else 2, "bbox": [x, y, w, h], "area": w * h, "iscrowd": 0, # 额外保留雷达 3D 字段,方便后续多模态训练 "radar_center_3d": obj["center_3d"], "radar_velocity": obj["velocity"] }) ann_id += 1 with open(out_json, "w") as f: json.dump(coco, f, indent=2) if __name__ == "__main__": convert_seq_to_coco( seq_dir="rm_radar_station/scenes/scene_gate_01/2024-06-01_08-00/seq_0001", calib={}, out_json="seq_0001_coco.json" )逻辑说明:脚本遍历label/下所有 JSON,按文件名排序保证帧序一致;每帧生成一个images条目,每个目标生成一个annotations条目。参数上,category_id的映射关系要根据你的类别体系改,别硬编码。radar_center_3d和radar_velocity不是 COCO 标准字段,但保留它们不会影响标准 COCO 解析器,反而方便你后面写自定义 Dataset 时直接取用。注意area字段必须填,有些评估脚本会用它过滤小目标。
3. 开源源码怎么跑:环境、训练与推理的最小闭环
3.1 环境搭建与依赖版本锁定
雷达站数据集的开源源码通常包含三块:数据加载器、模型定义、训练与评估脚本。我一般用 Python 3.8 + PyTorch 1.12 + CUDA 11.3 这个组合,不是因为它最新,而是因为它在大多数雷达点云库上兼容性最好。依赖里最容易出问题的是点云处理库和 OpenCV 的版本冲突。下面是一个我验证过的requirements.txt片段:
torch==1.12.1 torchvision==0.13.1 numpy==1.23.5 opencv-python==4.7.0.72 scipy==1.9.3 pyyaml==6.0 tqdm==4.65.0安装命令就一行,但要注意先装 CUDA 对应的 torch,再装其余:
pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 -f https://download.pytorch.org/whl/torch_stable.html pip install -r requirements.txt为什么强调版本锁定?因为点云体素化那一步,不同版本的 numpy 在np.histogramdd上的行为有细微差异,会导致体素索引偏移一位,训练时 loss 不降,排查半天才发现是环境问题。这种玄学问题,锁版本是最便宜的解法。
3.2 数据加载器与训练脚本的关键参数
开源源码里的 Dataset 类通常长这样,核心是把点云和标注对齐:
import numpy as np import torch from torch.utils.data import Dataset class RadarStationDataset(Dataset): def __init__(self, split_file, root_dir, num_points=16384): """ split_file: train.txt / val.txt,每行一个序列帧路径 root_dir: 数据集根目录 num_points: 每帧采样点数,不足补零,超出随机采样 """ self.samples = [line.strip() for line in open(split_file)] self.root = root_dir self.num_points = num_points def __len__(self): return len(self.samples) def __getitem__(self, idx): rel_path = self.samples[idx] radar_path = os.path.join(self.root, rel_path, "radar.bin") label_path = os.path.join(self.root, rel_path, "label.json") # 读取原始点云,假设每点 5 维:x, y, z, velocity, rcs points = np.fromfile(radar_path, dtype=np.float32).reshape(-1, 5) # 采样或补零到固定点数 if points.shape[0] >= self.num_points: choice = np.random.choice(points.shape[0], self.num_points, replace=False) else: choice = np.random.choice(points.shape[0], self.num_points, replace=True) points = points[choice, :] # 归一化到单位球,这一步对训练稳定性影响很大 points[:, :3] = points[:, :3] / (np.max(np.linalg.norm(points[:, :3], axis=1)) + 1e-6) return torch.from_numpy(points).float()逻辑说明:num_points设 16384 是毫米波雷达单帧的常见量级,太小会丢小目标,太大显存吃不消。采样时用replace=False优先,不够才重复采样。归一化那一步别省,雷达点云的坐标范围可能从几米到几百米,不归一化的话梯度爆炸是家常便饭。训练脚本里,batch_size我一般设 8 或 16,取决于显存;学习率用 1e-3 配余弦退火,比固定学习率稳。评估时除了 mAP,一定要看速度估计的 MAE,雷达站场景下速度是核心指标之一。
3.3 推理与可视化:把点云和检测框叠到图像上
推理脚本跑通之后,可视化是验证模型有没有学歪的最快手段。下面这段代码把雷达点云投影到图像平面,并画出检测框:
import cv2 import numpy as np def project_radar_to_image(points, extrinsic, intrinsic, image): """ points: Nx3 雷达坐标系点 extrinsic: 4x4 雷达到相机的外参 intrinsic: 3x3 相机内参 image: 原始图像 """ pts_homo = np.hstack([points[:, :3], np.ones((points.shape[0], 1))]) pts_cam = (extrinsic @ pts_homo.T).T[:, :3] # 只保留相机前方的点 valid = pts_cam[:, 2] > 0.1 pts_cam = pts_cam[valid] pts_img = (intrinsic @ pts_cam.T).T pts_img = pts_img[:, :2] / pts_img[:, 2:3] for pt in pts_img: u, v = int(pt[0]), int(pt[1]) if 0 <= u < image.shape[1] and 0 <= v < image.shape[0]: cv2.circle(image, (u, v), 2, (0, 255, 0), -1) return image逻辑说明:外参矩阵的乘法顺序不能错,extrinsic @ pts_homo.T得到相机坐标系下的点,再乘内参得到像素坐标。valid那一步过滤掉相机后方的点,否则投影会出现镜像鬼影。可视化时点的大小和颜色可以按速度或 RCS 映射,这样一眼就能看出哪些点来自运动目标。如果投影结果整体偏移,九成是外参标定错了,回去检查calib/下的文件。
4. 避坑与排查:雷达站数据集最容易翻车的五个地方
4.1 点云和图像时间戳对不齐
现象:投影可视化时,运动目标的点云和图像上的框有肉眼可见的错位,静止目标正常。原因:雷达和相机是独立采集的,时间戳没有做硬件同步,或者同步了但没写进数据。解决:在meta.json里记录每帧的雷达时间戳和相机时间戳,训练时按时间戳最近邻匹配,而不是按帧号硬对齐。如果错位超过 50ms,运动目标的速度估计会直接废掉。
4.2 标注框在雷达坐标系和图像坐标系之间混淆
现象:训练 loss 正常下降,但评估时 mAP 极低,可视化发现框全跑到图像外面去了。原因:标注文件里的bbox_2d和center_3d坐标系定义不统一,有的标在雷达坐标系,有的标在图像坐标系。解决:在标注规范里写死——bbox_2d一律用图像像素坐标,center_3d一律用雷达坐标系,单位米。转换脚本里加断言检查,比如center_3d的 z 值不应该超过雷达站到目标的物理距离上限。
4.3 点云采样导致小目标消失
现象:训练时小目标(比如远处的人)的召回率始终上不去,但大目标正常。原因:固定点数采样时,小目标只占几个点,随机采样很容易把它们全采掉。解决:改用分层采样,先按距离或 RCS 把点分成几组,每组按比例采样。或者把num_points提到 32768,代价是显存翻倍。我一般会在 Dataset 里加一个min_points_per_object的检查,如果某个目标采样后点数少于 3,就重新采。
4.4 跨站迁移时外参失效
现象:在 A 站训练好的模型,直接拿到 B 站推理,性能断崖式下跌。原因:两个雷达站的安装高度、俯仰角不同,外参变了,点云在图像上的投影关系全变了。解决:数据集里必须包含每个站的标定文件,推理前先加载对应站的外参。如果要做跨站泛化,训练时加入随机外参扰动做数据增强,让模型对外参变化不那么敏感。
4.5 评估指标只看 mAP 忽略速度误差
现象:mAP 很高,但下游跟踪模块频繁丢目标。原因:雷达的核心优势是测速,如果速度估计的 MAE 超过 1m/s,跟踪关联就会出错。解决:评估脚本里同时输出 mAP 和速度 MAE,速度 MAE 超过 0.5m/s 就要回去检查标注里的velocity字段是不是从雷达原始数据里正确解析的。有些开源源码在解析.bin时把速度维度的索引搞错了,这种 bug 不看速度指标根本发现不了。
5. 进阶技巧:用半自动标注把数据量翻三倍
雷达站数据集最大的瓶颈从来不是模型,是标注。纯人工标一帧雷达点云加图像,熟练工也要两三分钟,一天标不了几百帧。我后来固定用一套半自动流程:先用少量人工标注训一个初版模型,用它在未标注数据上跑推理,把高置信度的检测结果转成预标注,人工只做修正和补漏。这套流程的关键是置信度阈值和修正策略。
具体做法:推理时输出每个目标的置信度,阈值设 0.7 以上直接采纳为预标注,0.3 到 0.7 之间的标为「待确认」,低于 0.3 的丢弃。人工标注界面里,预标注框用不同颜色区分,修正时只需要拖拽调整,不用从零画框。实测下来,单帧标注时间从 150 秒降到 40 秒左右,而且因为预标注提供了初始位置,漏标率也下降了。
验证半自动标注质量的方法:随机抽 200 帧,人工从头标一遍,和半自动结果做 IoU 匹配,如果召回率低于 95%,说明初版模型的漏检太多,需要先补充训练数据再跑半自动。这个迭代过程一般跑两到三轮,数据量就能从几千帧涨到几万帧,而人工成本只增加了不到一倍。
还有一个技巧是「跨模态一致性检查」:雷达检测到的目标,在图像上应该有一个对应的视觉目标。如果雷达有框但图像上没有,要么是雷达虚警,要么是标注漏了图像框。写一个简单的检查脚本,把不一致的帧挑出来优先人工复核,能揪出不少隐藏的标注错误。这个习惯我保持了两年,每次数据集版本更新都跑一遍,省下的返工时间远比写脚本的时间多。
希望帮到你。
本文还有配套的精品资源,点击获取