news 2026/10/10 14:35:33

火星月球陨石坑检测数据集:VOC与YOLO双格式目标检测实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
火星月球陨石坑检测数据集: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. 火星月球陨石坑检测数据集:VCO+YOLO双格式,132张图够跑通检测闭环

第一次拿到这个火星月球陨石坑检测数据集时,我盯着目录列表看了半天:132张jpg,xml和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> <folder>firc</folder> <filename>firc_yunshi_109.jpg</filename> <size> <width>800</width> <height>600</height> <depth>3</depth> </size> <object> <name>keng</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>102</xmin> <ymin>88</ymin> <xmax>216</xmax> <ymax>165</ymax> </bndbox> </object> </annotation>

<name>keng</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 python=3.8 -y pip install labelImg labelImg

启动后界面左侧是文件列表,右侧是标注区。Windows下如果安装的是pyqt5的旧版,可能在高分屏上显示模糊,这是环境问题,不影响标注效果。在PyCharm里跑YOLO训练的人,一般也会顺手装一个labelImg,两条工具链互不干扰。

如果要从零标注火星月球影像,建议先做预标注。比如用已经训练好的YOLOv8权重对图片做推理,把高置信度结果导成初步矩形框,再人工确认。陨石坑在灰度影像上边缘模糊,预标注能把时间压缩一半以上。不过预标注只负责“先画出来”,最终框是否贴合坑边缘,还得人眼判断。低置信度框不要直接删掉,那些往往就是小型撞击坑,人工补框后能显著提升小目标召回。

3.2 标注操作与快捷键

labelImg的操作核心是几个快捷键,我习惯把常用动作固定下来。按W进入画框模式,鼠标左键从坑的一角拖到对角,松手后弹窗输入类别名keng。按D切换到下一张图,按A回到上一张。如果需要微调,用Ctrl+鼠标滚轮放大图片后再调框,比直接拖更精确。

陨石坑这类目标有几个标注原则值得坚持。第一,只框完整的坑,边缘被图片边界截断的坑也照框,但要在truncated字段里标记。第二,两个紧挨着的坑必须分开画,不要为省事合并成一个框。第三,对半影区域模糊的坑,框宁可稍微大一点,也别漏掉;因为检测器学习时,略大的框比漏检更好修正。

每标完一张图,马上按Ctrl+S保存。labelImg没有自动保存机制,一旦误关窗口,当前图片的所有框就全丢了。我见过有人一次性标了20多张没保存,程序崩溃后整个上午白干。标注过程中还要定期检查右上角当前保存的是PascalVOC还是YOLO格式,默认是PascalVOC,切换成YOLO后才会同步写出txt。

3.3 导出与验证

如果标注时一直使用PascalVOC模式,目录下只生成xml,YOLO训练还缺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(f'images/{s}.jpg\n') with open('val.txt', 'w') as f: for s in val_stems: f.write(f'images/{s}.jpg\n') print(f'train: {len(train_stems)} images') print(f'val: {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.yaml

data.yaml是训练配置文件,告诉模型去哪找数据、有多少类别。这份数据集的完整写法如下:

path: /your/abs/path/to/dataset train: train.txt val: val.txt nc: 1 names: 0: keng

path填数据集根目录的绝对路径,train和val填之前生成的txt文件名。nc填1,names列表只有keng一个。这里有个容易被忽略的点:names的索引必须和txt第一列对应,txt里是0,names列表第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里类别名是keng,data.yaml的names里却写了crater。YOLO训练只读txt,不读xml,所以模型本身在训练;但推理时把所有框都归类到你写的crater,和原标注的语义脱节。

解决:尽量保持xml、txt、data.yaml三处名字统一。真想改名,就用脚本同时替换xml里的<name>和data.yaml的names,txt第一列索引不变,三处同步。单独改一处,后面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', conf=0.35, iou=0.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')

conf=0.35是我在这种灰度影像上常用的经验值,火星表面纹理复杂时调到0.5压误检,月球暗区目标模糊时调到0.25保召回。iou=0.5是NMS阈值,两个紧挨着的坑如果框重叠区域大,保留置信度更高的那个;阈值太低会把邻近坑合并,太高又会让同一目标出多个框。生成txt后,用labelImg打开图片,把自动框当初始标注,删除误检、补上漏检,才算完成一次合格的数据扩充。

从那以后我每次拿到新数据集,都强制走一遍第4章的校验脚本再开训练,万无一失。这份火星月球陨石坑数据集的规模不大,但VOC和YOLO双格式齐全,类别定义清晰,能让你用最少的时间把目标检测链路完整跑起来,后续再接更大规模数据就有底气了。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 14:34:29

Spring DataSource原理剖析:连接池、自动配置与多数据源实战

1. 全局视角&#xff1a;为什么弄懂 DataSource 才算真正理解 Spring 的数据库原理直接说吧&#xff0c;Spring 的数据库原理这座大厦里&#xff0c;DataSource 就是地基中的地基。不管是 JdbcTemplate、MyBatis 还是 JPA&#xff0c;底层全部要跟数据库建立连接&#xff0c;而…

作者头像 李华
网站建设 2026/10/10 14:30:54

C++ Qt词法分析器课设:NFA/DFA状态图可视化与完整实现

简介&#xff1a;一套面向编译原理课程与期末课设场景的C/Qt词法分析器工程包&#xff0c;适合正在学习词法分析、自动机理论与GUI开发的学生参考。工具将源代码拆分为标记&#xff08;token&#xff09;&#xff0c;覆盖关键字、标识符、数字、运算符等常见规则&#xff0c;并…

作者头像 李华
网站建设 2026/10/10 14:30:14

Go并发面试题详解:两个goroutine交替打印1到100的三种解法

1. 题目拆解&#xff1a;面试官到底在考什么“两个 goroutine 轮流打印 1 到 100&#xff0c;一个打印奇数&#xff0c;一个打印偶数”——这道题在 Go 面试中出现的频率&#xff0c;高到几乎可以跟“反转链表”并列。我第一次在面试中被问到的时候&#xff0c;脑子里全是 chan…

作者头像 李华
网站建设 2026/10/10 14:29:39

ArkWeb开发手记02|权限、网络白名单与页面缓存控制

搞定了 ArkWeb 基础页面搭建&#xff0c;把 Web 组件生命周期做了绑定&#xff0c;解决最头疼的内存泄漏问题。但很多同学照着代码跑通之后&#xff0c;马上遇到新麻烦&#xff1a;H5 页面调用摄像头直接拒绝、上传图片无响应&#xff1b;更换 H5 资源之后 APP 里面还是旧页面&…

作者头像 李华
网站建设 2026/10/10 14:29:22

[鼎捷 ERP] BOM批量导入、工单和采集序列号相关问题排错合集(二)

目录 E10-P-MFG-013 BOM导入主件品号或工厂错误E10-P-MFG-014 BOM变更与导入报错处理E10-P-MFG-015 工单ICD信息字段无法选择E10-P-MFG-016 库存改制入库单审核提示未采集序列号E10-P-MFG-017 生产入库单提示须存在且未审核E10-P-MFG-018 生产入库单序列号采集未完成E10-P-MFG-…

作者头像 李华
网站建设 2026/10/10 14:28:29

租赁门店押金自动原路退回系统设计与实现:以汉服礼服为例

1. 汉服礼服租赁&#xff0c;为什么押金原路退回是个“硬需求”前阵子帮一个做汉服体验馆的朋友梳理订单流程&#xff0c;聊到押金这块&#xff0c;他给我看后台的退款记录&#xff0c;基本上每周都有几笔退款纠纷。有的是顾客说“押金怎么还没到账”&#xff0c;有的是“我当时…

作者头像 李华