简介:面向道路损伤检测的目标检测数据集,覆盖纵向裂纹、碰撞、车轮痕迹、坑洼、裂缝五类典型路面损坏,适用于自动驾驶路况感知、公路养护自动化巡检等场景。图片与标注均已完成预处理,数据集已按比例划分训练集与验证集,并附带数据配置文件,可直接用于YOLOv5、YOLOv7、YOLOv8、YOLOv9、YOLOv10、YOLO11等主流YOLO版本训练与验证,适合算法学习者、项目开发者快速验证模型或搭建道路巡检方案。压缩包共2000个文件,主要包含945个XML标注与945个TXT标注,对应VOC和YOLO两种常用格式,另含109张JPG原图和1个YAML配置文件,坐标已按图像宽高归一化,便于切换不同训练框架。资源整体约19.61MB,体积小巧,离线下载使用非常便捷。目前已有124人学习,具有一定的参考价值。使用该数据集可直接开展模型训练与效果对比,省去手工标注和格式转换的大量时间,是道路缺陷检测入门、算法选型与模型迭代的实用数据支撑。
1. 道路损伤检测的数据集困局:945 张 YOLO 标注图能省多少事
做道路损伤检测的人,第一道坎往往不是模型选型,而是目标检测数据集从哪来。自己拍照并标注,945 张图像按每张平均三到五个目标框来算,一个熟练标注员连续做也要两三周;网上找公开数据集,又常卡在 VOC 或 COCO 格式转换上,光写转换脚本就够折腾一晚上。这个 zip 包里装的是一份直接可用的 YOLO 格式道路损伤目标检测数据集,945 张图像全部带标签,类别覆盖纵向裂纹、碰撞、车轮痕迹、坑洼、裂缝,解压后放进 YOLOv5 或 YOLOv8 工程里就能直接训练。适合做路面巡检、道路养护检测的工程师,也适合拿来做目标检测入门实战的学生。下文按拆包验数据、训练前准备、避坑、验证的顺序,把这份资源从 zip 包到出模型完整走一遍。
2. 数据集结构与 YOLO 标签格式:拆开 zip 先搞懂这四件事
数据集和代码不一样,代码跑不起来会立刻报错,数据集有问题往往是训到一半才暴露,浪费的是整个训练周期。所以拿到 zip 包第一步不是解压后直接扔进训练脚本,而是把目录结构、标签格式、类别分布、坐标边界这四件事逐项查清楚。这一章就按这个顺序来。
2.1 目录布局与同名对应:先查这两件事
这类 YOLO 格式数据集的打包方式通常很固定:根目录下分 images/ 和 labels/ 两个文件夹,图像文件是 jpg 或 png,标签文件是与图像同名的 txt。有的发布者还会附带 classes.txt 或 data.yaml 用来声明类别顺序;如果没附,就得自己从标签文件里的类别 id 反推,这一步最容易忽略,避坑章我会专门展开。
先把结构列出来,同时做一次同名对应检查。这个动作的价值在于:确认 zip 包完整性,以及在训练开始前发现文件缺失,而不是等训练中断再回头查。
from pathlib import Path root = Path("road_damage_dataset") images_dir = root / "images" labels_dir = root / "labels" imgs = {p.stem: p for p in images_dir.glob("*") if p.suffix.lower() in {".jpg", ".jpeg", ".png"}} labels = {p.stem: p for p in labels_dir.glob("*.txt")} print(f"图像文件: {len(imgs)} 个") print(f"标签文件: {len(labels)} 个") print("有图无标签:", sorted(set(imgs) - set(labels))[:10]) print("有标签无图:", sorted(set(labels) - set(imgs))[:10])这段脚本的核心逻辑是拿文件名主干做集合差集。这里特意把图像扩展名统一转成小写再比较,因为 Windows 和 Linux 混用的数据集里.jpg和.JPG并存非常常见,直接拿字符串比对会误报缺失。如果「有图无标签」列表非空,说明部分图像没有标注,这段数据在训练时会被跳过,但会拉低对应类别的 recall;如果「有标签无图」非空,说明标签文件残留,通常不影响训练,但会让你统计的数据量虚高。两份集合完全对上之后再往下走。
2.2 标签坐标还原:读一行 txt,算出它在图上的哪个位置
YOLO 的标签是文本文件,每一行代表一个目标框,五个数值依次是类别 id、中心点 x、中心点 y、框宽 w、框高 h。前四个数值做了归一化,除以图像宽高后落在 0 到 1 之间,所以同一份标签在任意分辨率图像上都有效。这也是 YOLO 格式比 VOC 的xmin, ymin, xmax, ymax绝对坐标省事的地方,代价是解析时容易忘掉还原步骤。
随便抽一个标签文件验证:
from pathlib import Path import cv2 img_path = Path("road_damage_dataset/images/000123.jpg") img = cv2.imread(str(img_path)) img_h, img_w = img.shape[:2] label_path = Path("road_damage_dataset/labels/000123.txt") for line in label_path.read_text(encoding="utf-8").strip().splitlines(): if not line.strip(): continue parts = line.split() cls = int(parts[0]) cx, cy, w, h = map(float, parts[1:5]) x_min = int((cx - w / 2) * img_w) y_min = int((cy - h / 2) * img_h) x_max = int((cx + w / 2) * img_w) y_max = int((cy + h / 2) * img_h) print(f"类别 {cls}: 像素框 ({x_min}, {y_min}) -> ({x_max}, {y_max})")这里img_h, img_w从 OpenCV 读取的图像数组形状里拿,shape[0]是高度、shape[1]是宽度,顺序别写反。还原公式就是把归一化坐标乘回像素尺寸:框左上角 x 是中心点 x 减半宽,右下角 x 是中心点 x 加半宽,y 方向同理。这段脚本主要用途不是看内容,而是验证还原后的坐标有没有越界——如果 x_max 大于图像宽度或 y_min 小于 0,说明标签归一化数据本身就有问题,这类样本在训练时会被某些 YOLO 版本自动裁剪,也可能引起 loss 异常波动,发现了要单独剔出来。
2.3 类别分布与目标尺寸统计:决定训练参数的第一手数据
知道标签格式后,下一个动作是对全量数据集做统计:五个类别的目标框各有多少、框的尺寸分布如何。这一步直接决定后续训练参数怎么设。比如坑洼和碰撞痕迹这类目标通常只占整张图很小一块,如果框面积普遍小于图像面积的 1%,训练时就该考虑提高输入分辨率或调整锚框,而不是无脑用默认配置。
from pathlib import Path from collections import Counter import cv2 cls_counter = Counter() tiny_boxes = 0 total_boxes = 0 for img_path in sorted(images_dir.glob("*")): if img_path.suffix.lower() not in {".jpg", ".jpeg", ".png"}: continue img = cv2.imread(str(img_path)) h, w = img.shape[:2] label_file = labels_dir / (img_path.stem + ".txt") if not label_file.exists(): continue for line in label_file.read_text(encoding="utf-8").strip().splitlines(): parts = line.split() cls = int(parts[0]) bx, by, bw, bh = map(float, parts[1:5]) box_area = bw * w * bh * h image_area = w * h cls_counter[cls] += 1 total_boxes += 1 if box_area < image_area * 0.01: tiny_boxes += 1 print("类别分布:", dict(cls_counter)) print("小目标框占比: {:.1f}%".format(tiny_boxes / total_boxes * 100))脚本按类别统计目标框数量,同时用「框面积小于全图面积 1%」作为小目标阈值做评估,阈值 0.01 是经验值,不是固定标准。跑完建议把阈值改成 0.005 和 0.02 各算一次,看小目标占比对阈值敏不敏感。如果某一类只有几十个框,那一类在训练里大概率学不好,得提前想好是补数据还是做重采样。如果小目标占比超过三分之一,训练参数里 imgsz 就别用 640 默认值了,这个判断越早做越省时间。
提示:统计脚本建议只读不要改,运行前先备份原始 zip。后面做任何清洗都基于副本,原始包保留作为后悔药。
2.4 可视化抽检:把标注框画回图像上人工过一遍
数据统计只能告诉你数量分布,不能告诉你框画得准不准。道路损伤数据里最容易出的标注问题是「纵向裂纹」和「裂缝」这两个类别边界模糊——同一条裂纹,有的标注员画成纵向裂纹,有的画成裂缝,模型会把它们当成两个类去学,但实际上特征高度重叠。所以抽几十张图把框画出来,人工过一遍视觉确认是必要步骤。
import cv2 import random from pathlib import Path random.seed(42) sample_imgs = random.sample(sorted(images_dir.glob("*.jpg")), 30) output_dir = Path("check_vis") output_dir.mkdir(exist_ok=True) colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0), (0, 255, 255), (255, 255, 0)] class_names = {0: "longitudinal_crack", 1: "collision", 2: "wheel_track", 3: "pothole", 4: "crack"} for img_path in sample_imgs: img = cv2.imread(str(img_path)) h, w = img.shape[:2] label_file = labels_dir / (img_path.stem + ".txt") if not label_file.exists(): continue for line in label_file.read_text(encoding="utf-8").strip().splitlines(): parts = line.split() cls = int(parts[0]) cx, cy, bw, bh = map(float, parts[1:5]) x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), colors[cls % len(colors)], 2) cv2.putText(img, class_names.get(cls, str(cls)), (x1, max(0, y1 - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, colors[cls % len(colors)], 1) cv2.imwrite(str(output_dir / img_path.name), img) print(f"可视化结果已保存到 {output_dir}")这段脚本里 class_names 是我按常见命名写的示例映射,不代表这个数据集实际使用的英文标签,具体以包内 classes.txt 为准。人工抽查时重点看两点:框有没有偏离目标本体、相近类别是否出现明显画法不一致。如果发现纵向裂纹和裂缝的框大量叠加在同一条纹路上,说明这两个类本身区分度存疑,要么合并成一个类,要么靠加大每个类的样本量来补救,这个判断要在训练前做,不能等模型训完再后悔。
3. 训练前数据准备:划分、配置与首轮训练
数据集验证通过之后,进入训练前的准备环节。这一章只做三件事:划分训练集和验证集、写 data.yaml 配置文件、跑通第一条训练命令。很多初学者在这三步上翻车,常见的是划分时没固定随机种子导致实验结果不可复现,或者 data.yaml 里路径写成相对路径导致训练时报数据集找不到。
3.1 划分训练集与验证集:固定随机种子,避免结果不可复现
945 张图不算多,按 8:2 划分是训练集 756 张、验证集 189 张,这个比例对这个规模是合理默认值。划分的逻辑看起来简单,但有个细节容易翻车:如果直接用random.shuffle而不设种子,每次运行结果都不一样,后续想复现实验就无从谈起。正确做法是固定随机种子,或者基于文件名做散列取模。
import random from pathlib import Path random.seed(42) root = Path("road_damage_dataset") images = sorted(p for p in (root / "images").glob("*") if p.suffix.lower() in {".jpg", ".jpeg", ".png"}) random.shuffle(images) val_ratio = 0.2 val_count = int(len(images) * val_ratio) val_images = set(images[:val_count]) train_images = set(images[val_count:]) train_images_dir = root / "train" / "images" val_images_dir = root / "val" / "images" train_labels_dir = root / "train" / "labels" val_labels_dir = root / "val" / "labels" for d in [train_images_dir, val_images_dir, train_labels_dir, val_labels_dir]: d.mkdir(parents=True, exist_ok=True) for img in train_images: img.rename(train_images_dir / img.name) lab = root / "labels" / (img.stem + ".txt") if lab.exists(): lab.rename(train_labels_dir / lab.name) for img in val_images: img.rename(val_images_dir / img.name) lab = root / "labels" / (img.stem + ".txt") if lab.exists(): lab.rename(val_labels_dir / lab.name) print(f"训练集 {len(train_images)} 张,验证集 {len(val_images)} 张")这里直接用了文件移动而不是复制,因为原始 zip 已经备份过了,没必要在磁盘上存两份。random.seed(42)保证重跑时得到相同的划分结果,42 是我个人习惯,换成任意整数都行,关键是固定下来。val_ratio取 0.2 是目标检测常规默认值,如果某个类别框数特别少,可以考虑分层划分:按类别先从每类里抽,再合并成验证集,保证验证集里每类都有代表样本。945 张规模下简单随机划分通常够用,但如果 2.3 节统计发现某一类只有二十几个框,简单随机很可能让验证集里这一类只有三四个框,这种就要手动干预了。
划分完成后目录结构变成 train/images、train/labels、val/images、val/labels 四个文件夹,这是 YOLOv5 和 YOLOv8 都认识的经典布局。
3.2 data.yaml 编写:类别顺序错一位,模型全盘错认
data.yaml 是 YOLO 训练的数据入口,里面声明训练集路径、验证集路径和类别名列表。最容易犯的错误是 names 的顺序和标签里类别 id 对不上,比如标签里 0 代表纵向裂纹、1 代表碰撞,yaml 里却把碰撞写在第一位。模型不会报错,但训练出来的模型会把每一类都错认成名字对应错位的那个类,而且很难从 loss 曲线上看出来——loss 照样收敛,mAP 照样涨,一头扎进推理才发现全乱了。
path: /absolute/path/to/road_damage_dataset # 数据集根目录,建议写绝对路径 train: train/images val: val/images names: 0: longitudinal_crack # 纵向裂纹 1: collision # 碰撞 2: wheel_track # 车轮痕迹 3: pothole # 坑洼 4: crack # 裂缝上面这个 names 是常见映射示例,不代表 zip 包内实际的类别 id 顺序,以包内 classes.txt 或 data.yaml 为准。如果发布者没提供类别文件,可以跑一段脚本从标签文件里反推:
from pathlib import Path label_files = list(labels_dir.glob("*.txt")) class_ids = set() for f in label_files: for line in f.read_text(encoding="utf-8").strip().splitlines(): if line.strip(): class_ids.add(int(line.split()[0])) print("标签中出现过的类别 id:", sorted(class_ids))这段代码把全量标签里的类别 id 收集起来去重,输出结果应该是[0, 1, 2, 3, 4]这样的连续序列。如果输出跳号,比如[0, 1, 3],说明数据里少了某一类,这个信息要和 2.3 节的类别统计交叉验证。反推出 id 范围后,再结合图像内容人工确认每个 id 对应的类别名,这一步要认真做,因为 YOLO 训练框架不会替你校验名字和视觉内容是否匹配。path 字段建议写绝对路径,相对路径在 ultralytics 里会拼接在工程目录下,经常报 No such file or directory,排查起来很费时间。
3.3 首轮训练参数选择与日志阅读:loss 不降先查数据
数据集规模不到一千张,模型没必要一上来就选最大的。以 YOLOv8 为例,第一轮先用 nano 版本跑通流程,验证数据链路没问题,再换 s 或 m 提精度。这既能快速暴露数据问题,也能给后续实验留出对比基线。
yolo detect train \ data=road_damage.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ project=./runs \ name=road_damage_v1参数说明:data指向刚写好的 yaml;model用 yolov8n.pt 预训练权重作为初始权重,这是迁移学习的标准做法,比从零训练收敛快得多;epochs在 945 张图上跑 100 轮足够 loss 进入平台期,再往后容易过拟合;imgsz用 640 是速度与精度的折中,如果 2.3 节统计出小目标占比高,这一步改成 960;batch根据显卡显存调整,16G 显存跑 batch=16 的 640 输入没有压力,显存小就降到 8,另外 batch 太小会影响 BN 层统计,尽量别低于 8。
训练开始后不要只盯着终端滚动条,重点观察两个指标。第一,box_loss和cls_loss是否稳定下降,这两个值对应的是 YOLO 损失函数里的定位分支和分类分支,如果 loss 不降反升,大概率是标签有问题而不是模型有问题,回到第 2 章重新检查标签越界和类别错位。第二,验证集mAP50有没有随训练轮数正常抬升,如果卡在某个值上不去,先别急着调模型,回 2.3 节看类别分布——多数类把整体指标拉高、少数类一直学不好,是最常见的原因。
注意:YOLOv5 和 YOLOv8 的数据集目录结构要求略有差异,但 train/images 和 val/images 这种布局两者通用。如果用的是 mmrotate 这类旋转目标检测工具,目录约定和标签格式又是另一套,需要单独适配。训练中断想续跑,ultralytics 会自动从
runs/road_damage_v1/weights/last.pt继续,前提是 project 和 name 参数保持一致。
4. YOLO 道路损伤训练避坑:945 张图上最容易翻车的五个问题
这一章记录的是实际跑这份数据时最容易遇到的问题,每一条按「现象、原因、解决」展开。这些问题不是同时出现,但每个都真实发生过,建议当成训练前的检查清单用。
4.1 类别 id 与 names 文件错位:模型全类错认但 loss 正常
现象:训练过程 loss 正常下降,mAP50 看起来不错,用训练好的模型推理时,坑洼的检测框标成了纵向裂纹,碰撞痕迹显示成裂缝,所有类别整体平移了一位,而且很难从指标上察觉。
原因:data.yaml 里 names 的顺序和标签文件里的类别 id 不一致。标签里 0 号是纵向裂纹,yaml 第一个名字写的却是碰撞,模型学到的是「id=0 的视觉特征对应碰撞」这个错误映射。YOLO 训练过程没有任何机制检查这个对应关系,loss 该收敛还是收敛,这是这类问题最阴险的地方。
解决:训练启动前跑一遍 3.2 节的类别 id 反推脚本,把标签里出现过的 id 集合与 data.yaml 的 names 键值逐一对照。发布者给了 classes.txt 就以它为准,没给就人工抽 20 张图像把框画出来确认。把这步写进训练脚本的启动前置检查里,比等训练完再发现省两小时。从那以后我每次换新数据集第一件事就是跑这个对照,不再信文件名。
4.2 小目标占比高:坑洼碰撞检不出来
现象:验证集上纵向裂纹和裂缝的 mAP50 能到 0.7 以上,坑洼和碰撞只有 0.2 甚至接近 0,单独拿包含小目标的图像推理,模型几乎不输出这些类别的框。
原因:道路损伤数据集的天然属性——坑洼和碰撞痕迹在巡检图像里往往只占很小一块像素面积。如果 2.3 节统计的小目标占比超过三分之一,默认 640 分辨率下,小目标被缩放到只有十几个像素宽,特征几乎丢失。YOLO 默认锚框是按 COCO 数据集统计的,对这类极小目标本身就不友好。
解决:两条路。第一,imgsz 从 640 提到 960 或 1280,输入分辨率越大,小目标保留的像素越多,代价是显存上涨、训练变慢;第二,数据增强里叠加 mosaic 和 copy-paste,让包含小目标的样本在每张训练图里出现得更频繁。我一般先跑 imgsz=960 的对比实验,坑洼类 mAP50 通常能拉上来 10 到 15 个点,还不够再考虑针对性补数据。降低 conf 阈值不是正路,那是事后补救,不是根治。
4.3 类别样本量失衡:少数类被多数类带偏
现象:训练初期 loss 下降很快,但验证集上少数类的 precision 和 recall 明显低于多数类,混淆矩阵里少数类样本大量被预测成相邻的多数类,比如车轮痕迹被预测成碰撞。
原因:945 张图不等于每个类别都有 945 个框。实际分布往往是纵向裂纹和裂缝占了大半,碰撞和车轮痕迹只有几十个框。模型每轮训练见到多数类的机会远多于少数类,决策边界整体偏向数据量大的那边,这和数据增强无关,是类别不平衡的典型表现。
解决:先看 2.3 节的统计结果。如果少数类框数不到多数类的五分之一,做两类处理:一是对少数类图像做离线增强,翻转、亮度抖动、随机裁剪都行,但别做太狠导致标注和图像内容不匹配;二是训练时给少数类更高的采样权重,ultralytics 里可以按类别频率调整 sampler 权重。不要只调 loss 权重,少数类本身特征多样性不足,权重调再高也学不到足够的泛化特征。补数据是最稳的,但周期长,离线增强是当天能见效的折中方案。
4.4 有图无标签或有标签无图:训练中断或漏检
现象:训练脚本启动后没多久报错,提示某个图像找不到对应标签,或者标签数组维度不匹配;另一种情况完全不报错,训练正常完成,但验证集漏检严重,尤其集中在某几类。
原因:数据集在传输或解压过程中丢失部分文件,或者原始打包时某些图像本身就没有标注。2.1 节的同名对应检查在训练前没跑的话,要等到训练加载数据时才发现缺口。这种缺口在 945 张规模里哪怕只有二三十张,对应类的 recall 就会明显变差,因为模型根本没机会看到这部分样本。
解决:严格养成先跑 2.1 节脚本再训练的习惯。有图无标签的样本要么补标注、要么直接从数据集里移除;有标签无图的文件直接删除,避免统计混乱。补标注人力不够时,先用训练好的模型做预标注再人工修正,这是一线项目里最常见的操作节奏。另外每个 epoch 结束后扫一眼验证集的 loss,如果验证 loss 突然跳变,排除学习率因素后优先怀疑数据加载链路。
4.5 解压乱码与扩展名大小写混用:路径匹配全乱
现象:在 Windows 上解压 zip 后,部分图像文件名显示成乱码,或者图像是 .JPG 后缀而脚本里 glob 匹配的是小写 .jpg,导致匹配数量对不上,代码在数据加载阶段报找不到文件。
原因:zip 包如果在 Linux 或 macOS 上打包,中文文件名用 UTF-8 编码,Windows 自带解压工具默认按 GBK 解压就会乱码;扩展名大小写混用则常见于相机直接导出的素材未做统一处理。这两类问题不影响标签内容本身,但会让自动化脚本匹配失效,肉眼很难发现。
解决:解压优先用 7-Zip,解压时选择保留原始编码;已经乱码的,用 Python zipfile 模块重新解压并指定编码。扩展名混用问题,解压后统一跑一次 rename 把 .JPG、.jpeg、.Jpeg 全部转小写 .jpg。处理完再走一遍 2.1 节对应检查,数量对上再进训练流程。另外注意标签文件内容如果是 UTF-8 带 BOM,第一行的类别 id 前会多一个不可见字符,用utf-8-sig编码读取能避开这个坑。
提示:这五个问题不是每次全遇到,但每一条都真实发生。建议把五条整理成 checklist 写进数据准备脚本的注释里,换新数据集时强制跑一遍,别跳过。
5. 训练完成后的验证闭环:混淆矩阵、实图抽查与小目标专项评估
模型训练完,第一件事不是急着导出部署,而是做验证闭环。只看终端最后一行 mAP50 是最容易自欺欺人的做法,这个数字在类别不平衡数据上会被多数类拉高,掩盖少数类的真实表现。我现在的固定流程是三步:看混淆矩阵和每类 PR 曲线,做一批实图推理抽查,最后针对表现最差的类别单独评估。
验证命令在 YOLOv8 里很直接:
yolo detect val \ data=road_damage.yaml \ model=runs/road_damage_v1/weights/best.pt \ imgsz=640跑完后重点看 results 目录下的 confusion_matrix.png 和 PR_curve.png。混淆矩阵横纵轴是真实类别和预测类别,对角线越亮越好;亮点出现在非对角线位置,说明哪两类在互相混淆,就去翻那一类的样本找视觉共性,纵向裂纹和裂缝混淆就要考虑是不是类别定义本身有问题。PR 曲线看的是曲线下面积,面积小说明 recall 提升时 precision 掉得快,这类目标要么特征弱、要么样本少。
实图抽查不能省。选验证集里包含坑洼和碰撞小目标的图像跑推理,把检测框画回原图:
from ultralytics import YOLO model = YOLO("runs/road_damage_v1/weights/best.pt") results = model.predict("val/images/000223.jpg", imgsz=640, conf=0.25) for r in results: r.plot()这里 conf=0.25 是默认阈值,小目标在 0.25 下检不出来时,把阈值降到 0.1 再看一次。降阈值后能检出但框位置偏移明显,说明是回归精度问题,回训练阶段提 imgsz;降阈值后依然检不出来,说明模型根本没学到这个特征,问题在数据端。这一步能快速区分模型问题和数据问题,避免盲目调参消耗时间。
最后是小目标专项评估。把验证集里坑洼和碰撞类的框单独拉出来,算各自 mAP50,如果专项分数比整体低 20 个点以上,回第 4 章对症下药处理。从那以后我每次跑完训练都强制走一遍这个验证闭环,不再沉迷于终端里那个好看的总 mAP,毕竟道路损伤检测最终要看的是坑洼和碰撞这类真正影响行车安全的目标能不能被稳定识别出来,希望帮到你。
本文还有配套的精品资源,点击获取