1. 课程导入与农业视觉认知
在开始写第一行代码之前,我们需要先建立一幅“地图”:农业机器视觉到底解决什么问题,它在田间地头以什么形态出现,Python 在其中扮演什么角色,以及接下来 30 章我们将沿着怎样的路径前进。本章不涉及复杂算法,但会为你后续所有实操建立一个共同的参照系——很多初学者后期卡住,往往不是不会调库,而是没想清楚“我要让机器看什么、看到之后要输出什么”。
什么是农业机器视觉
农业机器视觉,是把相机(可见光、多光谱、深度相机、热成像等)采集到的农田图像或视频,转化为可被计算机处理的数据,再通过图像处理与机器学习方法,输出对农业生产有用的判断或指令。它和通用计算机视觉共享底层技术,但面对的挑战非常特殊:光照剧烈变化(正午强光、阴天、树冠阴影)、目标高度非刚性(随风摆动的叶片)、遮挡严重(果实被枝叶挡住一半)、背景杂乱(土壤、杂草、地膜、水滴),以及类别本身极其精细(不同病害在早期可能只差几个斑点)。
因此,农业视觉的核心不是“把模型跑起来”,而是把农业问题翻译成视觉任务。同一个“看看这块地长得好不好”,可能被翻译成分类(健康/病害)、检测(病斑位置与数量)、分割(病叶区域像素级轮廓)或计数(果实个数)四种完全不同的任务,对应的数据标注方式、模型结构和评价指标都不一样。这个“翻译”能力,是本课程希望你先建立起来的第一项素养。
四类典型应用场景
作物监测关注的是“状态”,例如叶面积指数、冠层覆盖度、缺水或缺氮的早期表现。常见做法是用多光谱或可见光图像计算植被指数(如 ExG 超绿指数),再按阈值或回归模型映射到长势等级。它的输出往往是连续数值或分级,而不是单个标签。
果实计数关注的是“数量与位置”,属于目标检测或实例分割任务。难点在于果实相互遮挡、大小随距离变化、成熟度不同导致颜色差异。评价时常用平均绝对误差(MAE)和决定系数 R²,而不是简单的准确率。
病害识别关注的是“类别与严重程度”,早期多为图像分类,进阶为病斑分割。这里最容易被忽视的是数据分布问题:训练集若只包含清晰单叶特写,部署到田间整株图像上准确率会明显下降。
采摘机器人则把视觉与执行机构连在一起,视觉不仅要回答“是什么、在哪里”,还要给出三维位姿和可抓取点,并判断遮挡是否影响机械臂接近。它本质是一个“感知—决策—执行”闭环,视觉只是其中一环。
Python 在农业视觉中的角色
为什么本课程选择 Python 而不是 C++ 或 MATLAB?原因很实际。第一,农业视觉项目往往从“快速验证一个想法”开始,比如“用颜色阈值能不能把青色果实从叶片里分出来”,Python 配合 OpenCV 十几行代码就能看到结果,试错成本极低。第二,深度学习生态几乎以 Python 为中心,PyTorch、Ultralytics(YOLO 系列)、MMDetection 等让检测与分割模型的训练和推理变得标准化。第三,农业数据常需要与表格、传感器记录、GPS 信息联合分析,Pandas 和 NumPy 让这类“视觉 + 农学数据”的融合处理非常顺手。
需要清醒认识的是,Python 不是万能的。在嵌入式采摘设备上,最终部署常需要模型导出为 ONNX 或 TensorRT,甚至改用 C++ 推理;Python 更多承担原型验证、数据处理、模型训练与评估的角色。理解这条“Python 做研发、轻量化做部署”的分工,能避免你后期在性能问题上走弯路。
学习路径与工具准备
本课程的整体路径可以概括为四段递进:图像基础与 OpenCV 操作 → 传统图像处理与特征提取 → 深度学习检测与分割 → 农业场景综合项目。前两段帮你建立“像素级直觉”,能判断一张图的问题出在光照、对比度还是噪声;后两段让你具备训练和评估模型的能力。每一段都会围绕真实农业对象展开,而不是抽象的数字图像。
工具准备方面,建议按以下清单一次性配好环境,避免中途反复折腾:
- Python 3.10 或 3.11,使用 conda 或 venv 创建独立虚拟环境,命名为
agri-vision。 - 核心库:
opencv-python、numpy、matplotlib、pandas、scikit-learn。 - 深度学习:
torch、torchvision、ultralytics;有 NVIDIA 显卡时安装对应 CUDA 版本。 - 开发工具:VS Code 或 Jupyter Lab,建议同时装好 Jupyter,便于逐格观察图像处理中间结果。
- 数据管理:准备一个
datasets/目录,按raw/、processed/、annotations/分层存放,从一开始就养成不覆盖原始数据的习惯。
可以用下面这段最小代码验证环境是否就绪——它读取一张图片、转换到 HSV 空间并计算超绿指数 ExG,是后续作物监测章节的基础操作:
import cv2
import numpy as np
img = cv2.imread("datasets/raw/leaf_sample.jpg")
b, g, r = cv2.split(img.astype(np.float32))
# ExG = 2G - R - B,突出绿色植被
exg = 2 * g - r - b
exg_norm = cv2.normalize(exg, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
print("图像尺寸:", img.shape, "ExG 均值:", exg.mean().round(2))
cv2.imwrite("datasets/processed/exg_demo.png", exg_norm)
运行后如果能看到输出尺寸、ExG 均值,并在 processed/ 下得到一张绿色区域被明显增强的灰度图,说明环境与基本流程已经打通。这里的数值仅用于验证流程,不代表任何具体作物的长势结论。
最后强调一个贯穿全课程的原则:先明确输出,再选择方法。在动手写代码前,先用一句话写清楚“输入是什么图像、输出是什么形式、用什么指标判断好坏”。这句话会成为你每个项目的锚点,也是本课程后续所有实操的起点。