第四节:温度特征提取——从数据里“挖”出叶片健康的密码
好,咱们接着聊。上一节我们把红外图像处理干净了,拿到了每个像素点的温度值。但问题来了——一张图几千几万个温度点,你盯着看能看出啥?
所以,特征提取就派上用场了。说白了,就是把海量数据压缩成几个有物理意义的指标。我个人习惯把这步叫做“数据瘦身”,但瘦完还得有营养。
4.1 基础统计量:最高温、最低温、平均温
这三个值,是温度分析的“三驾马车”。几乎每个项目我都会先看它们。
- 最高温:往往对应叶片上的异常热点。比如病虫害侵染初期,局部代谢加快,温度会突然升高。我在番茄大棚里就遇到过,叶片背面有红蜘蛛,正面温度比正常叶片高了1.8℃。
- 最低温:通常是叶片的蒸腾冷却区。如果最低温偏高,说明蒸腾受阻——可能是气孔关闭了。
- 平均温:反映叶片的整体热状态。但注意,平均温容易被“拉平”,掩盖局部异常。
代码实现很简单,用OpenCV或者NumPy几行就搞定:
import cv2
import numpy as np
# 假设 thermal_data 是已经校准过的温度矩阵(单位:℃)
thermal_data = cv2.imread('leaf_thermal.tiff', cv2.IMREAD_UNCHANGED)
max_temp = np.max(thermal_data)
min_temp = np.min(thermal_data)
mean_temp = np.mean(thermal_data)
print(f"最高温:{max_temp:.2f}℃")
print(f"最低温:{min_temp:.2f}℃")
print(f"平均温:{mean_temp:.2f}℃")
我的小习惯: 拿到数据后,先算一个“温差幅度”(最高温 - 最低温)。如果这个值超过5℃,我就要警惕了——正常健康叶片的温差通常在2~3℃以内。
4.2 温度梯度分析——找“突变”
温度梯度,就是温度在空间上的变化率。你想想看,一片健康的叶子,温度分布应该是平滑过渡的。但如果某个区域突然变热或变冷,那一定有问题。
我一般用Sobel算子或者拉普拉斯算子来计算梯度。梯度大的地方,就是温度突变的位置。
# 计算x方向和y方向的梯度
grad_x = cv2.Sobel(thermal_data, cv2.CV_64F, 1, 0, ksize=3)
grad_y = cv2.Sobel(thermal_data, cv2.CV_64F, 0, 1, ksize=3)
# 梯度幅值
grad_magnitude = np.sqrt(grad_x**2 + grad_y**2)
# 找出梯度最大的前5%像素点
threshold = np.percentile(grad_magnitude, 95)
hot_spots = np.where(grad_magnitude > threshold)
避坑指南: 我曾经在黄瓜叶片上吃过亏——梯度分析发现了一个“热点”,以为是病害,结果拔起来一看,是滴灌管漏水滴在叶片上了。所以,梯度分析只能告诉你“哪里异常”,不能告诉你“为什么异常”。一定要结合现场情况判断。
4.3 温度分布直方图——看“形状”
直方图这东西,很多人觉得就是画个柱子图,没啥技术含量。但我想说,直方图的形状里藏着大秘密。
正常叶片的温度直方图,通常是单峰、对称、窄分布的。如果出现双峰,说明叶片上存在两种明显不同的热状态区域——比如一半正常、一半缺水。
如果直方图偏态严重(左偏或右偏),也值得深究。
import matplotlib.pyplot as plt
# 将温度数据展平成一维数组
temps_flat = thermal_data.flatten()
plt.hist(temps_flat, bins=50, color='skyblue', edgecolor='black')
plt.xlabel('温度 (℃)')
plt.ylabel('像素数量')
plt.title('叶片温度分布直方图')
plt.grid(True, alpha=0.3)
plt.show()
实战经验: 有一次我在分析柑橘叶片时,直方图出现了明显的“双峰”。我判断是叶片一半受光、一半遮阴导致的。后来用遮光布处理了一下,双峰就消失了。所以,做直方图分析时,别忘了考虑光照不均匀的影响。
4.4 时域温度变化曲线——看“趋势”
单张图片的温度分析是“快照”,但植物是活的,温度会随时间变化。所以,时域分析才是真正能反映叶片生理状态的手段。
我通常的做法是:每隔5~10分钟采集一次红外图像,连续监测1~2小时。然后提取每个时间点的平均温,画出一条温度-时间曲线。
这条曲线的斜率、波动幅度、是否有周期性,都能告诉我们很多信息。
import pandas as pd
# 假设 time_points 是时间戳列表,mean_temps 是对应的平均温度
data = {
'time': ['08:00', '08:10', '08:20', '08:30', '08:40', '08:50'],
'mean_temp': [22.3, 22.8, 23.1, 23.5, 23.2, 22.9]
}
df = pd.DataFrame(data)
plt.plot(df['time'], df['mean_temp'], marker='o', linestyle='-', color='coral')
plt.xlabel('时间')
plt.ylabel('平均温度 (℃)')
plt.title('叶片平均温度时域变化')
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.show()
注意: 时域曲线如果出现“锯齿状”剧烈波动,先别急着下结论。我曾经遇到过这种情况,后来发现是风吹动了叶片,导致测量角度变化。所以,做时域分析时,尽量在无风或微风环境下进行。
知识体系总览
下面这张图,是我自己总结的温度特征提取的完整流程。你可以把它当作一个“检查清单”,每次做分析时对照着来。
嗯,以上就是温度特征提取的核心内容。这四个维度——基础统计量、梯度、直方图、时域曲线——就像四把不同的钥匙,从不同角度打开叶片温度数据这扇门。我个人建议,每次做分析时,至少从两个维度交叉验证,这样得出的结论才靠谱。