把摄像头架在回收料斗上方,让系统自己分辨掉进传送带的是PET饮料瓶还是PP餐盒,是HDPE洗发水瓶还是PS泡沫箱,然后告诉分拣机械手“该往哪个料仓扔”——这就是基于YOLOv8的可回收塑料识别分类检测系统在做的事。如果你正好在搞智能回收设备、垃圾分类终端,或者只是想把深度学习模型落地成一个带界面的正经项目,这篇内容应该能帮你少走不少弯路。围绕它要讲清楚的不只是训练一个模型,还包括数据集怎么攒、标注怎么定、UI怎么接、实机运行会踩哪些坑,我尽量照着实际动手的顺序说。
1. 为什么要把“可回收塑料识别”做成一个视觉检测系统
1.1 垃圾分类环节的真实痛点
塑料回收行业有一个不算新鲜但一直没被彻底解决的问题:分拣效率卡在“材质识别”这一步。饮料瓶、洗发水瓶、外卖餐盒、塑料袋、泡沫箱堆在一起,表面上都是“塑料”,但PET、HDPE、PP、LDPE、PS这几种材质的回收处理路径完全不同。热熔温度不一样,再生造粒品质不一样,收购价也不一样。一旦混料,整批再生料的品级可能直接降档,损失远比想象中大。
人工分拣能解决一部分问题,但流水线上的工人需要长期辨认瓶底的材质标识,速度、注意力、用工成本都是瓶颈。用传统图像处理去识别?光照一变就崩,瓶身印刷图案一多就分不清,基本不可行。所以把基于深度学习的YOLOv8检测模型放到这套场景里,本质上是让机器学会“看一眼就知道是哪类塑料”,再配合硬件去执行分拣动作。
我做过的类似项目中,真正有价值的不是“识别得有多准”这个单点指标,而是整套系统能不能在环境变化、样本分布变化之后依然稳定工作。这决定了它是个毕业设计Demo,还是一个能放进车间试运行的样机。
1.2 用YOLOv8来做这件事,整体方案长什么样
整个系统可以拆成四个模块:数据集模块、模型训练模块、后端推理模块、UI展示与控制模块。数据集模块负责采集塑料瓶罐图片并按YOLO格式标注;模型训练模块用YOLOv8在GPU上训练出权重文件;后端推理模块负责加载模型、对图片或摄像头帧做检测;UI模块把结果可视化,比如框出物体、显示置信度、统计各类别的数量。
我一开始把重心放在模型精度上,后来发现整个项目真正难的不是杀进99%准确率,而是从“模型跑通”到“整个系统能用”之间那一大段工程活。比如摄像头画面里的反光、塑料薄膜的半透明特性、瓶子堆叠导致的目标重叠遮挡,这些都是训练时经常被忽略、实机运行时躲不掉的麻烦。
系统方案的另外一条主线是“先离线后实时”。离线阶段处理静态图片、统计识别准确率;实时阶段接入摄像头或视频流,让UI界面连续显示检测结果。先保证离线可用,再谈实时性能,这个顺序能避免很多无意义的调试。
2. YOLOv8的选型逻辑:对比其他检测方案,它凭什么合适
2.1 主流检测算法对比:更快、更容易落地
可回收塑料识别本质上是一个目标检测任务,不是图像分类任务。我要的是同时知道“画面里哪里有塑料”“它属于哪一类”,而不是只给整张图贴一个标签。可选的检测方案主要有几类:两阶段检测器、单阶段检测器、以及更轻量的分类加定位方案。
两阶段检测器(以Faster R-CNN为代表)精度高,但推理速度慢,摄像头实时场景下帧率很难上去。传统图像处理加分类器的方案速度可以,但塑料瓶表面印刷、反光、形变一多就彻底失效。
YOLO系列属于单阶段检测器,特点是一次前向推理同时输出目标框和类别,速度和精度的平衡点抓得很好。尤其YOLOv8相比前代在结构上更简洁,上手门槛低,官方工具链完善,对于做应用系统而不是搞算法创新的人来说,属于“拿来就能用”的选择。
对比结论很清楚:
| 方案 | 精度 | 实时速度 | 工程难度 | 适用场景 |
|---|---|---|---|---|
| Faster R-CNN | 高 | 慢 | 较高 | 对速度不敏感的离线检测 |
| 传统图像处理 | 低 | 快 | 低 | 背景固定、目标规范的简单场景 |
| YOLOv8 | 高 | 快 | 中 | 可回收塑料实时识别分类 |
2.2 模型规模怎么选:从YOLOv8n到YOLOv8x
YOLOv8官方提供了n/s/m/l/x五种规格。它们用同一套代码和训练流程,但网络宽度、深度不同,参数量和推理耗时也不同。这里给出一个我在实际项目中感受比较直观的对比:
| 模型 | 模型体积 | 推理速度 | 精度 | 适用场景 |
|---|---|---|---|---|
| YOLOv8n | 约6MB | 最快 | 够用 | 嵌入式设备、边缘盒子 |
| YOLOv8s | 约22MB | 快 | 较好 | 常规摄像头实时检测 |
| YOLOv8m | 约49MB | 中等 | 好 | 精度优先的实时检测 |
| YOLOv8l | 约83MB | 较慢 | 更好 | 服务器推理 |
| YOLOv8x | 约168MB | 慢 | 最好 | 离线批量识别 |
塑料检测的场景通常没有极端的小目标需求,但瓶盖、瓶身上的小标签算得上是“中小目标”,需要模型有一定特征提取能力。我建议起步用YOLOv8s,它既保证了摄像头实时帧率,又给精度留了余量。如果你用的是一块中高端显卡或者只需要处理静态图片,上m甚至l规格也没有问题。
实机测试时注意一件事:模型体积增大带来的精度提升在到达某个阈值后会变得非常有限。我曾见过有人把规格从s换成x,mAP只涨了不到一个点,推理速度却掉了一半。不是越大越好,而是要在你的算力和实时性约束内选最合适的。
2.3 识别结果如何定义:先定类别体系而不是先写代码
训练之前最容易被低估的一步是定义“到底识别哪几类”。塑料材质类别可以在树脂代码层面区分得很细,但实际检测系统不可能也不需要对每一个树脂牌号都建模。我采用的做法是按“回收分拣的终端去向”来定类别,这样一套系统做出来真的能被回收线使用。
我常用的一套类别定义如下:
- PET:常见饮料瓶、矿泉水瓶
- HDPE:洗护用品瓶、奶瓶、部分药瓶
- PP:餐盒、饮料杯、打包盒、硬质容器
- LDPE:塑料袋、保鲜膜包装
- PS:泡沫箱、泡沫餐盒
- 其他硬塑料:玩具壳、外壳等无法简单归入上述类别的硬质塑料
类别数量控制在5到8类比较合适。类别太少,现场分不出来毛;类别太多,每类的样本量不够,反而拉低整体精度。这里的原则是“分类粒度对齐回收产线的实际料仓数量”,而不是对齐学术论文里的细粒度分类。
3. 数据集的构建与标注:模型的上限由这里决定
3.1 数据采集策略:真实环境 > 网图
很多新手同学习惯从开放数据集或者搜索引擎爬图来做训练集,这种做法跑通Demo可以,做正经系统非常危险。网图里往往是“摆拍”过的干净背景,瓶子规规矩矩立在画面中央,而真实回收线的图片是乱七八糟的:瓶瓶罐罐互相遮挡、传送带运动模糊、灯光反光、标签磨损、瓶身扭曲。
我建议的数据采集优先级是:
- 自己架摄像头拍:覆盖不同光照(白天、夜间、强光)、不同角度(俯视、侧视)、不同背景(传送带、桌面、回收袋)。
- 找现场运行视频抽帧:把一段时间内的摄像头录像每隔几秒抽一帧,能低成本拿到大量真实姿态样本。
- 补充公开图片:只用于丰富背景多样性,不能作为主力。
目标是把“目标出现在画面中的各种状态”都覆盖到。一个瓶子平躺、竖立、倒扣、被压扁之后的形态差异非常大,只拍规整摆放形态会让模型的泛化能力很差。
3.2 标注规范:不要跨类别、边界框要贴合
数据采集完成后,进入标注环节。YOLO格式要求为每张图生成一个同名的txt文件,每行记录“类别ID 中心点x 中心点y 宽度 高度”,坐标值均归一化到0到1之间。这个格式本身不复杂,真正的坑在标注规范。
我踩过最大的教训是标注不统一。第一次标注时,有的标注员把整个塑料瓶画进框,有的只画瓶身主体。结果模型训练出来之后,预测框一会儿大一会儿小,评测指标看起来还行,实际用起来边界很飘。
后来我定了三条硬规则:
- 边界框必须框住物体的可视主体,如果是透明瓶子,框住整个轮廓而不只是瓶身部分。
- 物体被遮挡超过一半时,不标注;遮挡小于一半时,只框可见部分。
- 一张图里同类物体密集堆放时,允许漏标极少数小目标,但不允许把一个瓶子画到另一个瓶子的框里。
这三条规则看似简单,却能显著减少训练时的标签噪声。标注工具我用的基于Python的开源标注工具,支持YOLO格式导出,用起来足够顺手。一个中等规模的数据集(几千张图),两三个人几天内就能完成。
3.3 数据增强和数据集的目录组织
数据增强不能只依赖YOLOv8内置的在线增强(Mosaic、翻转、HSV扰动等),离线增强也要做一部分,尤其是针对塑料识别场景特有的几种变化:旋转(瓶子可能在传送带上以任意角度进入视野)、亮度变化(光照强度不稳定)和镜像翻转。
我通常会在离线阶段对原始图片做一次水平翻转、90度旋转、亮度随机的增强副本,把数据集规模扩充2到3倍。离线增强之后,YOLOv8训练时还会做Mosaic等在线增强,效果叠加,模型对场景变化的鲁棒性会明显提高。
数据集目录必须严格遵循YOLO工具链约定的结构:
plastic_dataset/ train/ images/ labels/ val/ images/ labels/ data.yamldata.yaml里的内容大致是这样的:
path: ./plastic_dataset train: train/images val: val/images names: 0: pet_bottle 1: hdpe_bottle 2: pp_container 3: ldpe_bag 4: ps_foam 5: other_plastic训练集和验证集的比例建议8:2,划分时注意不要让同一场景的连续帧全部落在训练集或验证集里。要把它们打乱后随机分配,否则验证集里全是与训练集几乎相同的画面,mAP会虚高,完全没有参考价值。
4. 模型训练实战:参数、过程与性能提升
4.1 安装与环境配置:这一步的坑
训练YOLOv8需要Python环境、PyTorch和GPU支持。我的常规配置是Python 3.10、CUDA 11.8以上、PyTorch 2.x,然后在Python环境中安装ultralytics库和opencv-python。
最容易被卡住的地方是PyTorch与CUDA版本的匹配问题。我建议先确认显卡驱动支持的CUDA版本,再安装对应的PyTorch版本,不要直接装CPU版凑合,那样训练速度会慢到怀疑人生。
安装完成之后,用一条命令验证GPU可用:
python -c "import torch; print(torch.cuda.is_available())"如果是True,说明环境OK。如果False,大概率是PyTorch版本和CUDA驱动版本不匹配。
4.2 训练命令与超参数解读
准备好数据集后,最简单的方式是直接写一个Python训练脚本:
from ultralytics import YOLO # 加载预训练权重,这里用s规格起步 model = YOLO("yolov8s.pt") results = model.train( data="plastic_dataset/data.yaml", epochs=100, imgsz=640, batch=16, device=0, workers=4, lr0=0.01, patience=20, seed=42, )这些超参数每一个都值得说清楚:
imgsz=640:YOLOv8默认输入尺寸。图片会等比缩放后填充到640×640,这是精度与速度的平衡点。盲目拉大到1280对塑料瓶这种中等目标提升有限,但推理耗时翻倍。epochs=100:我用100轮作为基准。如果训练曲线还在明显下降,就继续加;如果早就收敛了,就提前结束。batch=16:受限于显存,16是一个稳妥的数字。batch太小容易导致训练不稳定,太大则显存不够。patience=20:早停机制,连续20轮验证集指标没有提升就停止训练,防止过拟合。lr0=0.01:初始学习率。YOLOv8内部有学习率调度,大部分场景不需要手动调整。
训练过程中需要重点观察两个指标曲线:train/loss和val/loss。如果训练loss持续下降但验证loss反而回升,说明过拟合了,需要增加数据增强或者提前停止。
4.3 训练曲线怎么读:过拟合与类别不平衡
一个常见现象是总体mAP不错,但某几个类别(通常是塑料袋LDPE或者PS泡沫)的精度特别低。原因通常是两类问题:样本量不足,或者样本形态复杂度太高。
塑料袋是这里面最难识别的类别。它本身是半透明的,卷起来、摊开、团成球之后的外观完全不一样,人工标注时连“边界在哪”都不容易判断。PS泡沫箱虽然外观特征明显,但表面容易被胶带、商标覆盖,训练样本如果不够丰富,模型很容易把泡沫箱和普通纸箱混淆。
我处理类别不平衡的办法是给难分类别加样本权重。YOLOv8支持配置class_weights,也可以更粗暴地增加该类别在数据集中的占比:去现场多拍、多做增强、反复标注。单纯调阈值无法解决本质问题,特征没学到位,调阈值只是拆东墙补西墙。
还有一个非常容易被忽略的点:视频抽帧得到的训练集里,连续帧高度相似,相当于有效样本量缩水。我通常会对抽帧后的图片按画面相似度做去重,保证训练集多样性,这一步做完后模型提升非常明显。
4.4 模型导出:从pt到ONNX的选择
训练结束后,模型会保存为best.pt。但如果只做Python推理,这个文件就够用了。需要接入C++、或者用OpenVINO、TensorRT加速时,需要导出为相应格式。
我最常用的导出方式是转ONNX:
yolo export model=best.pt format=onnx imgsz=640ONNX的好处是跨平台、跨语言,在多数边缘设备上可以直接做CPU推理。实时性要求极高的场景可以进一步转成TensorRT引擎,但TensorRT部署依赖显卡型号,灵活性差一些,通常只在固定的工控机上使用。
这里提醒一句:导出的ONNX模型在框架内置的验证脚本里跑分通常和PyTorch模型几乎一致,但接入自己写的推理代码后,需要留意预处理方式是否一致。YOLOv8训练时用的是RGB图、像素归一化到0-1、resize到640×640,如果推理时用BGR、或者直接用原图尺寸,结果会明显变差。
5. UI界面整合:把模型变成别人也能用的系统
5.1 技术选型:Web界面还是桌面界面
UI界面的作用不只是“好看”,而是让一个不懂Python和命令行的人也能操作系统:导入图片、点击识别、查看结果。可回收塑料检测系统的实操场景分两种,对应的UI选择也不同。
如果系统运行在一个带有摄像头的回收设备上,操作人员需要看实时画面,我推荐用桌面程序,比如基于Python的PyQt5或Pyside6。响应快、不依赖浏览器、能直接调用本地摄像头。
如果系统只是作为后台服务运行,供管理员在电脑上查看识别统计,用Web界面更合适。我常用的方案是Streamlit或Gradio,它们能用很少的代码生成一个可交互页面,省掉大量前端工作。
我实际用一个基于Streamlit的Web界面做过整套演示系统,核心代码量很短:
import streamlit as st from ultralytics import YOLO model = YOLO("best.pt") st.title("可回收塑料识别分类检测系统") uploaded_file = st.file_uploader("上传待识别图片", type=["jpg", "png", "jpeg"]) if uploaded_file is not None: image_bytes = uploaded_file.read() results = model.predict(source=image_bytes, conf=0.4) annotated_frame = results[0].plot() st.image(annotated_frame, channels="BGR", caption="识别结果")这个页面能直接把图片里的塑料检测出来并画框显示,几分钟就能跑通。但它的局限在于无法很好地做连续视频流检测。如果要做摄像头实时检测,建议用一行代码开启摄像头预测:
results = model.predict(source="0", show=True, conf=0.4)5.2 核心功能设计与界面分区
要把UI做得可用,不只是识别一张图片。我建议UI至少包含下面几个区域:
- 识别区:图片/视频流的展示与检测结果叠加显示。
- 结果统计区:显示每个类别的检测数量、置信度均值,最好附一张柱状图。
- 参数调节区:置信度阈值、检测类别的开关。这个在实际调试中非常有用,因为不同场景下最优阈值完全不同。
- 控制区:开始识别、停止识别、保存当前帧、导出统计报表。
置信度阈值这个参数别小看。回收产线上如果更看重召回,可以把阈值调低到0.3,宁可多框出来一些错误框,也不漏掉目标;如果更看重准确率,就调到0.5以上,减少误报。UI里一定要留出这个调节入口。
我之前调试过的一个场景里,系统挂在传送带上方,瓶瓶罐罐快速连续经过。用纯图片识别时效果很好,但到了连续视频流里,模型每一帧都在做推理,如果没有做帧间隔控制,UI界面会卡得很厉害。解决办法也很简单:设定每2到3帧推理一次,中间帧直接复制上一帧的结果,对最终分拣效果几乎没有影响。
5.3 程序接口设计:模型推理与业务逻辑解耦
UI代码里尽量不要直接混在一起写模型加载、推理、显示逻辑。我习惯把程序拆成三个文件:
model_loader.py:负责加载权重、封装预测函数,返回检测框、类别、置信度等结构化结果。ui_app.py:负责界面布局和交互,调用模型接口。utils.py:负责画框、统计数量、格式化结果。
这样做的最大好处是换模型或换UI时不需要改动其他部分。后续把模型升级为YOLOv8x、或者把Streamlit换回PyQt5,只改对应模块即可。对长期维护来说,这个拆分能省下大量的重复开发和调试时间。
6. 实测中的意外情况与调优记录:比训练更磨人的事
6.1 一个让我重新标了三天数据的案例
训练第一版模型时,我拿到的场景是室内固定光照,摄像头俯视桌面,瓶子一个一个被放上台面,背景干净,分类效果一度让我非常满意。我以为这套系统已经稳了,直到把它挪到另一台实际设备上测试,发现HDPE类别的检测框开始乱跳,甚至把一支圆珠笔认成了塑料瓶。
排查半天,问题不在模型结构,而在训练数据:原始数据集里,HDPE类塑料瓶很多是白色瓶身,而圆珠笔也是白色圆柱体,两者的轮廓、颜色、尺度在画面里极其相似。模型学的并不是“材质”,而是“白色圆柱物体”这个表象。
解决思路不是简单加负样本,而是重新梳理了HDPE类别的图片:加入了大量不同颜色、不同形状的洗护瓶数据,同时把类似形状的非塑料物体样本也加入训练集,作为背景负例。中间还补拍了一批带标签和瓶盖纹理的特写。前前后后重新标注了三天,模型在这个类别上的误检率才真正降下来。
这个案例让我清楚了一件事:做分类检测系统,首先要承认视觉模型分不清材质,它只能通过外观特征去推断。所以你的数据里必须包含足够多的“迷惑项”,模型才能学会分辨。
6.2 反光、遮挡、小目标:塑料场景特有的识别陷阱
塑料材质有两个天然麻烦:反光和半透明。反光会导致瓶身局部过曝,如果这一块区域刚好是模型用来分类的纹理特征,识别结果就可能翻车。半透明物体(比如矿泉水瓶)的边缘和背景融为一体,检测框会忽大忽小,置信度也普遍偏低。
针对反光,我试过加偏振镜片滤除偏振光,效果很好,但不是所有场景都具备安装条件。软件层面能做的补偿有两项:一是训练数据里尽量多包含强反光和镜面反射样本,让模型见过“亮瞎眼”的瓶子;二是推理时对图像做一次高光区域识别,把过曝区域的像素适当压暗,恢复部分纹理信息。
目标重叠遮挡在小瓶罐密集通过的传送带上尤其严重。一个瓶子被另一个瓶子挡住一半时,人工标注都未必标得准。我之后专门对遮挡场景做了优化:把一些正常图片中的物体随机擦除一部分,用这种增强方式模拟遮挡,让模型学会利用“可见的那一半”来完成识别。
6.3 真实项目上线前还要做的三件事
如果这套系统要在真实产线上运行,有几点是实验室阶段几乎不会遇到,但现场必须有预案的:
第一,模型更新机制。现场数据会不断出现训练集里没有的新瓶型,系统需要一个定期收集现场图片、增量标注、重新微调的流程。不能训练完就锁死权重,三个月后肯定失灵。
第二,性能监控。不要只看单张图片的准确率,要在系统里记录每天的识别总数、各类别置信度分布、误检率,定期分析。置信度分布整体下移往往说明来了新形态的样本,是模型需要更新的信号。
第三,容错处理。检测结果被用于自动分拣时,单帧误判可能导致一个瓶子进错料仓。实际方案通常需要在两次或三次连续帧里都识别为同一类别才执行分拣动作,用时序投票消除单帧偶然错误。
这些内容看起来并不“性感”,但它们是把一个视觉识别Demo变成一套可靠业务系统的关键。模型准确率提高一个点是在练肌肉,而容错和更新机制是在保证整个系统不会因为一次误判就产生经济损失。
最后再分享一个小技巧:在做可回收塑料识别的时候,别一开始就追求相机拍出来“好看”的效果。真正重要的是把摄像头架在目标即将被传送带送走的位置,让瓶子以最自然、最多样的姿态进入视野。多花一天在现场拍数据、观察光照,效果比多训50个epoch还要明显。模型终归是数据喂出来的,数据长什么样,模型就长什么样。