VCO转YOLO指南:火星月球陨石坑检测数据集处理与训练实践

发布时间:2026/9/11 23:03:46
VCO转YOLO指南:火星月球陨石坑检测数据集处理与训练实践 简介面向火星与月球表面目标检测研究这份数据集提供陨石坑keng标注样本共132张真实遥感影像采用Pascal VOC与YOLO双格式存储适合用于训练轻量化陨石坑识别模型或验证检测算法。包内文件总计398个包含132个jpg原图、132个xml标注和132个txt标签文件所有图片均配套对应标注类别仅设“keng”合计1044个矩形框标注工具为labelImg且已经按VOC和YOLO两种规范整理可直接接入主流训练框架。资源压缩后仅10.27MB轻量易下载适合快速开展数据集划分、模型迭代与对比实验。目前已有243人学习下载对于需要一份干净、统一格式的陨石坑样本进行算法验证或毕业设计的开发者而言能显著节省数据清洗与格式转换时间同时为后续扩展多类别检测任务提供基础数据支持。1. 火星月球陨石坑检测数据集VCOYOLO格式拿到 132 张图后先要做什么如果你从标注分享页里下载到火星月球陨石坑检测数据集VCOYOLO格式132张1类别.7z第一反应通常是立刻解压把图片丢进训练脚本。但这类来自行星科学项目的压缩包真正要花时间的不是模型而是格式对齐。文件名里的 VCO 一般对应标注端的原始记录YOLO 才是训练时直接读取的标签两者坐标口径、字段单位、图像尺寸都可能不一致。先花半小时解压、列目录、校验哈希、抽查坐标范围比直接训练再回头排错快得多。这篇文章按解压校验、VCO 转 YOLO、训练参数、结果验证四个环节讲完适合手里拿着.7z数据集准备跑通YOLO目标检测流程的工程师和科研人员。2. VCO 标注字段与 YOLO 标签格式转换以 crater 单类别为例拿到压缩包后我一般先不急着写训练代码而是打开 VCO 文件看字段。不同团队对 VCO 的存储习惯差异很大常见的有 JSON、CSV 甚至 XML但核心信息基本一致图像名、陨石坑中心坐标、直径以及可选的长短轴半径。YOLO 标签则非常固定每行一个class x_center y_center width height坐标全部除以图像宽高。这一章先把两套格式的换算关系讲清楚再给出一段可直接改用的转换脚本。2.1 VCO 标注里的 crater 字段到底存了什么这份数据集类别只有 1 个所以类别映射不会出错风险全在坐标字段。VCO 里一个陨石坑常见字段如下字段名含义示例image_name原始图像文件名M1284_ortho.pngimage_width图像像素宽度1024image_height图像像素高度1024center_col_px陨石坑中心列坐标512.4center_row_px陨石坑中心行坐标384.2diameter_px像素直径32.5confidence人工标注重信度0.95注意两个问题。第一center_col_px是列坐标对应图像 x 方向center_row_px是行坐标对应 y 方向。转 YOLO 时不能把 col 当作 y很多坐标错位都来自这里。第二diameter_px是直径而 YOLO 需要框宽和框高。陨石坑在正射影像里接近圆宽高可以直接取 diameter但在斜视影像中会出现椭圆投影这时 VCO 里通常还会给semi_major_px和semi_minor_px需要用长短轴拼出框宽和框高。2.2 YOLO 标签格式与 torch 训练侧的读取习惯YOLO 格式不是“图像 标签框”的二进制而是纯文本。拿上面的示例陨石坑来说图像是 1024×1024中心 x 512.4中心 y 384.2直径 32.5归一化后就是0 0.500391 0.375195 0.031738 0.031738YOLO 标签第一列是类别 ID0 对应names[0]也就是 crater。后面四个浮点数都在 0 到 1 之间分别是中心点相对宽、中心点相对高、框宽相对宽、框高相对高。训练时模型读入原始图片再把标签乘以输入尺寸映射到 feature map 上计算回归损失。这里有个和 KITTI 标注转 YOLO 相似的地方——KITTI 给的是左上角和右下角需要先做x (left right) / 2而 VCO 直接给中心和直径少了坐标加减反而更容易漏掉坐标系转换这一步。2.3 从 VCO 转 YOLO 的 Python 脚本假设 VCO 文件是一个 JSON 数组每个元素是一张图像的标注记录下面这段脚本可以把整个目录的 VCO 全部转成 YOLO 标签import json from pathlib import Path vco_root Path(/data/dataset/vco) label_root Path(/data/dataset/labels) label_root.mkdir(exist_okTrue) for vco_path in sorted(vco_root.glob(*.json)): data json.loads(vco_path.read_text()) img_w float(data[image_width]) img_h float(data[image_height]) lines [] for crater in data[craters]: cx float(crater[center_col_px]) # 列坐标 x cy float(crater[center_row_px]) # 行坐标 y d float(crater[diameter_px]) nx cx / img_w ny cy / img_h nw d / img_w nh d / img_h # 防止边缘标注归一化后越界训练时容易触发警告 nx max(0.0, min(1.0, nx)) ny max(0.0, min(1.0, ny)) lines.append(f0 {nx:.6f} {ny:.6f} {nw:.6f} {nh:.6f}) label_path label_root / (vco_path.stem .txt) label_path.write_text(\n.join(lines) \n)这段代码的关键是把center_col_px除以image_widthcenter_row_px除以image_height不能搞反。最后对中心点做一次 clip是为了防止手工标记正好压在图片边缘时生成大于 1 的中心坐标导致 YOLO 训练在 loss 计算阶段出现 NaN 或严重抖动。框宽高这里没有 clip如果你发现某个陨石坑直径本身就比图像大更合理的做法是在转换前就把该样本标记为异常而不是靠裁剪掩盖问题。转换成 YOLO 格式后找个样本和原图叠加可视化一次别直接开训。常见做法是把中心点和直径画成圆看是否与陨石坑边缘贴合。画完再进入下一步。3. 7z 压缩包的解压、哈希校验与数据集完整性检查.7z不是单纯的压缩容器解压方式、目录层级、文件对应关系都会影响后续训练。很多人在 Windows 上双击解压后直接复制路径到 Linux 服务器结果发现目录里有隐藏文件、文件名大小写不一致或者 VCO 与 YOLO 标签没有一一对应。所以我建议把解压和校验写成一个固定流程每一步都留下输出记录。3.1 Linux 下用 7z 命令行先看包内容再解压拿到压缩包后的第一条命令不是解压而是列目录7z l /data/raw/火星月球陨石坑检测数据集VCOYOLO格式132张1类别.7z注意压缩包路径里有中文Linux 下建议用双引号包裹避免 shell 把空格或特殊符号拆开。7z l会列出包内所有文件路径重点看是否存在images/、vco/、labels/三层目录以及有没有多余的 MAC 系统__MACOSX文件夹。如果有解压时要排除掉否则glob(*.json)会扫到无关文件。完整性校验推荐先执行7z t再计算一次哈希值7z t /data/raw/火星月球陨石坑检测数据集VCOYOLO格式132张1类别.7z 7z h -scrcsha256 /data/raw/火星月球陨石坑检测数据集VCOYOLO格式132张1类别.7z7z t会逐文件测试压缩包内数据是否能完整解出重点排查分卷下载导致的 CRC 错误。7z h -scrcsha256是 7z 命令行对压缩包本体计算 SHA-256 哈希可以用于和发布页面给的哈希值核对。如果发布页只给了 SHA-1把参数改成-scrcsha1即可。哈希一致不代表标注内容一定正确只能证明文件没有被篡改或意外损坏所以解压后还需要做目录级检查。解压命令我一般写成mkdir -p /data/dataset 7z x /data/raw/火星月球陨石坑检测数据集VCOYOLO格式132张1类别.7z -o/data/dataset -y-o参数指定解压输出目录注意-o和路径之间不能有空格这是个容易踩的坑。-y表示遇到同文件覆盖时不交互询问适合脚本执行。解压完成后先7z l看目录再做文件计数。3.2 用 Python 校验 132 张图像与 VCO、YOLO 标签是否一一对应解压完成后不要相信文件名前缀一致就认为万事大吉。用以下脚本扫描三个子目录核对数量和后缀from pathlib import Path import json dataset Path(/data/dataset) for sub in [images, vco, labels]: files list((dataset / sub).glob(*)) files [f for f in files if not f.name.startswith(.)] print(sub, len(files)) image_files {p.stem: p for p in (dataset / images).glob(*)} vco_files {p.stem: p for p in (dataset / vco).glob(*)} label_files {p.stem: p for p in (dataset / labels).glob(*)} print(image - vco missing:, sorted(image_files.keys() - vco_files.keys())) print(image - label missing:, sorted(image_files.keys() - label_files.keys()))这里用stem匹配文件名是因为图像后缀可能是.png或.tif而标签固定是.txt只比较后缀前面部分更稳健。如果输出结果显示有缺失文件先检查压缩包里是不是只有 131 张或者在解压时把部分文件放到了其他子目录。常见的一个问题是 VCO 文件名以.json结尾但 JSON 内部image_name写的是另一套文件名那就要以 JSON 内的image_name为准重新映射。再往下需要检查图像尺寸和标签坐标范围是否自洽import cv2 import numpy as np for img_path in sorted((dataset / images).glob(*)): img cv2.imread(str(img_path)) if img is None: print(broken image:, img_path) continue h, w img.shape[:2] label_path dataset / labels / (img_path.stem .txt) for line in label_path.read_text().strip().splitlines(): parts line.strip().split() if len(parts) ! 5: print(bad label:, label_path, line) else: cls, nx, ny, nw, nh parts # 标签归一化后必须落在合理区间 if not 0 float(nx) 1 or not 0 float(ny) 1: print(out of range:, img_path.name, line)这段代码会把损坏图片、标签行数错误、中心坐标越界的样本全部挑出来。陨石坑检测数据集中图像损坏概率不高但标签越界反而常见尤其是手工标注人为把陨石坑直径描大一圈时归一化后的width x_center可能大于 1。YOLO 对此并不总是报错但会导致训练损失震荡所以提前筛掉。4. 基于 YOLO 训练陨石坑检测模型小样本参数和损失曲线VCO 转 YOLO 跑通后终于可以进入训练环节。这一章不讨论从零搭建网络而是直接用 YOLOv8 的 CLI 完成整个流程。132 张单类别数据集非常小最需要克服的不是模型结构而是训练集和验证集的划分方式以及损失曲线里表现出的过拟合信号。4.1 按文件名切分 train/val并写 data.yaml常见的错误做法是把全部 132 张图同时写进train和val这样训练的 loss 很低但验证指标虚高部署后漏检率会让你怀疑模型根本没有学会。正确做法是先按文件名随机切 20% 到 30% 作为验证集并且保证验证集不参与训练。这里的关键是让 YOLO 根据图像路径自动找到同名标签。先写一个切分脚本import random from pathlib import Path random.seed(42) image_dir Path(/data/dataset/images) images sorted(image_dir.glob(*)) random.shuffle(images) val_count int(len(images) * 0.25) val_images images[:val_count] train_images images[val_count:] with open(/data/dataset/train.txt, w) as f: for p in train_images: f.write(str(p) \n) with open(/data/dataset/val.txt, w) as f: for p in val_images: f.write(str(p) \n)train.txt中每行是图像绝对路径Ultralytics 会根据路径里的images目录自动推导出labels目录位置。比如图像路径是/data/dataset/images/M1284_ortho.png标签路径就会去/data/dataset/labels/M1284_ortho.txt找。如果你的目录不叫images这一步会失效所以前面检查目录结构才重要。对应的crater.yaml写为path: /data/dataset train: train.txt val: val.txt nc: 1 names: 0: craterpath是公共前缀train和val可以写相对路径也可以直接写绝对路径。nc: 1表示单类别names里的名称会出现在最终保留的预测类别中建议用crater方便后续可视化。4.2 小样本下训练参数怎么调数据集只有 132 张如果直接跑默认 100 epochs 加 mosaic前 20 轮往往看不到验证集 mAP 变化。我常用的起始命令是yolo detect train \ datacrater.yaml \ modelyolov8n.pt \ epochs200 \ imgsz960 \ batch16 \ patience40 \ optimizerAdamW \ lr00.001 \ mosaic0.5 \ close_mosaic10这里没有任何一个参数是万能默认值重点看下面这张表参数推荐值原因modelyolov8n.pt132 张图只够训练小模型yolov8s 以上很容易过拟合imgsz960火星月球影像中陨石坑尺度差异大640 会丢失小目标batch16显存允许时尽量用大一点BatchNorm 的统计量更稳定epochs200小数据集需要更多轮次配合早停避免无效等待patience40验证指标连续 40 轮不涨就停止mosaic0.5保留增强但不能全程拉满否则小目标被切碎close_mosaic10最后 10 轮关闭 mosaic让模型适应真实目标分布在遥感图像里imgsz 的选择比模型宽度更重要。imgsz960时一个直径 32 像素的小型陨石坑在输入图上约占 32 个像素特征提取还能保留如果缩到 640可能只剩 21 像素微弱边缘很容易被下采样吞掉。显存不够就把batch降到 8优先保 imgsz。4.3 损失曲线和评估指标怎么读YOLOv8 训练时results.csv里每行记录train/box_loss、train/cls_loss、train/dfl_loss三个训练损失以及验证集的metrics/precision(B)、metrics/recall(B)、metrics/mAP50(B)。由于这里只有 1 个类别cls_loss从一开始就接近 0不是关注重点真正要看的是box_loss和dfl_loss。如果box_loss稳定下降但val/box_loss在前 30 轮后开始上升说明模型开始过拟合训练集中的陨石坑形态。这时候优先降低epochs把patience调到 20不要盲目加数据增强。如果box_loss和dfl_loss都震荡不降多半是标注里有大量直径和中心位置偏差回到第三章的校验脚本把可视化输出图翻一遍。这里有一个陨石坑检测特有的评估陷阱通用目标检测用IoU0.5判断正样本但陨石坑是圆形边缘模糊目标人工标注直径本身有误差同一个坑不同标注人员可能相差 20%。直接用mAP50容易低估模型能力更常用的评估方式是看预测圆心和 GT 圆心距离是否小于 0.6 倍 GT 半径。这个逻辑会在下一章的可视化验证中直接落成代码。5. 用 YOLO 预测脚本验证火星月球陨石坑检测的坐标偏移最后一章给一个针对陨石坑数据集的验证技巧不要只看训练日志里的 mAP而是把模型预测结果和 VCO 原始标注画在同一张图上按圆心偏移量排序逐个检查。5.1 用圆心距离和半径比值替代 IoU 评估检测质量import json import cv2 from pathlib import Path from ultralytics import YOLO model YOLO(/data/dataset/runs/detect/train/weights/best.pt) output_dir Path(/data/dataset/check_imgs) output_dir.mkdir(exist_okTrue) for img_path in sorted(Path(/data/dataset/images).glob(*)): vco_path Path(/data/dataset/vco) / (img_path.stem .json) data json.loads(vco_path.read_text()) img cv2.imread(str(img_path)) results model.predict(img_path, imgsz960, conf0.25, iou0.6)[0] preds [] for x, y, bw, bh in results.boxes.xywh.cpu().numpy(): preds.append((float(x), float(y), max(float(bw), float(bh)) / 2)) for crater in data[craters]: cx float(crater[center_col_px]) cy float(crater[center_row_px]) radius float(crater[diameter_px]) / 2 best_ratio 9.9 for px, py, pr in preds: dist ((px - cx) ** 2 (py - cy) ** 2) ** 0.5 ratio dist / radius if ratio best_ratio: best_ratio ratio color (0, 0, 255) if best_ratio 0.6 else (0, 255, 0) cv2.circle(img, (int(cx), int(cy)), int(radius), color, 2) for px, py, pr in preds: cv2.circle(img, (int(px), int(py)), int(pr), (255, 0, 0), 1) cv2.imwrite(str(output_dir / (img_path.stem _check.jpg)), img)这段脚本把 VCO 真值画成彩色圆把 YOLO 预测画成蓝色圆。当某个真值没有找到与其圆心距离不超过 0.6 倍半径的预测时这个圆会被画成红色。按图名逐个翻红色主要集中在哪种场景下一目了然是整张图的边缘区域还是直径特别小的陨石坑还是图像本身有云雾遮挡。这个观察比任何 loss 曲线都更能指导下一步比如针对性提高 imgsz或在验证时降低 conf 阈值。本文还有配套的精品资源点击获取