1. 先从用途倒推数据设计
1.1 这七类树种到底从哪来
做无人机树种检测这件事,最难的不是飞,不是标,而是想清楚一个问题:你花三个月做出来的数据集,到底要喂给哪个具体业务。
我这次的项目,源自一个林区智慧巡检需求。客户要求用无人机完成重点区域的树种分布摸底,点名要区分落叶松、云杉、华山松、白桦、川西云杉、兴安落叶松、樟子松。光看这份清单就知道,这不是南方常见的阔叶林识别,而是典型的北方混交林场景。针叶树占了一大半,而且里面还有云杉和川西云杉这种亲缘关系很接近的"双胞胎"树种。
我一开始也想过去找现成的开源遥感数据集。试了一圈发现,公开数据大多是国外树种或者热带雨林,放到国内的寒温带针叶林场景上,迁移效果很差。更麻烦的是,光学影像在不同季节、不同地形下,树冠的光谱和纹理表现差异极大。比如白桦和落叶松,七月份都是绿油油的,但到了九月底,落叶松变黄的速度和程度跟白桦并不一致,这种季节变化最后都会成为模型误判的来源。
所以最终决定放弃"找数据集",转向"造数据集"。整个项目其实可以拆成五件事:林区树种清单确认、无人机影像采集、正射影像切片、标注规范制订、模型训练与回归验证。后面每一件事,我都吃了一点亏,也总结出了一些能直接抄的结论。
1.2 为什么单株树冠是合适的标注粒度
在数据集设计阶段,我首先卡在标注粒度这个问题上。到底是按单株树冠标,还是按林分区域标?
按林分区域标,操作上最省事,画个多边形把整片林子圈起来就行。但实际用下来问题很大:混交林里往往几十米范围内就有两三种树混在一起,边界完全不清晰,圈出来的区域标签纯度非常差。模型学到的是"这块绿有落叶松的特征",而不是"这个树冠是落叶松",到单木尺度调查时就废掉了。
按单株树冠标,精度高,但工作量翻倍。我观察了一下,一张1000m乘800m的正射影像,如果林分密度中等,单株树冠数量可能在几千棵。这意味着标注量是以十万计的。最后我们的做法是混合策略:先按单株树冠标一个核心区域,保证每一类都有足够样本;再用林分级别的粗标做预训练,让模型先学会"树冠检测"和"非树冠背景区分",然后把预训练模型拿来给人工标注做辅助预标注,人工只需要修正框的位置和类别。
这里有个经验:不要一开始就追求"全量精细标注"。先把数据分成AB两组,A组标精细,B组标粗糙,然后用A组训模型,用B组做测试集。如果B组上精度明显下降,说明标注粒度不一致已经成了瓶颈,再回头补标。我实测下来,至少能省百分之三十的人工标注时间。
1.3 一份"好"数据集的验收标准
很多人以为数据集验收就是看总张数和总标注数,这其实是个误区。无人机树种检测数据集最容易翻车的点是类间不均衡和场景单一。
先说类间不均衡。云杉、樟子松、落叶松这类针叶树如果采集区域大面积连片,会造成某类标注框特别多,另一些类别只有零星几十个框。模型训练时少数类的AP会直线下降。我给自己定了一个参考标准:每类至少保留800到1200个有效树冠样本,少于500个的类别需要回补采集,不然这个类别的存在价值约等于零。
再说场景单一。如果所有影像都来自同一片林区、同一飞行高度、同一光照条件,模型到了另一片地形就会表现得很差。我当时拿到第一版测试数据时,模型在训练区mAP能到0.82,换到相邻河谷马上跌到0.57。原因就是采集时只顾着"数据量够大",忽略了地形和光照多样性。
基于这个教训,我后来的验收标准里加了三条硬性条件:一是必须有至少三个不同地形单元(山地、河谷、丘陵)的影像;二是同一树种必须在阴坡和阳坡各有分布样本;三是飞行高度不能只有一个档位,至少要包含30米以下和80米以上两种分辨率采集。这三条看起来简单,但直接影响模型能不能真正在巡检业务里跑起来。
2. 七个树种的识别特征拆解
2.1 树冠形态与光谱特征的差异
树种检测模型学到的特征,主要来自树冠的形状、颜色、纹理和阴影关系。这里先把我整理的七类树种俯视特征表列一下。
| 树种 | 树冠形态 | 夏季俯视颜色 | 冠层纹理特征 | 最容易混淆的对象 |
|---|---|---|---|---|
| 落叶松 | 塔形,冠顶钝尖 | 黄绿或浅绿 | 针叶簇生,纹理细碎 | 兴安落叶松、幼年樟子松 |
| 云杉 | 尖塔形,冠幅较窄 | 深绿至灰绿 | 枝条密集,颗粒感强 | 川西云杉 |
| 华山松 | 广卵形,冠幅大 | 亮绿,光泽感强 | 针叶较长,纹理偏粗 | 高处拍摄的樟子松 |
| 白桦 | 卵形或近圆形 | 亮绿,透光感明显 | 阔叶叶片密集,边缘柔 | 少数阔叶灌丛 |
| 川西云杉 | 窄塔形,冠顶略平 | 灰绿偏蓝 | 鳞叶排列紧密,颗粒感更强 | 云杉 |
| 兴安落叶松 | 塔形,冠基较大 | 浅绿,春季偏嫩黄 | 针叶簇生,树冠内部有明显空隙 | 落叶松 |
| 樟子松 | 圆形或宽卵形 | 深绿带黄 | 针叶较长,冠层不均匀,有亮斑 | 华山松、落叶松 |
这张表不是我拍脑袋写的,是拿了几百张影像和地面实测照片反复比对出来的。最核心的发现是:单一的"颜色均值"特征完全靠不住,真正稳定的是"树冠边缘锐利度+冠层纹理周期性"的组合。云杉和川西云杉颜色接近,但川西云杉的树冠边缘更平直,有过明显的平台感,而云杉更尖。这种细节在标注时很容易忽略,却在训练时成为模型区分它们的关键线索。
2.2 相似种之间的判别逻辑
我在这个数据集上踩过最大的坑,就是云杉和川西云杉的区分。两者的俯视影像相似度实在太高,第一次标注时,标注员甚至提出"这两类是不是标错了"。
后来我仔细对比发现,光学影像上真正能用的判别特征有三个。
第一个是冠幅与树高的比例。云杉的冠幅相对更宽,适合在中等郁闭度林分中生长,俯视时树冠之间常出现重叠;川西云杉的冠幅更窄,树冠间距相对更大,空隙更明显。这个特征在低分辨率影像上也能分辨。
第二个是树冠边缘的光影表现。云杉枝条分层明显,树冠边缘有比较自然的锯齿状阴影;川西云杉的鳞叶排列更紧密,树冠边缘看起来更光滑,锯齿感很弱。晴天侧光拍摄时这个特征非常明显。
第三个是阴影的方向和密度。由于树冠结构不同,云杉下方的阴影更碎片化,川西云杉下方的阴影更连续。后期我把影像按太阳高度角做了归一化处理后,这个特征就更能体现出来了。
对于落叶松和兴安落叶松,单看俯视影像其实更难。两者的树冠形态几乎一样,唯一的稳定区分点是冠幅大小和郁闭度下的分布格局。落叶松在混交林里更常见,树冠偏小;兴安落叶松更耐寒,常形成纯林或优势林分,树冠偏大。但这两个特征并不是绝对的,所以数据集中一定要包含不同地域、不同生长阶段的样本,不能只靠光学特征硬扛。
2.3 从树种构成反推采集区域安排
七类树种的构成其实已经决定了采集计划的大致范围。里面既有云杉、川西云杉这种偏湿润环境的树种,也有樟子松、兴安落叶松这种耐旱耐寒的先锋树种,还有白桦这种典型的次生林落叶阔叶树。这意味着采集区域必须覆盖多种生境,单一林场搞不定。
我最后选定的做法是"三片区采集":第一个片区以针叶纯林为主,覆盖落叶松、兴安落叶松和樟子松;第二个片区以针阔混交林为主,覆盖云杉、川西云杉和白桦;第三个片区选择林缘和疏林地带,主要采集华山松,同时补充其他树种的稀疏样本。
这样安排的好处是:每个树种都能在"优势生境"和"劣势生境"下分别出现,模型学到的不是"这一片都是云杉",而是"云杉在不同混交状态下的样子"。第三片区采下来的数据量最少,但因为特征变化最大,训练时对AP的贡献反而最大。
3. 影像采集与预处理实战
3.1 飞行参数到底怎么定
采集无人机树种检测数据,飞行参数直接决定后续所有环节的成败。我最后定下来的参数体系如下,供大家参考。
飞行高度上,我做了两档。第一档是100米高度,主要获取大范围正射影像,用于生成区域概览图和训练检测模型的"远景样本"。这个高度下地面分辨率大概在7到10厘米每像素,单棵树冠由几十个像素组成,对人眼来说勉强能分辨树种,对模型来说已经足够学习树冠结构特征。
第二档是35米高度,获取高分辨率局部影像,针对的是单株树冠的细节。这个高度下地面分辨率能到2到4厘米每像素,树冠内部纹理、枝条结构都非常清晰。这部分数据我主要用于标注难度较高的相似种,比如云杉和川西云杉。
航线重叠率是另一个关键参数。航向重叠我设了80%,旁向重叠70%。这个数值比普通测绘要求的60%到65%要高不少。原因是树冠是有高度的立体目标,在正射拼接时会产生视差,如果重叠率不够,树冠边缘会出现明显的拼接锯齿和重影,直接污染样本质量。
飞行时间上,我强烈建议避开正午。树冠阴影最小的时候不一定适合采集,因为缺少立体感,树冠边缘和背景的对比度反而下降。上午十点到十一点半,以及下午两点半到四点,这两个时间段侧光明显,树冠轮廓清晰,阴影还能辅助标注员判断冠层边界。有雾、大风、阴天我都不建议飞,阴天平光条件下很多纹理特征会被压平,模型学到的特征会很飘。
3.2 正射拼接与切片策略
采集回来的原始影像必须经过正射拼接才能得到完整的林区俯视图。这一步我踩过不小的坑:第一次用默认参数拼接,结果树冠边缘出现很多"重影"和"拉花",尤其是高一点的树,拼出来像万花筒。
问题出在数字表面模型的生成策略上。无人机树种检测数据集的正射拼接不能完全依赖标准地形模型,树冠是有几十米高的立体结构,如果只做平面正射校正,树顶和树底的高差会带来明显的投影错位。我的解决办法是:先用稀疏点云生成数字表面模型,再做真正射校正,让树冠顶部的影像"站直",然后再生成立体视图供后续使用。
拼接完成后,需要把大幅正射影像切割成训练切片。这里我试过两种切片尺寸:1024像素和1536像素。1024在训练速度和显存占用上更友好,但树冠尺度偏大时,一棵树的风范可能占满整个切片,上下文信息太少,模型分不清"这是整棵树冠"还是"树冠局部"。1536效果更好,但batch size必须降下来,训练时间会拉长。
切片时还有个容易忽视的细节:相邻切片之间要有10%到20%的重叠。如果不重叠,树冠正好被切在边界上时,这个样本基本报废。重叠切片的做法是让同一棵树在相邻切片里各出现一次,数据量虽然翻倍了,但有效样本率大幅提高,模型收敛也更快。
3.3 哪些影像必须提前扔掉
第一轮我采集了将近3万张原始影像,真正进入训练集的只有不到一半。大量影像在预处理阶段就被我扔掉了,这里说几条筛选红线。
云层阴影下的影像必须扔。树林里云影移动造成的光照不均匀,比单纯阴天更恐怖,它会在同一张切片里制造两个亮度完全不同的区域。模型如果见过太多这种样本,会试图用亮度来分类,而不是用树冠特征。
雾霾和薄霭也要扔。低空航拍时,远处林区的山体常常笼罩在淡蓝色的大气散射里。这种影像上的树冠颜色整体偏灰蓝,饱和度低,如果混进训练集,会让模型对"颜色饱和度"产生错误依赖。
拼接后出现拉花和错位的区域,宁可切掉也不能留。局部错位虽然看起来不大,但在模型眼里就是一堆乱码式的边界纹理,标注框一旦画在这些区域,等于主动给训练集投毒。
还有一类是飞行姿态剧烈变化导致的倾斜影像。无人机在大风天转弯时,姿态角变化很大,影像边缘的地物明显倾斜。正射校正后这些区域会被拉伸得很奇怪,放进训练集只会增加无效样本。
4. 标注规范与质量控制
4.1 检测框还是分割掩码
做单株树冠标注,第一步就要决定用目标检测框还是实例分割掩码。我两个方案都试过,说一点实际感受。
如果项目目标是"统计树种面积、生成分布图",那么检测框就够用了。水平外接框虽然不能精确贴合树冠轮廓,但在统计上误差是可以接受的,只要框的中心位置准确,面积估算误差能够控制在10%以内。检测框的标注效率也高得多,一名标注员一天能标1200到1500个框,如果是分割掩码,大概只能画300到400个。
如果目标是"单木定位+树冠面积精准测量",那么必须用分割掩码。比如要做蓄积量估算、间伐作业设计,一个框的精度远远不够,树冠边界多画或少画几个像素,面积误差会被放大。
考虑到成本和客户需求,我最后采用的是折中方案:主标注用水平检测框,类别标签和中心点严格把关;另外对不容易判别的混交林区域追加掩码标注,用来训练一个辅助分割模型。上线时主用检测模型,辅助分割模型只做面积修正参考。
4.2 边界情况怎么定规则
树种检测标注最容易产生分歧的是一些边界情况。我在制定标注规范时明确了几条规则,后来发现这几点直接决定了标注一致性。
第一,树冠被遮挡超过一半的不标。混交林里树冠互相挤压,边缘经常会有树冠被其他树挡住。如果被遮挡面积超过50%,模型学到的就是一个残缺的树冠形状,容易造成特征错乱。如果遮挡在30%以下,可以标,但要在备注里标记"partial"。
第二,出于画面边缘的树冠不标。正射切片边缘经常有半个树冠露在外面,这类样本在检测时会产生一个超出画幅的预测框,后处理时很麻烦。我规定只有树冠主体完整出现在画面内才允许标注。
第三,幼树和灌木不标。没有进入主林层的幼树,树冠太小,与灌丛在影像上极难区分。我把树冠直径低于平均值的样本全部排除,宁可少标一点,也不能让模型把灌木当成樟子松。
第四,同一棵树在重叠切片里出现多次怎么办。我允许标注,但规定"同一个树冠ID"必须通过备注字段关联。后续在做数据划分时,保证同一个树冠ID的所有切片都出现在同一个数据集里,避免切片级别的数据泄露。
4.3 专家复核与一致性检查
标注一致性是这类数据集的隐形天花板。两个标注员对同一棵树的判断不一致,这个样本在训练时就会产生梯度冲突。我的做法是三轮质检。
第一轮是系统自动检查:用脚本统计每张切片的标注框数量、类别分布和框面积分布,出现极端值就标记为可疑样本。比如一张切片里框了300棵落叶松,但其他同类切片平均只有80棵,这张图基本就是标错了区域。
第二轮是专家抽检:请有林学背景的人对5%到10%的切片进行复核。专家复检主要任务不是纠错,而是确认类别定义有没有偏差。我当时发现,标注员把很多"受光不足、颜色偏深的华山松"顺手标成了樟子松,这个错误靠标注员自己交叉检查根本发现不了,只有专家能看出端倪。
第三轮是分类交叉检查:每个类别随机抽20个框,集中显示在屏幕上,让不同标注员描述"为什么觉得这个是落叶松"。如果他们描述的特征各有侧重,说明类内样本多样性足够;如果所有人都说"看着像",那就要警惕这个类别的特征是否太单一,可能需要补充采集。
5. 模型训练与效果评估
5.1 基线模型选择与训练配置
数据集做完,模型训练反而是最顺利的环节。我基于YOLO系列的检测框架做基线,对比了不同backbone下的效果,最终采用的配置如下。
输入分辨率选1280乘1280。虽然训练变慢,但对树冠这种中大型目标非常必要。我试过640分辨率,检测框数量上去了,但云杉和川西云杉的区分度明显下降,说明细节纹理在降采样过程中被丢掉了。1280分辨率下,模型能看见树冠内部的纹理颗粒,这对相似种分类帮助极大。
训练集、验证集、测试集的划分方式要特别小心。我强烈建议按"采集区块"划分,而不是按切片随机划分。同一片林区相邻切片的内容高度相似,如果随机划分,验证集里会有大量与训练集来自同一次飞行的样本,"记忆"代替了"学习",验证分数虚高。我前面提到同一树冠ID要关联,正是为了在划分时做去重。
训练超参数上,我给了两个参考:初始学习率设在0.01左右,用余弦退火调度;数据增强开启Mosaic和MixUp,但概率只开到0.5。树冠俯视图不像通用目标检测数据集那么丰富,过强的Mosaic会把不同树种的树冠纹理拼在一起,反而产生错误的类间混合特征。
5.2 评估指标别只看mAP
训练完模型,很多人习惯只看mAP50和mAP50-95,这两个指标确实重要,但树种检测项目里必须多看两个维度。
第一个是各类别单独AP。七类树种,如果整体mAP50在0.8以上,看起来很漂亮,但打开类别明细,白桦可能高达0.92,川西云杉只有0.61。巡检业务里客户关心的恰恰是那些难分的类别,只看总体指标会掩盖严重偏科。
第二个是"混淆矩阵"。我发现落叶松和兴安落叶松的混淆程度最高,其次是云杉和川西云杉。这时候就要回去检查训练集里这两对的样本比例和拍摄环境多样性。我给自己的要求是:每对易混淆类别的交叉错误率尽量控制在15%以下,如果超过20%,说明数据集里这对相似种的特征重叠太严重,需要补特征或者采集更多专项样本。
我第一版模型的实测数据如下,供大家做个参照。
| 类别 | AP50 | AP50-95 | 主要错误类型 |
|---|---|---|---|
| 落叶松 | 0.84 | 0.62 | 14%错分为兴安落叶松 |
| 云杉 | 0.88 | 0.68 | 9%错分为川西云杉 |
| 华山松 | 0.79 | 0.57 | 11%错分为樟子松 |
| 白桦 | 0.91 | 0.72 | 4%错分为灌丛 |
| 川西云杉 | 0.74 | 0.51 | 19%错分为云杉 |
| 兴安落叶松 | 0.81 | 0.58 | 16%错分为落叶松 |
| 樟子松 | 0.77 | 0.55 | 12%错分为华山松 |
5.3 难例挖掘与针对性回补
模型训练不是一次性的事情。第一版在川西云杉上只有0.74的AP50,说明这个类别的特征学习明显不足。我做了一次针对性的难例挖掘。
我把测试集里所有被分错的切片单独导出来,用聚类做了一个可视化分析。结果显示,被错分的川西云杉主要集中在两类场景里:一是生长在阴坡的窄冠个体,树冠形态明显收窄,和普通云杉差异被拉开;二是混交林里树冠受挤压的个体,树冠呈现不规则多边形,很难从俯视影像上捕捉典型特征。
针对这些难例,我做了三件事:第一,回补采集了阴坡窄冠川西云杉的专项数据;第二,在训练时对易混淆类别做了过采样,让每个batch里云杉和川西云杉的出现频率接近;第三,增加了光学影像的对比度归一化预处理,降低光照不均匀带来的干扰。经过这一轮迭代,川西云杉的AP50提到了0.79,虽然还是不理想,但至少没有出现大规模的类间崩溃。
这里多说一句,不要为了追求指标好看而删掉"不好做"的样本。很多时候难样本恰恰代表真实业务场景,删掉它们等于自欺欺人。宁可模型在测试集上分数低一点,也要保证它见过足够多的"困难地形"。
6. 实际巡检落地时的现实问题
6.1 季节变化对模型泛化的冲击
模型训练完,不等于巡检就万事大吉。我第一版模型在六月份采集的数据上效果不错,到了九月末帮客户做秋季巡检,效果直接打折扣。白桦和落叶松在秋季快速变色,树冠从绿色转为金黄,模型之前学到的"颜色分布"特征全部失效,大量白桦被漏检,落叶松被错分成白桦。
这个问题在树种检测里非常普遍。纯光学影像模型本质上学习的是某个季节下的树种外貌,一旦季节变了,外貌变化比不同树种的差距还大。我的解决办法是建立"季节版本"概念:不指望一个模型扛一年,而是按巡检时间分两季建模,一个是生长旺季模型,一个是秋季变色模型。多光谱数据能缓解一部分季节问题,但不是所有巡检队都配得起多光谱相机,所以对大多数团队来说,季节版模型更现实。
另一个折中思路是在训练数据里故意混入不同时期的少量样本。例如在生长季训练集中混入10%的去年秋季影像,让模型不至于对颜色完全敏感。实测下来增加了大概3%到5%的鲁棒性,虽然不大,但在误检率上case减了不少。
6.2 光照、阴影与树冠重叠
巡检作业中绕不开的一个问题,是航向与太阳角度的关系。如果无人机按固定航线飞行,那么同一片林区前后两架的侧光方向可能完全相反。树冠阴面在模型眼里往往是"暗色噪区",如果训练数据里全是顺光影像,逆光巡检时模型的表现会很挣扎。
我的对策是两条。第一,采集阶段刻意记录每张影像的航向角度,并在切片时保留该信息用于数据清洗。第二,训练阶段做"光照翻转增强",把影像左右翻转、上下翻转,同时配合亮度扰动。这种增强方式能部分模拟太阳角度变化,让模型学到与光照方向无关的树冠结构特征。
树冠重叠的问题更难解。郁闭度高的纯林里,成片树冠几乎连在一起,水平检测框之间大量重叠。模型训练阶段如果密集重叠样本太多,NMS阈值会很不好调:阈值调高了容易漏检,调低了会把一棵树重复框两三次。我最后用了一个相对保守的NMS参数:置信度0.35,IoU阈值0.45。同时在后处理阶段加了一个"重叠框合并"规则,如果两个同类别框的重叠面积超过70%,且置信度差在0.1以内,就合并成一个树冠组,后续统计时按面积归一化处理。
6.3 从树冠检测到巡检报告的最后一公里
模型输出的检测框,距离客户能用的巡检报告还差好几步。我最后的处理管线是:检测框先做地理配准,把像素坐标转换到WGS84经纬度坐标系下;再对树冠框进行面积估算,按树种累加得到分布面积;然后把结果聚合成小班尺度的树种比例表。
这一步最容易出问题的是地理配准精度。如果正射影像拼接精度不够,一个检测框的地理坐标偏差可能从五米到二十米不等。单独看一个树冠好像看不出问题,汇总到小班面积时,就会发现边界的树种分布完全对不上。我建议数据处理的最后关一定要加入地面控制点校验,至少保证框中心平均误差在三米以内,不然报告里的面积数据经不起推敲。
另外,巡检报告不能只给一张树种分布图。我后来在成果里加了一个"树种组成变化预警"模块:把多期检测结果叠加,自动比对同一位置的树种变化。比如某块小班去年是落叶松纯林,今年突然出现大量白桦,这可能是抚育或者自然更新导致的。客户对这个功能的反响比我预想的好很多,也让我更确认了一点:数据集和模型永远只是中间产物,真正值钱的是能指导现场决策的结论。
我的体会是,这类智慧农业巡检项目,最花时间的其实不是算法,而是把数据的"脏活累活"做扎实。数据采集前先花一周把树种清单和地形图谱摸清楚,后面所有环节都会受益。如果一上来就闷头飞、闷头标,等到模型训完再发现数据有问题,回填成本会是前期的好几倍。