news 2026/10/6 6:27:05

基于YOLOv8的PCB板缺陷检测:从数据集准备到部署实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于YOLOv8的PCB板缺陷检测:从数据集准备到部署实战

简介:一份面向计算机科学与技术等相关专业本科生/研究生的毕业设计参考文档,围绕基于YOLOv8的PCB板缺陷检测系统展开,针对传统人工目检效率低、误检率高等痛点,给出从需求分析、系统设计到实验验证的完整方案。资源包内仅含1个docx文件,整体大小3.66MB,内容覆盖中英文摘要、绪论、关键技术介绍、系统分析、功能与非功能需求、YOLOv8网络结构、损失函数、训练与推理以及数据集准备等章节,目录结构清晰,便于按章节查阅和复用。目前已有500人学习下载,尤其适合正在开展深度学习/计算机视觉方向毕业设计、需要论文框架与实现思路参考的学生和指导教师。文档结合YOLOv8框架详细说明了PCB缺陷检测系统的设计理念与技术架构,并展示了实验验证结果,可帮助读者快速理解目标检测在工业质检场景中的应用方法,同时为论文写作和系统复现提供直接素材。

1. 为什么把PCB板缺陷检测交给YOLOv8:从传统视觉到毕业论文的落地路径

PCB板缺陷检测这个课题,每年都有大量毕业论文和工厂项目做到一半卡住:人工目检效率不稳,传统视觉方案要针对断路、短路、孔洞、毛刺分别写规则,换个板子就失灵。我第一次把YOLOv8接进来是一条小批量产线,当时最直观的感受是,只要标注质量过关,端到端检测比调规则省太多时间。这篇笔记要讲的就是一套能复现的完整路径:从PCB缺陷数据准备、用YOLOv8训练自己的数据集,到封装成检测系统、部署到普通工控机甚至RK3588板卡,最后把这些过程组织成毕业论文实验。适合准备做毕业设计的学生,也适合刚接PCB视觉检测项目的工程师参考。

2. 准备PCB缺陷数据集:标注格式转换、类别平衡与增广策略

PCB板缺陷检测的翻车现场,八成在数据环节。常见开源PCB缺陷数据集给出的标注格式不统一,有的把缺陷坐标放在JSON里,有的按VOC的XML组织,还有的是模板差分后的坐标映射表,直接丢给YOLO命令是读不进去的。我一般拿到数据后第一件事不是急着训练,而是把所有标注转成YOLO需要的txt格式,再通过可视化脚本逐张确认框和缺陷确实对得上。

2.1 从任意标注格式到YOLO标签:一个自动转换脚本

先看一个最省事的转换场景:原始标注是CSV,每一行对应一个缺陷,列里有图像路径、缺陷类型、两个角点坐标。下面这段代码会把它们写成YOLO训练目录下的txt文件。

import os import pandas as pd from PIL import Image from pathlib import Path CLASSES = ['missing_hole', 'mouse_bite', 'open_circuit', 'short', 'spur', 'spurious_copper'] def convert_csv_to_yolo(csv_path, img_dir, out_dir): df = pd.read_csv(csv_path) for _, row in df.iterrows(): img_name = row['image_path'] img = Image.open(os.path.join(img_dir, img_name)) w, h = img.size # 用真实宽高做归一化基准 x1, y1, x2, y2 = row['x1'], row['y1'], row['x2'], row['y2'] # 夹紧到图像边界,防止坐标越界 x1 = max(0, min(x1, w - 1)) x2 = max(0, min(x2, w - 1)) y1 = max(0, min(y1, h - 1)) y2 = max(0, min(y2, h - 1)) cx = (x1 + x2) / 2 / w cy = (y1 + y2) / 2 / h bw = (x2 - x1) / w bh = (y2 - y1) / h # 过滤掉无效框 if bw <= 0 or bh <= 0: continue cls_id = CLASSES.index(row['defect_type']) label_path = Path(out_dir) / (Path(img_name).stem + '.txt') with open(label_path, 'a') as f: f.write(f"{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}\n")

这段代码有几个细节不能省。用图像真实宽高归一化,而不是把坐标缩放到某个固定尺寸,因为后面训练时imgsz会统一做resize,标签只要保持相对比例就不会错。夹紧坐标这一步看着多余,但很多标注工具会把框略微画出图像边界,留着会在训练早期让边界框回归出现奇怪的数值。过滤掉宽或高小于1像素的框,是为了排除标注软件产生的零碎点。

转换完成后,我习惯把图像按images/train、images/val、labels/train、labels/val组织,YOLO的detect训练会自动按data.yaml里的路径找标签。划分时按图像名随机打散,注意同一块PCB拼板上的多张局部图要放进同一个集合,否则板面特征泄露到验证集,最后报告的mAP会偏乐观。

2.2 整理成“yolov8训练自己的数据集”需要的data.yaml:类别平衡与增广参数

数据转成txt后,下一步是写data.yaml。这里最容易被忽略的是类别名称顺序和训练代码里的CLASSES顺序必须一致。如果你的数据里短路样本有600张,毛刺样本只有80张,直接开训会出现训练多个epoch后毛刺类AP仍然是0的情况。这种不平衡在PCB数据集里极其普遍,因为断路、短路往往是大面积缺陷,鼠标咬伤和多余铜皮则是小面积缺陷,样本数量天然不对等。

path: ./PCB_dataset train: images/train val: images/val nc: 6 names: 0: missing_hole 1: mouse_bite 2: open_circuit 3: short 4: spur 5: spurious_copper

类别不平衡的常见做法是先把少样本类别复制两三轮,再配合在线增广让网络看到的是“做过随机扰动”的样本,否则复制出来的像素完全一致,模型会把重复样本原样背下来。如果你不想改数据文件,也可以在训练命令里直接覆盖增广相关超参:

yolo detect train \ model=yolov8s.pt \ data=./PCB_dataset/data.yaml \ imgsz=640 \ epochs=150 \ batch=16 \ degrees=2.0 scale=0.2 translate=0.1 \ hsv_h=0.01 hsv_s=0.2 hsv_v=0.2 fliplr=0.5

这里特别提醒:degrees别设太大。PCB是刚性板,产线上有定位治具,角度偏移通常很小,设成90甚至180会让模型学到“板子什么角度都有”,实际检测时反而对小缺陷的位置更不敏感。hsv_h也要压低,PCB板面颜色稳定,色相扰动太大等于给每个缺陷换了一层滤镜,最后部署到真实相机下会对颜色变化过于敏感。

2.3 做一次可视化清洗:哪些标注反而是负样本

标注格式正确不等于标注质量好。PCB缺陷和走线颜色非常接近,人眼都要仔细看,标注软件里很容易出现框偏了、框大了、同一个缺陷重复标的情况。我一般写好转换脚本后,会再写一个画框脚本随机抽查每个类别至少十张图。

import cv2 from pathlib import Path def draw_labels(img_path, label_path, names): img = cv2.imread(str(img_path)) h, w = img.shape[:2] for line in Path(label_path).read_text().strip().splitlines(): cls_id, cx, cy, bw, bh = line.split() cls_id = int(cls_id) cx, cy, bw, bh = map(float, (cx, cy, bw, bh)) x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) color = (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, names[cls_id], (x1, max(0, y1 - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1) cv2.imshow('label check', img) cv2.waitKey(0)

检查时重点看三件事:框中心是否落在真实缺陷上;同一个缺陷有没有被重复标注;正常走线、过孔边缘有没有被误标成缺陷类。最后一条最隐蔽,因为有些标注员会把所有“看起来可疑”的区域都标进去,等于强行给模型喂了负样本。这一步是血泪经验,省掉它后面定位漏检会花几倍时间。

清洗数据的同时我会顺手统计所有框的宽高分布。如果大部分缺陷框小于16×16像素,训练输入就要往640以上走,否则在8倍下采样的特征图上,一个小缺陷可能只剩两个像素点,检测头根本拿不到足够信息。这个统计结果直接决定下一章的训练分辨率,比换网络结构更优先。

3. 用YOLOv8训练PCB缺陷检测模型:网络结构、超参与损失曲线

3.1 从yolov8网络结构图看小目标检测的瓶颈

YOLOv8的主干用C2f模块替换了YOLOv5的C3,C2f增加了更多分支连接,梯度流动更顺畅。对PCB这种走线密集的图像,深层语义很重要,但小缺陷往往在浅层特征上更明显。YOLOv8的neck是PAN-FPN,自顶向下和自底向上两条路径把浅层位置信息和深层语义做融合,这一步是检测小缺陷的关键。head则换成了解耦头,分类和回归分开,让训练收敛更稳。

理解网络结构后,最直接的产出是决定输入分辨率。YOLOv8下采样倍数到8、16、32,8倍特征图对应640输入就是80×80,一个16像素的缺陷在特征图上大约占2×2个点,勉强够用。如果大部分缺陷小于8像素,提高输入分辨率比改网络结构更靠谱,或者直接对原图做切块。

3.2 最小训练命令与关键超参数

数据准备完毕,训练命令并不复杂。以一张6GB显存的卡为例,我最常用的命令是:

yolo detect train \ model=yolov8s.pt \ data=./PCB_dataset/data.yaml \ imgsz=640 \ epochs=150 \ batch=16 \ device=0 \ degrees=2.0 scale=0.2 translate=0.1 \ hsv_h=0.01 hsv_s=0.2 hsv_v=0.2 fliplr=0.5 \ project=PCB_defect name=baseline

参数说明:model用yolov8s.pt预训练权重,COCO上的底层纹理对PCB仍有迁移价值,比从零训练收敛快。imgsz=640是速度和精度的折中,如果显存有12GB,可以提到960或1024。batch=16在6GB卡上跑yolov8s基本是上限,显存不够就降batch,而不是改小imgsz,因为对PCB小缺陷来说分辨率更关键。device=0指定第一张GPU,CPU环境改成cpu会慢很多,建议用云GPU或者Colab跑。

预训练权重不建议盲目上yolov8m或yolov8l。PCB缺陷数据通常只有几千张,m以上的模型参数量大,在小数据集上很容易过拟合,训练集loss降得很漂亮,验证集mAP反而更低。我一般先跑yolov8n做冒烟测试,确认数据没问题后再用yolov8s跑全量。

3.3 在三类可视化里定位训练问题:loss曲线、PR曲线与热力图

训练结束后的第一件事是看runs/detect/baseline/results.png,这就是标题里常说的yolov8画损失函数曲线图。文件里包含box_loss、cls_loss和dfl_loss三条曲线,如果150轮训练里三条曲线都在稳定下降,说明模型在学;如果cls_loss先降后升,多半是过拟合或者标签里有噪声。这时应该回到数据清洗而不是加训练轮数。

第二件事是看每个类别的AP,不要只盯mAP。PCB缺陷检测里,小类别如mouse_bite经常只有其他类一半的AP,这是类别不平衡的直接表现。按类AP拉出来,哪个类低就优先补哪个类的样本。

第三件事是看热力图。YOLO官方没有一键生成Grad-CAM的命令,常见做法是用PyTorch hook把backbone最后一段特征图取出来,再做通道均值叠加。下面的代码是核心思路:

import torch from ultralytics import YOLO model = YOLO('PCB_defect/baseline/weights/best.pt').model model.eval() feat_maps = {} def hook_fn(name): def hook(module, inp, out): feat_maps[name] = out.detach() return hook # 先打印model.model,找到SPPF所在层索引再注册hook print(model.model) target = model.model[8] # 以实际打印结果为准,常见是SPPF target.register_forward_hook(hook_fn('sppf')) img = torch.randn(1, 3, 640, 640) with torch.no_grad(): model(img) feat = feat_maps['sppf'][0] # [B, C, H, W] heatmap = feat.mean(dim=0).squeeze()

这段代码里的注释是重点:不同版本的YOLOv8模型内部层索引可能不一样,直接抄[8]不保证每次都指向SPPF。先打印model.model确认,把索引改成实际位置。拿到的heatmap需要min-max归一化到0-255,再叠到原图上。如果热力图高亮区域集中在PCB板边缘而不是缺陷本体,说明模型学到的可能是“板子位置”,这时候要去查标注框是否包含了太多背景。

4. 把训练好的模型做成PCB缺陷检测系统:接口封装与部署落地

4.1 先用一段Python代码把YOLOv8封装成检测函数

系统开发的第一步是写一个稳定的检测函数,把模型加载、推理、结果序列化全部包进去。这样后面接Web接口、接GUI、接产线程序都复用同一段逻辑。

from ultralytics import YOLO import json def detect_pcb_defects(model_path, img_path, conf=0.25, iou=0.45): model = YOLO(model_path) results = model.predict( source=img_path, conf=conf, iou=iou, imgsz=640, device='cpu' ) out = [] for r in results: boxes = r.boxes if boxes is None: continue for box in boxes: x1, y1, x2, y2 = box.xyxy[0].tolist() cls_id = int(box.cls[0]) score = float(box.conf[0]) out.append({ "bbox": [x1, y1, x2, y2], "class_id": cls_id, "class_name": r.names[cls_id], "confidence": round(score, 4) }) return json.dumps(out, ensure_ascii=False)

这个函数里device='cpu'只是为了方便测试,实际生产环境改成'cuda:0'。conf参数在PCB场景不建议设高,小缺陷的置信度天然偏低,我一般设到0.1,宁可在后处理里多保留几个候选框,也不要漏掉一块问题板。iou保留默认0.45,如果你发现两条靠得很近的独立缺陷被合并成一个框,就把iou调到0.3。

另一个要点是模型加载。上面的写法每调一次就加载一次权重,在频繁检测的产线里完全不可接受。实际封装成类时,把YOLO对象初始化到类的__init__里,进程运行期间只加载一次。

4.2 用FastAPI提供HTTP检测接口

一个常见的系统形态是:产线相机拍照,图像通过HTTP POST到检测服务,服务返回JSON结果。FastAPI写这种接口很快,异步接收文件和同步推理也够用。

from fastapi import FastAPI, UploadFile, File import numpy as np import cv2 from ultralytics import YOLO app = FastAPI() model = YOLO('PCB_defect/baseline/weights/best.pt') @app.post("/detect") async def detect(file: UploadFile = File(...)): data = await file.read() img = cv2.imdecode(np.frombuffer(data, np.uint8), cv2.IMREAD_COLOR) results = model.predict(source=img, conf=0.1, iou=0.3, imgsz=640) boxes = results[0].boxes defects = [] if boxes is not None: for box in boxes: defects.append({ "bbox": [int(v) for v in box.xyxy[0].tolist()], "class": results[0].names[int(box.cls[0])], "conf": float(box.conf[0]) }) return {"status": "ok", "defects": defects}

这段代码的关键坑在图像解码部分。cv2.imdecode读进来是BGR,而ultralytics训练时内部按RGB预处理,只要把numpy数组直接传给model.predict,它内部会做转换,这里不要手动转RGB,否则颜色通道反了,检测结果会灾难性下降。FastAPI用uvicorn启动后,单机并发足够几十台相机轮流调用,如果检测耗时太长,优先检查是不是每张图都触发了GPU显存重新分配。

4.3 边端部署到RK3588:yolov8转ONNX再转RKNN

这几年很多项目会把检测放到产线边缘设备,RK3588因为带NPU,功耗比整台工控机低很多,适合嵌入到检测机台里。部署路径是先把YOLOv8导出成ONNX,再用RKNN工具链转成rknn格式。导出命令如下:

yolo export model=PCB_defect/baseline/weights/best.pt \ format=onnx imgsz=640 opset=11

导出时opset别拉太高,RKNN-Toolkit2对opset 11附近支持比较稳。转换成rknn用的是RKNN工具链自己的脚本,不同版本参数差异很大,我在这里只强调两个最常踩的点:输入尺寸固定为640×640,不要开动态shape;导出前确认模型输出节点名字,RKNN转换报错里说的“shape mismatch”八成是输出节点没对齐。

RKNN最影响精度的是量化。转换时要用一批校准图片,calibration.txt里每一行是图片路径,这些图片必须从你训练集里选,并且一定要覆盖所有缺陷类别。如果校准集只放了几十张正常板,量化后模型输出很可能和小缺陷相关的通道全部丢失。转换完成后,先拿一张训练图跑一次RKNN推理,对比PyTorch浮点模型的输出,如果某个类置信度掉得特别明显,就扩充这个类的校准图,或者考虑把检测头部分留在浮点计算。

提示:RKNN转换脚本和工具链版本强相关,我写的命令是简化示意,实际以你安装的RKNN-Toolkit2官方手册为准。

5. 训练与部署中的避坑:5个把PCB缺陷检测做翻车的真问题

5.1 现象:mAP不低,但产线漏检空焊和虚焊

原因:训练数据主要是实验室样板,背景干净;产线板子有脏污、助焊剂残留、反光不均匀,模型没见过这类环境,所以验证集mAP好看,一到现场就漏。解决方法是到产线现场采集不良板,哪怕只有几十块,也要把它们加到训练集里。如果现场样本实在少,就把脏污区域单独截出来当作负样本参与训练,让模型学会把“脏但没坏”和“真坏了”区分开。做这类项目时我在验证集之外单独留一个“现场测试集”,不在训练调参阶段碰它,等系统上线前才用来评估真实性能。

5.2 现象:loss曲线还在下降,PR曲线却很差

原因:loss是多个类别的平均指标,多数类样本多,把整体loss拉低,少数类PR接近0也不会体现在总loss里。这种“假性收敛”在PCB缺陷数据集里很常见。解决方法是训练完成后按类别打印AP,定位到哪一个类最差。对少样本类别做复制加增强,或者干脆把模型预测结果里这一类别的阈值单独调低,让更多低置信度候选框进入最终结果。别只在全局mAP上纠结,类别级AP才是衡量产线真实覆盖率的指标。

5.3 现象:显存溢出,训练直接崩掉

原因:在6GB显卡上试图用imgsz=1280加batch=16,几乎必炸。解决方法是把batch降到4或2,或者换yolov8n。PCB小目标需要高分辨率,但高分辨率和高batch在显存上互相冲突。我的习惯是先按当前显存算一个保守组合,比如6GB配imgsz=960和batch=4,先跑通一轮再逐步加量。实在要维持大batch,就用梯度累积,但ultralytics CLI没有直接暴露这个参数,需要改训练循环,成本不低,不如降低batch增加epoch数。

5.4 现象:RK3588部署后,模型精度下降,且每次结果有波动

原因:量化和预处理不一致。YOLOv8导出时默认做了归一化,RKNN推理输入可能要求0-255的RGB,也可能是RGB与BGR未对齐,输出结果就会忽高忽低。解决方法是写一个对比脚本,同一张图分别在PyTorch和RKNN上跑一遍,逐元素比对输出tensor的数值量级和通道顺序。如果数值量级差十倍以上,先改输入归一化方式;如果只有个别通道有差异,检查BGR/RGB;如果全都在0.5左右浮动,检查量化校准集是否覆盖了缺陷类别。

5.5 现象:同一张图,Python检测和部署端检测结果不一样

原因:图像预处理不一致。训练时用letterbox把长边缩放到640,短边填充灰色;部署端直接cv2.resize强行拉成640×640,宽高比变了,检测框位置自然就不对。这是最常被忽视的“玄学”,其实一点不玄。解决方法是复现ultralytics的letterbox逻辑,从源码里把letterbox函数抠出来放到部署代码里,保持填充颜色一致。我踩过这个坑以后,凡是部署端接模型,第一件事就是确认预处理函数和训练时完全相同,而不是拿一张图测到看起来正常就上线。

6. 毕业论文实验设计:让YOLOv8的结果在论文里立得住

6.1 三个实验对照组,别只放一张mAP表

毕业论文的评审最看重三张表:不同YOLO版本对比、不同输入分辨率对比、是否使用数据增强的消融。固定同一份数据划分,跑yolov8n、yolov8s、yolov8m三个权重,记录mAP@0.5和mAP@0.5:0.95。然后用最优模型把imgsz从640提到1024,看小类别AP的变化。最后在最优条件下关掉Mosaic、关掉色彩增强,各跑一次,证明你的增广策略确实有效。这三组实验做完,论文的“实验与分析”章节就立住了。

6.2 一个小技巧:用tiling切图提升小目标检测AP

PCB板上的小缺陷很密集,直接提到1024分辨率对显存不友好。一个常见做法是把大图切成512×512的块,带少量重叠,每个块单独过模型,最后再把框映射回原图坐标。这样模型看到的相当于放大的缺陷,AP提升比改网络结构更直接。

def tile_image(img, tile_size=512, overlap=64): h, w = img.shape[:2] tiles = [] step = tile_size - overlap for y in range(0, h, step): for x in range(0, w, step): y2 = min(y + tile_size, h) x2 = min(x + tile_size, w) if y2 - y < tile_size or x2 - x < tile_size: continue tiles.append(img[y:y2, x:x2]) return tiles

这个切图函数是最简版本,实际使用时要同步切标签、计算box在新图里的相对坐标,推理后还需要通过重叠区域做去重。论文里把它写成“基于切图的检测策略”,会比单纯调参更有工程说服力。我自己的习惯是在论文里放一组badcase,不只展示检测正确的图,也展示漏检图并分析原因。这种认账的写法反而让评审相信你的系统是一个真实闭环。希望帮到你。

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

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

工业级Agent实战:从工具调用到目标驱动的范式跃迁

1. 这不是又一篇“Agent科普文”&#xff0c;而是我踩了17个坑后画出的实战路线图“Agent论文和工业界实战总结&#xff08;1&#xff09;&#xff1a;从工具到伙伴的范式跃迁”——这个标题里藏着三个被严重低估的关键词&#xff1a;范式跃迁、工业界、实战。不是“概念演进”…

作者头像 李华
网站建设 2026/10/6 6:26:34

华为防火墙综合配置案例:从校园到金融中心的现网实战

简介&#xff1a;这是一份华为防火墙综合配置案例官方技术文档&#xff0c;面向负责配置和管理防火墙设备的网络管理员&#xff0c;帮助读者在典型项目场景中掌握FW&#xff08;USG/Eudemon系列&#xff09;的配置方法。资源为单个PDF文件&#xff0c;大小4.88MB&#xff0c;采…

作者头像 李华
网站建设 2026/10/6 6:25:17

给WorkBuddy装个Skill,5分钟生成PPT:AI技能配置实战指南

我偷偷给WorkBuddy装了个技能后&#xff0c;5分钟出PPT&#xff1a;同事以为我开了外挂先说个场景。上周三下午&#xff0c;领导临时通知第二天早上要交一份季度复盘PPT&#xff0c;二十几页那种&#xff0c;还要带数据图表和结论页。我当时手头还压着两个需求没提测&#xff0…

作者头像 李华
网站建设 2026/10/6 6:25:02

华为云昇腾服务部署DeepSeek:从MindIE原理到生产级实践

简介&#xff1a;这份PDF系统分析了在华为云昇腾云服务上部署DeepSeek大模型的技术特点与应用场景&#xff0c;面向人工智能工程师、云计算架构师以及需要将大模型能力落地的企业技术团队。内容从昇腾处理器的并行计算能力与算力调度优势讲起&#xff0c;详细介绍了灵活的算力调…

作者头像 李华
网站建设 2026/10/6 6:24:48

AI写代码总翻车?字段级Spec让大模型一次生成可用代码

我前阵子接了个活儿&#xff0c;想让 AI 帮我写一个“客户信息管理模块”。我当时觉得这需求够清楚了吧&#xff0c;五个字&#xff0c;一句话&#xff0c;丢给 AI 就能出代码。结果它给我生成了一堆看起来运行正常、实际上完全没法用的东西&#xff1a;电话字段允许输入“abc”…

作者头像 李华
网站建设 2026/10/6 6:24:19

网络103规约解析:报文格式、四遥调试与点表映射实战

简介&#xff1a;以南瑞继保网络103规约为核心的协议资料&#xff0c;面向电力系统自动化工程师、远动调试人员及对IEC 60870-5-103扩展实现感兴趣的技术学习者&#xff0c;可应用于调度中心、集控站与RTU之间的数据通信场景。压缩包内共1个doc文档&#xff0c;大小3.38MB&…

作者头像 李华