火星月球陨石坑检测数据集:VOC与YOLO双格式目标检测实战指南 简介面向目标检测与行星遥感研究的一份小型数据集包含132张火星、月球表面陨石坑jpg图片配套VOC格式xml与YOLO格式txt标注文件共标注1044个keng类矩形框。使用labelImg工具按统一规则画框标注类别一致、坐标信息完整可直接用于YOLO系列、Faster R-CNN等模型训练与算法验证适合刚接触目标检测的开发者练习标注格式转换、训练流程搭建也便于科研人员快速评估陨石坑识别模型。压缩包共398个文件核心由132张jpg原图、132个xml标注和134个txt标注组成其中xml便于使用VOC工具链读取txt则记录归一化坐标、可直接供YOLO训练使用整体仅10.27MB轻量易下载适合在个人电脑上快速迭代实验。数据集不包含分割掩码仅面向检测任务每张图片均有对应标注类别单一、框数充足可显著降低数据预处理工作量让使用者更聚焦模型本身。目前已有244人学习参考适合作为目标检测入门实践或陨石坑识别方向的基础训练数据。1. 火星月球陨石坑检测数据集VCOYOLO双格式132张图够跑通检测闭环第一次拿到这个火星月球陨石坑检测数据集时我盯着目录列表看了半天132张jpgxml和txt各132个标注类别只有一个keng总框数1044。直觉告诉我这份资源不是为了给你刷点而是为了让你少踩“从零开始标数据”的坑。标题里写的VCO其实是VOC的常见笔误内容严格按Pascal VOC标准组织。每张图同时携带VOC和YOLO两种标注文件省掉最繁琐的格式转换环节特别适合想用YOLO跑一遍真实目标检测流程、又不想花几个晚上手工整理标签的人。它也适合目标检测入门者拿来做迁移学习实验先理解数据格式和训练闭环再换大数据集。2. VOC与YOLO两种标注格式为什么要同时给xml和txt这个数据集最直接的价值是同一份标注给你两种表达方式。VOC格式文件结构完整、可读性强适合人工核对和二次编辑YOLO格式一行一个框训练时加载效率高。很多目标检测资源只给其中一种训练前你还得满世界找转换脚本。这套数据把两条路都铺好了但你先得搞懂两种格式各自的脾气后面补数据、改标签时才不会翻车。2.1 VOC的xml结构一个矩形框在文件里长什么样打开firc_yunshi_109.xml你能看到类似下面的结构annotation folderfirc/folder filenamefirc_yunshi_109.jpg/filename size width800/width height600/height depth3/depth /size object namekeng/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin102/xmin ymin88/ymin xmax216/xmax ymax165/ymax /bndbox /object /annotationnamekeng/name是类别名所有xml里都只有这一个值。bndbox里的四个值是像素绝对坐标即左上角(xmin, ymin)和右下角(xmax, ymax)。这个坐标可以直接在图片上画框所以人工检查时我一般用OpenCV把框画出来看一遍比盯着数字猜可靠得多。size节点决定了VOC坐标是否有效。如果xml里记录的宽高和实际jpg尺寸不一致后面做resize、归一化时所有框都会偏。拿到这份数据集后我做的第一件事就是写脚本把每个xml的width和height与图片真实尺寸做比对这一步花不了一分钟却能拦下至少一半后续训练报错。truncated和difficult在训练时通常不起作用YOLO的Dataloader不读这两个字段。但对数据质量有要求的人可以用它们标记“框截断”和“难例”。比如有些坑被图片边缘截断你仍然框出来了就可以把truncated置1下次平衡数据分布时单独处理。2.2 YOLO的txt格式归一化坐标与类别索引YOLO的txt文件每行一个目标格式是“类别索引 中心点x 中心点y 宽 高”。这套数据集只有一个类别所以txt第一列全是0。打开firc_yunshi_109.txt内容类似0 0.198750 0.210833 0.142500 0.128333 0 0.605000 0.482500 0.131250 0.135000四个小数都经过归一化除以图片宽高所以取值范围是0到1。它们的计算规则和VOC坐标的对应关系如下x_center (xmin xmax) / 2.0 / width y_center (ymin ymax) / 2.0 / height w (xmax - xmin) / width h (ymax - ymin) / height这段换算看起来简单但自己动手时很容易疏忽两点。一是忘记除以宽度和高度导致中心点成了几百起步的大数训练时边界框优化直接发散。二是小数点精度建议输出时固定保留6位小数像这份数据集一样。只保留两位小数时640分辨率的图每个框会偏移几十个像素小坑目标尤其敏感。txt的命名必须和jpg完全一致firc_yunshi_109.jpg对应firc_yunshi_109.txt。训练时Dataloader通过图片路径推断标签文件路径如果文件名大小写、特殊符号不一致该图会被当作无标注样本跳过而训练日志里往往只有一条不显眼的警告。2.3 两个格式配合使用训练脚本的读取路径训练阶段用的是txt不是xml。Ultralytics YOLOv8、YOLOv5、YOLOX这些框架都只解析labels目录下的txt。xml更多用在可视化检查、转COCO格式、以及部分基于VOC接口的检测库中。这份数据集虽然给了两套文件但你不能把xml和txt混着用得在配置阶段明确“谁是输入”。用途推荐格式原因人工检查标注质量VOC xml坐标绝对、可读性强可直接画框展示YOLO训练加载YOLO txt每行一个归一化框Dataloader解析成本最低转COCO JSONVOC xml从bndbox生成bbox数组相对直观数据增强后重写标签两套同步增强改变图片尺寸需同时更新坐标和尺寸还要注意摘要里特意说了“不包含分割路径的txt文件”意思是这套数据只有检测矩形框没有目标轮廓多边形。你不能直接拿去做实例分割训练只能用目标检测模型。想做分割得先从矩形框出发人工补轮廓这部分工作量和检测标注完全不是一个量级。3. 用labelImg标注陨石坑从打开图片到导出txt的完整流程这套数据集的标注工具是labelImg标注规则是“对类别画矩形框”这也是目标检测数据标注最常见的方式。理解它的操作流程你才能知道现有标签是怎么来的也才能在需要补数据时保持同样的标注尺度。3.1 环境准备与预标注labelImg依赖PyQt5建议在独立的Python虚拟环境里安装避免PyQt5和本机其他GUI库打架。安装命令很简单conda create -n labelimg python3.8 -y pip install labelImg labelImg启动后界面左侧是文件列表右侧是标注区。Windows下如果安装的是pyqt5的旧版可能在高分屏上显示模糊这是环境问题不影响标注效果。在PyCharm里跑YOLO训练的人一般也会顺手装一个labelImg两条工具链互不干扰。如果要从零标注火星月球影像建议先做预标注。比如用已经训练好的YOLOv8权重对图片做推理把高置信度结果导成初步矩形框再人工确认。陨石坑在灰度影像上边缘模糊预标注能把时间压缩一半以上。不过预标注只负责“先画出来”最终框是否贴合坑边缘还得人眼判断。低置信度框不要直接删掉那些往往就是小型撞击坑人工补框后能显著提升小目标召回。3.2 标注操作与快捷键labelImg的操作核心是几个快捷键我习惯把常用动作固定下来。按W进入画框模式鼠标左键从坑的一角拖到对角松手后弹窗输入类别名keng。按D切换到下一张图按A回到上一张。如果需要微调用Ctrl鼠标滚轮放大图片后再调框比直接拖更精确。陨石坑这类目标有几个标注原则值得坚持。第一只框完整的坑边缘被图片边界截断的坑也照框但要在truncated字段里标记。第二两个紧挨着的坑必须分开画不要为省事合并成一个框。第三对半影区域模糊的坑框宁可稍微大一点也别漏掉因为检测器学习时略大的框比漏检更好修正。每标完一张图马上按CtrlS保存。labelImg没有自动保存机制一旦误关窗口当前图片的所有框就全丢了。我见过有人一次性标了20多张没保存程序崩溃后整个上午白干。标注过程中还要定期检查右上角当前保存的是PascalVOC还是YOLO格式默认是PascalVOC切换成YOLO后才会同步写出txt。3.3 导出与验证如果标注时一直使用PascalVOC模式目录下只生成xmlYOLO训练还缺txt。这时可以用下面的脚本批量转换避免重新打开labelImg一张张过import xml.etree.ElementTree as ET from pathlib import Path xml_paths list(Path(annotations).glob(*.xml)) for xml_f in xml_paths: root ET.parse(xml_f).getroot() filename root.find(filename).text size root.find(size) width int(size.find(width).text) height int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text cls_id 0 if name keng else -1 box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center (xmin xmax) / 2.0 / width y_center (ymin ymax) / 2.0 / height w (xmax - xmin) / width h (ymax - ymin) / height lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) out_path Path(labels) / (Path(filename).stem .txt) out_path.write_text(\n.join(lines) \n)width和height从xml读取确保和图片尺寸一致。cls_id按类别名映射这里只有keng一类所以固定为0。输出用:.6f格式化保证坐标精度。转换完成后用第4章的校验脚本检查txt行数和xml object数量是否一致一致再进训练流程。4. 数据集检查与划分训练/验证集拆分脚本标注数据不管来自哪个工具训练前都要做一遍体检。132张图规模小人工看着检查一遍也来得及但用脚本能从文件名匹配、坐标范围、框数量三个维度同时兜底。这套数据虽然工具生成我仍然坚持走完整检查流程因为它能暴露文件拷贝、压缩、上传过程中引入的隐性损坏。4.1 用Python校验xml和txt是否匹配下面的脚本会遍历所有图片检查对应xml和txt是否存在并对比两边标注框数量from pathlib import Path import xml.etree.ElementTree as ET img_dir Path(images) xml_dir Path(xml) txt_dir Path(txt) for img in sorted(img_dir.glob(*.jpg)): xml_f xml_dir / (img.stem .xml) txt_f txt_dir / (img.stem .txt) if not xml_f.exists(): print(f缺少xml文件: {img.name}) continue if not txt_f.exists(): print(f缺少txt文件: {img.name}) continue root ET.parse(xml_f).getroot() xml_count len(root.findall(object)) txt_count 0 with open(txt_f, r) as f: for line in f.read().splitlines(): if line.strip(): txt_count 1 if xml_count ! txt_count: print(f框数不一致: {img.name}, xml{xml_count}, txt{txt_count})我一般还会在循环里检查txt每行是否恰好5个字段、坐标是否都在[0,1]区间。YOLO训练遇到非法坐标时经常静默跳过该图校验脚本能把这些隐患一次性报出来。对这份数据集正常结果是没有任何输出全部匹配。如果有不匹配的图就需要重新标注或从数据集中剔除千万别抱着侥幸心理硬训。4.2 按比例划分数据集训练前要把图片分成训练集和验证集我习惯用8:2划分并固定随机种子保证每次实验的可比性。脚本如下from pathlib import Path import random random.seed(42) all_stems [p.stem for p in Path(images).glob(*.jpg)] random.shuffle(all_stems) split int(len(all_stems) * 0.8) train_stems all_stems[:split] val_stems all_stems[split:] with open(train.txt, w) as f: for s in train_stems: f.write(fimages/{s}.jpg\n) with open(val.txt, w) as f: for s in val_stems: f.write(fimages/{s}.jpg\n) print(ftrain: {len(train_stems)} images) print(fval: {len(val_stems)} images)random.seed(42)这行看着不起眼但少了它你每次运行脚本都会得到不同的划分结果模型A和模型B就失去了可比性。split是训练集和验证集的切分点132张图按80%切分后得到105张训练、27张验证。因为数据只有一个类别不需要按类别做分层采样如果类别数多了还得用StratifiedShuffleSplit保证每类比例一致。train.txt里写的是图片路径YOLO训练时用image_path找到对应txt。这套数据集的路径可以写成images/firc_yunshi_109.jpg这种相对形式只要data.yaml里的path指向数据集根目录相对路径就能正确解析。最好不要在train.txt里写Windows反斜杠路径跨平台训练时Windows路径分隔符是经典翻车点。4.3 生成YOLO训练用的data.yamldata.yaml是训练配置文件告诉模型去哪找数据、有多少类别。这份数据集的完整写法如下path: /your/abs/path/to/dataset train: train.txt val: val.txt nc: 1 names: 0: kengpath填数据集根目录的绝对路径train和val填之前生成的txt文件名。nc填1names列表只有keng一个。这里有个容易被忽略的点names的索引必须和txt第一列对应txt里是0names列表第0个就必须是keng。如果改成其他名字虽然训练不报错但验证集输出的类别名会变成你改后的名字容易和xml原始标注混淆。写好data.yaml后还要确保labels目录存在。Ultralytics YOLO在读取图片时会默认找图片目录同级的labels目录如果txt文件和jpg放在同一个目录要先把所有txt复制到labels目录。另一种做法是保持原目录结构不动写一个软链接把labels指向txt所在目录。我建议直接用脚本复制一份干净利落排查问题时少一层间接关系。5. 常见问题与避坑标注框丢失、类别名对不上、路径编码翻车这类数据集的坑不在标注本身而在“喂给训练器”的过程。下面几条都是我实际处理时踩过的按现象、原因、解决的顺序写出来。5.1 训练时报“no labels found”现象训练启动后日志很快出现类似found no valid labels for train.txt的警告loss不下降或直接为0。原因YOLO默认从labels目录读取txt而这份数据集给的是jxeg和txt同目录你没建labels目录或者没改路径Dataloader找不到标签文件。解决在数据集根目录下建立labels目录把所有txt复制进去保持文件名和jpg一致。同时检查data.yaml里path字段是否指向正确的根目录。如果图片存在images、txt存在labels目录结构符合框架预期这个警告基本不会再出现。5.2 类别名和xml写的不一致现象训练能跑但验证结果里所有类别AP都是0或者推理输出的类别名是数字而不是keng。原因xml里类别名是kengdata.yaml的names里却写了crater。YOLO训练只读txt不读xml所以模型本身在训练但推理时把所有框都归类到你写的crater和原标注的语义脱节。解决尽量保持xml、txt、data.yaml三处名字统一。真想改名就用脚本同时替换xml里的name和data.yaml的namestxt第一列索引不变三处同步。单独改一处后面Debug时一定后悔。5.3 归一化坐标被截断小目标跑偏现象训练收敛后预测框位置整体偏左上角小坑目标尤其明显IoU怎么都提不上去。原因转换脚本里用了round(x, 2)之类的低精度格式。对640分辨率图片两位小数带来的误差约6像素对小型陨石坑是致命偏移。labelImg默认保留的小数位数够用但如果你自己补数据很容易随手写成简化版格式。解决坐标统一输出6位小数类似f{x:.6f}。不要用round直接format固定长度。这样文件可读性不受影响精度损失可以忽略。5.4 路径分隔符和中文目录导致的读取失败现象本地Windows环境一切正常代码传到Linux服务器后一批图片的标签匹配失败。原因Windows路径反斜杠在Linux下成了转义符或无效字符train.txt里的C:\data\images完全无法解析。路径中带中文或空格解析器兼容性又会再打折扣。解决所有路径统一用pathlib.Path生成写train.txt时用as_posix()转成正斜杠。数据集根目录避免中文和空格。这个坑隐蔽在“本地能跑”只有上服务器复现时才爆出来让人特别难受。5.5 图片尺寸和xml尺寸不一致现象写脚本可视化标注框时某些框直接画到图片范围外或者坐标算出来为负。原因图片后来被压缩、裁剪过xml里的size没有同步更新。labelImg保存时记录的尺寸是第一手数据图片经过处理后就可能失真。解决训练前用PIL读取每张jpg的尺寸和xml的width、height比对不一致的先重写尺寸或删除对应样本。这份数据集由同一工具同一批生成基本不会出问题但补标数据时就保不准了所以这个检查要写进固定流程。6. 用验证集可视化与小目标补标让数据集真正转起来训练一轮后别只盯着mAP数字把验证集的预测框画出来更直观。Ultralytics YOLOv8跑完验证会自动生成val_batch_pred.jpg里面是图片和预测框的叠合图。我建议再打开原xml画一遍人工标注框两者叠加对比你很快能看出模型在哪类目标上漏检——这套数据集里漏检最严重的就是直径几十像素的小坑。验证集27张图人工过一遍也不费劲但换回来的判断比任何单个指标都真实。小目标补标是提升数据可用性的关键一步。我的扩展方案是先训练一个临时模型再对新图做预标注人工修正后并入数据集from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict(new_image.jpg, conf0.35, iou0.5) boxes results[0].boxes.xyxy.cpu().numpy() ids results[0].boxes.cls.cpu().numpy() h, w results[0].orig_shape with open(new_image.txt, w) as f: for box, cls_id in zip(boxes, ids): x1, y1, x2, y2 box xc (x1 x2) / 2 / w yc (y1 y2) / 2 / h bw (x2 - x1) / w bh (y2 - y1) / h f.write(f{int(cls_id)} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}\n)conf0.35是我在这种灰度影像上常用的经验值火星表面纹理复杂时调到0.5压误检月球暗区目标模糊时调到0.25保召回。iou0.5是NMS阈值两个紧挨着的坑如果框重叠区域大保留置信度更高的那个阈值太低会把邻近坑合并太高又会让同一目标出多个框。生成txt后用labelImg打开图片把自动框当初始标注删除误检、补上漏检才算完成一次合格的数据扩充。从那以后我每次拿到新数据集都强制走一遍第4章的校验脚本再开训练万无一失。这份火星月球陨石坑数据集的规模不大但VOC和YOLO双格式齐全类别定义清晰能让你用最少的时间把目标检测链路完整跑起来后续再接更大规模数据就有底气了。希望帮到你。本文还有配套的精品资源点击获取