简介这是一套基于Python和YOLOv8开发的杂草检测系统源码面向农业智能化、计算机视觉及深度学习方向的开发者与研究者可解决农田杂草自动识别与定位问题助力精准施药与作物保护。项目采用含2427张图像的公开数据集覆盖作物与杂草两类目标图像经标注与增强处理后用于模型训练完整呈现从数据准备、模型训练到验证评估的流程。包内共24个文件其中4个Python脚本分别实现模型训练、验证、预测及UI交互展示19张图片为训练过程可视化与检测效果示例另有1份Markdown说明文档辅助快速上手整个压缩包约5.5MB轻量便携。目前已有77人学习下载。读者可借助源码快速搭建自己的杂草检测实验直接替换数据集即可迁移到其他目标检测任务并基于可视化界面进行实时演示具有较高的实战参考价值适合有一定Python与深度学习基础的读者。1. 一间温室里的翻车现场让我决定认真对待这套源码某次周末去一个朋友的温室帮忙看苗他抱怨人工除草成本太高想用一个摄像头自动定位杂草。我当时随手拿通用目标检测的模型试了一天结果在田埂实拍视频里几乎什么都检不出来——杂草和作物都是绿色的叶子互相遮挡小苗只有几十个像素通用模型的黑匣子完全不适用。后来我换到基于 Python 和 YOLOv8 的杂草检测方案把数据、训练、推理整条链路重新走了一遍效果才真正立住。这套源码包解决的不是“能不能检测到绿色东西”而是“怎么在田间复杂背景下把杂草和作物分开”这个具体问题。它适合正在做精准除草、作物表型分析、田间监测相关项目的开发者也适合想用 YOLOv8 落地农业视觉但不想从零折腾数据格式和训练参数的从业者。如果你需要的是能直接投入现场验证的检测系统这套东西值得花一个下午跑通。2. 拿到源码包先做的事环境准备与目录结构2.1 用最小命令确认 YOLOv8 环境是否就绪杂草检测的训练和推理依赖 PyTorch 和 YOLOv8 的官方 Python 包环境装错是最常见的翻车点。我一般会先用 conda 建一个独立环境避免把系统 Python 搞乱。注意选择 Python 3.10 或 3.11兼容性比 3.12 更稳尤其是装 PyTorch 的时候。conda create -n weed_det python3.10 -y conda activate weed_det pip install ultralytics python -c import ultralytics, torch; print(ultralytics, ultralytics.__version__); print(torch, torch.__version__); print(cuda, torch.cuda.is_available())这段命令先创建并激活名为 weed_det 的虚拟环境再安装 ultralytics 包最后用一段 Python 代码打印库版本和 CUDA 是否可用。看输出时重点看最后一行如果 cuda 是 False说明 GPU 没接上后面训练会慢得让人怀疑人生。我通常还会顺便确认一下显卡驱动能不能被 PyTorch 识别如果 torch.cuda.is_available() 返回 False优先检查驱动和 PyTorch 安装版本是否匹配而不是急着改代码。CPU 也能训练小数据集但每轮耗时翻几倍强烈不建议用 CPU 跑完整的训练流程。2.2 先读源码目录这些文件才是这套杂草检测系统的骨架解压源码包之后第一步不是急着跑训练而是把目录结构摸清楚。这套杂草检测系统通常包含数据配置、训练入口、验证入口、推理入口和训练好的权重文件五类核心内容。我见过不少人直接双击 train.py 然后报错回头一看是路径没对应上。文件/目录职责落地时要注意的点data.yaml数据集配置路径要改成你本机的绝对路径train.py训练入口命令行参数优先改代码容易出错val.py验证入口用来算 mAP 和每类别的召回率detect.py推理入口支持图片、视频、摄像头weights/模型权重目录优先用 best.pt别用 last.ptdataset/图片与标注确保 train/val 子目录结构正确requirements.txt依赖清单与 ultralytics 版本强相关这套目录结构基本是 YOLOv8 工程的标准布局源码包只是把入口脚本提前封装好了。你不需要改动每个文件重点记住 data.yaml 是数据集的地图train.py 是训练的开关weights 是最终产物。理解了这个骨架后面所有步骤都是围绕这三个点展开的。2.3 用预训练权重跑通第一个推理验证整条链路在动训练之前先跑一次推理确认环境、模型加载、图像读写整条链路是通的。源码包一般会在 weights 目录里放一个训练好的权重文件如果没放先用 YOLOv8 官方预训练权重顶一下验证链路后再换自己的模型。推理入口通常长这样python detect.py --weights weights/best.pt --source dataset/sample.jpg --conf 0.3 --device 0这条命令把源图片丢给模型置信度阈值设为 0.3指定用 0 号显卡推理。conf 参数很关键田间场景杂草与背景对比度低阈值设太高会漏检设太低会满屏框。第一次跑通后把输出图片打开看一眼确认框的位置是否合理类别标签是否对应。如果这一步能正常输出带标注的图片说明环境、依赖、权重和输入输出全部就绪接下来才值得投入时间去准备数据和调参。我在这一步吃过亏当时直接跳过去训练结果训练到一半才发现 label 读取路径有问题白跑了一整夜。3. 数据准备把田间影像变成 YOLO 能读懂的标注3.1 先理解杂草检测的标注难点小目标、密集、背景脏杂草检测与常规目标检测最大的区别在于目标外观和背景高度相似。杂草和作物同为绿色纹理差异小且苗期杂草常常只有几十个像素大小。再加上田间光照变化、土壤反光、叶片遮挡直接套用 COCO 数据集训练出来的通用模型基本失效。这也是为什么源码包不能只给你一个模型文件数据准备环节才是决定精度的关键。我在标注田间数据时会把图片分辨率尽量控制在 1280 以上否则小目标在缩略图里根本看不清标注质量会大幅下降。标注工具方面常见的选择是 LabelImg 或 CVAT两者都能导出 YOLO 格式的 txt 标注文件。更具体地说标注时要遵循“能框就框、不放过小目标”的原则漏标的小目标在训练时会被当作背景是造成漏检的直接原因。如果项目预算允许优先用高分辨率无人机或地面机器人采集图像再用人工标注质量比自动标注稳得多。3.2 把非 YOLO 标注转成 YOLO 格式转换脚本与四个边界坑YOLO 格式的标注不是像素坐标而是归一化后的中心点坐标加宽高。从 VOC 或 COCO 标注转过来时必须做坐标转换。下面这段脚本可以把 VOC 格式的 XML 标注转成 YOLO 格式我建议你把这段脚本存成 convert.py 放在源码包根目录以后换数据集还能复用。import os import xml.etree.ElementTree as ET from PIL import Image def convert_xml_to_yolo(xml_path, out_dir, classes): tree ET.parse(xml_path) root tree.getroot() img_name root.find(filename).text img_path os.path.join(os.path.dirname(xml_path), img_name) img Image.open(img_path) w, h img.size out_txt os.path.join(out_dir, os.path.splitext(img_name)[0] .txt) with open(out_txt, w) as f: for obj in root.iter(object): cls obj.find(name).text if cls not in classes: continue cls_id classes.index(cls) box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) x_center (x1 x2) / 2 / w y_center (y1 y2) / 2 / h bw (x2 - x1) / w bh (y2 - y1) / h f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}\n) classes [weed, crop] xml_dir annotations out_dir labels os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): convert_xml_to_yolo(os.path.join(xml_dir, xml_file), out_dir, classes)这段脚本读取 XML 里的目标框坐标除以图片宽高后归一化再写入 txt 文件。注意类别索引从 0 开始weed 是 0crop 是 1顺序必须和 data.yaml 里的 classes 列表一致否则训练出来的模型类别会错位。这里有四个边界坑是反复踩过的一是图片宽高必须用实际尺寸不能写死二是 txt 文件必须和图片同名且放在同层级目录YOLO 按文件名配对三是空标注文件也要生成一个空 txt否则某些库会直接跳过这张图四是类别名大小写必须严格一致“Weed”和“weed”会被当成两个类别。我建议转换完成后抽样对比原图和 txt 标注画框验证比闷头训练靠谱得多。3.3 数据集划分先清洗再划分顺序不能乱很多人在数据划分上偷懒直接把连续拍摄的田间照片按前 80% 做训练、后 20% 做验证。这样做最典型的问题是相邻帧高度相似验证集与训练集几乎重叠mAP 虚高一到现场就翻车。正确做法是先把图片按拍摄时间、地块分组再做随机划分保证同一地块的照片不会同时出现在训练集和验证集里。python -c import os, random, shutil images os.listdir(images) random.seed(42) random.shuffle(images) split int(len(images) * 0.8) for i, img in enumerate(images): subset train if i split else val shutil.copy(os.path.join(images, img), os.path.join(subset, images, img)) 这段脚本按 8:2 划分图片固定随机种子保证可复现。关键细节是 shuffle 之前要先按地块分组最简单的手法是给每组图片文件名加地块前缀或者按子目录划分。更稳妥的做法是用 sklearn 的 train_test_split 配合分组参数但源码包里一般不会内置复杂的划分逻辑手动分组就够了。划分完成后检查 train 和 val 下的类别分布是否接近杂草出现密度差异大时建议按 StratifiedSplit否则类别比例失衡会直接影响 mAP 计算。4. 训练与调参让模型真正学会“分草”4.1 最小可复现的训练命令从 train.py 到数据入口数据准备完成后训练入口通常已经封装好了直接传参即可。源码包里的 train.py 一般会读取 data.yaml再调用 ultralytics 的 YOLOv8 训练接口。如果你打算自己拼命令最基础的形式是这样python train.py --data data.yaml --weights yolov8s.pt --epochs 100 --batch 16 --imgsz 640 --device 0train.py 是源码包封装好的训练入口它会把命令行参数拼进 YOLOv8 的训练配置。weights 参数代表预训练权重yolov8s.pt 是 small 版本训练速度快适合先验证数据质量。epochs 设 100 轮起步batch 大小根据显存调整imgsz 设为 640 是 YOLOv8 的默认值但杂草检测建议提到 1280。注意用 --device 0 指定 GPU不设这个参数时模型可能默认跑在 CPU 上。第一次跑训练时不要追求精度重点是确认 loss 在下降、数据加载没有报错。如果 loss 正常下降但 mAP 很低通常是数据标注问题而不是训练参数问题及时止损去查数据比硬调参更有效。4.2 四个必须动过的参数imgsz、epochs、batch、patienceYOLOv8 训练参数很多但真正影响杂草检测效果的只有四个imgsz、epochs、batch、patience。把这四个参数理解透能解决八成训练效果差的问题。参数推荐值影响与理由imgsz1280 或 640640 训练快但小目标漏检多1280 能显著提升小目标召回率显存不够时用 640 增强epochs100~300杂草数据量小时 100 轮足够数据量大或类别多时加到 200 以上batch8~16受显存限制batch 过大容易 OOM过小则收敛不稳patience20~50验证指标连续多少轮不涨就早停设 20 是保守值设 50 适合数据噪声大的场景imgsz 是杂草检测最该优先调的参数。我做过对比实验同一份数据在 640 下 mAP 50 大概 78提到 1280 之后能到 86小目标召回率提升明显但训练时间也翻了近一倍。batch 需要结合 imgsz 来看imgsz 提到 1280 而 batch 还保持 32显存基本直接爆掉。patience 是防止过拟合的保险丝田间数据噪声大验证指标偶尔会震荡一两个 epochpatience 设太小反而会在即将上升时提前掐断训练。我一般习惯设 30折中稳定性和效率。4.3 类别不均衡与小目标漏检我常用的三个补救手段杂草检测里类别不均衡几乎是必然的杂草样本数量可能是作物的数倍而且杂草个体小而密集模型很容易学会“只找大目标”。这时候光调训练参数不够我用过三个补救手段都有效。第一是类别权重通过 loss 系数拉高低频类别的贡献。第二是数据增强把图片随机裁剪放大让模型多看小目标。第三是修改标注策略把密集的小杂草按簇标注而不是一个叶子一个框。from collections import Counter labels [] with open(labels/train.txt, r) as f: for line in f: labels.append(line.split()[0]) counter Counter(labels) total sum(counter.values()) class_weights [total / (len(counter) * counter[i]) for i in range(len(counter))] print(class weights:, class_weights)这段脚本统计每个类别的样本数量然后按反频率计算类别权重。class_weights 可以直接传给 YOLOv8 的 loss 配置里把低频类别放大压制高频类别。注意计算权重时用的是实例数而不是图片数一张图里有 50 个杂草和 1 个作物类别权重差距可能达到几十倍这时候不能直接用原值要做开根号或 log 压缩否则模型会走向另一个极端。对于小目标漏检问题YOLOv8 的 mosaic 增强默认开启在田间场景下我建议保留但要把增强强度从默认的 1.0 降到 0.5 左右太强会让小目标变得模糊不清反而适得其反。5. 训练与部署中绕不开的 5 个坑避坑篇5.1 训练 loss 降了验证 mAP 却一直不涨训练集 loss 稳步下降但验证 mAP 卡在某个值不动这是最让人恼火的场景。现象是训练曲线很漂亮验证曲线平平无奇甚至还在降。原因通常是过拟合的典型表现田间数据集太小模型把训练集里的背景纹理当成了特征。解决思路是扩充数据量、做更强的数据增强、缩短训练轮数或者提高 dropout。我在实际项目中遇到过这种情况最后是用随机旋转、亮度扰动和随机裁剪把数据量翻了三倍mAP 立刻涨了 4 个点。还有一个隐蔽原因是训练集和验证集来自不同地块光照和土壤质地差异太大模型在训练集上学到的特征在验证集上完全不适用。这时候要检查数据划分是否按地块分组而不是按文件顺序硬切。5.2 显存总在 epoch 末尾爆掉训练到第 N 轮快结束时显存突然爆掉报错显示 CUDA out of memory但前面几十轮都正常。原因往往是验证阶段仍然占着显存训练 batch 又刚好逼近显存上限验证图一次推完就溢出了。解决思路是把验证 batch 调小YOLOv8 里有个参数叫 val_batch默认值和训练 batch 一样。我一般会在 data.yaml 里单独设 val_batch 为训练 batch 的一半比如训练 batch 16验证就用 8。另一个原因是显存碎片化输入图片尺寸不固定导致每轮分配不同可以用 --rect 参数强制固定比例训练让显存分配更稳定。如果显存仍然紧张还有个实用的办法是把 imgsz 从 1280 降到 960精度损失很小但显存占用少很多。5.3 模型把作物和杂草一起识别成杂草训练完成后跑推理发现模型把地上的作物苗也框成了杂草这是田间场景最容易出现的误检。原因可分为两类一是标注阶段杂草和作物的框混淆或者类别定义本身边界不清二是数据里杂草和作物形态太相似模型学到的是“绿色叶子都算杂草”而不是“这两种绿色叶子有区别”。排查时先把标注数据可视化用不同颜色的框叠加在原图上检查如果标注本身就是错的所有训练技巧都是白搭。如果标注没问题则需要增加作物类别的样本多样性把不同生长阶段的作物都标出来。我做过一个项目作物苗期和杂草特别像后来靠增加不同时间的采样数据并且把“作物”单独作为一类参与训练模型终于分清了。5.4 推理时小目标几乎全丢大目标倒是很准模型对大面积杂草识别很准但苗期的小杂草一帧里能漏掉一多半。原因是训练时图像被缩放到了 640 或 1280小目标在特征图里可能只剩几个像素特征根本不够用。解决思路是提高推理时的分辨率detect 阶段用和训练一致的 imgsz最好能高一点。我把推理 imgsz 从 640 提到 1280 后小目标漏检率降了接近一半但速度也明显下降。如果现场设备算力有限做不到高分辨率推理另一个思路是把图片切成小块分别推理再把结果拼回去。具体做法是先把大图按 50% 重叠切成四块每块单独推理最后用 NMS 把重叠区域的重复框合并掉。这个方法不需要重新训练就能改善小目标漏检实测在小目标密集场景效果明显。5.5 换一台电脑后环境始终装不上源码包在一台机器上跑通换到另一台机器上安装依赖时总是报错最常见的是与 GPU 驱动相关的版本冲突。现象是 pip install ultralytics 一切正常但 import torch 后 CUDA 不可用或者训练时直接报算子编译错误。原因多半是 PyTorch 版本和显卡驱动不匹配或者是装上了 CPU 版本的 PyTorch。解决思路是先检查显卡驱动支持的 CUDA 版本再安装对应的 PyTorch。不要直接用 pip install torch 默认版本它经常不带 CUDA 编译。正确做法是去 PyTorch 官方命令里选对应 CUDA 版本的安装命令。如果机器是纯 CPU 环境则要确认代码里所有 device 参数都设成了 cpu否则会一直报错 CUDA error: no kernel image available。源码包里的 requirements.txt 只是兜底不能完全替代手动检查环境。6. 导出与验证让模型从“验证集好看”到“田间能用”6.1 导出 ONNX 并做精度对比训练完成后除了保留 PyTorch 权重我建议导出 ONNX 格式做部署前验证。ONNX 可以在不依赖完整 PyTorch 环境的设备上运行也会暴露一些训练时看不到的算子兼容问题。导出命令通常长这样python detect.py --weights weights/best.pt --source deploy_test/ --conf 0.3 --device cpu python -c from ultralytics import YOLO; m YOLO(weights/best.pt); m.export(formatonnx, imgsz640)导出之前先跑一次 CPU 推理确认模型在无 GPU 环境下也能工作再导出 ONNX。导出结束后建议用同一个测试集分别跑 PyTorch 模型和 ONNX 模型对比检出框数量和 mAP。如果 ONNX 结果差很多优先检查输入尺寸和归一化是否一致这比怀疑算子更常见。导出 ONNX 时要注意 imgsz 参数要和训练一致否则剪裁会导致小目标进一步缩水。我习惯导出后先用 Netron 查看计算图结构确认输出节点只有一个避免后处理逻辑写错。6.2 用一段未参与训练的连续视频做最终验收模型在测试集上 mAP 再高都不如拿一段没参与训练的视频实测来得直观。源码包里通常没有现成的验收视频我会自己用手机在田间拍一段或者从已有监控录像里截取 3~5 分钟片段。验收标准有几个硬指标连续帧的检测框是否稳定、杂草密集区是否有漏检、作物区域是否有误报、抖动时是否出现框跳变。视频里最考验模型的是叶子遮挡和运动模糊这两个场景下模型往往会露出原型。如果视频测试发现误报集中在特定光照时段比如正午强光或黄昏逆光就需要把那段时间的样本补充到训练集里再做一轮微调。整套流程走完从环境到推理再到验收你会发现这套源码包真正的价值不在于开箱即用而在于把 YOLOv8 算法和田间场景真正串在了一起。最后说一句我的习惯每次训练完模型我会把训练参数、权重文件、验证指标存在同一个目录命名带日期。模型迭代多了以后这组记录就是后悔药随时能回看是哪一次改动带来提升。希望帮到你。本文还有配套的精品资源点击获取