ENVI 中的 Spectral Math 工具在使用 deriv(s1) 函数时,是针对单个光谱曲线进行计算的,而不是对整个图像的每个像素光谱进行批量处理,以下Python代码实现了对高光谱整个图像的一阶导数计算。
首先得简单提一下高光谱数据求一阶导数到底是怎么个事儿。
我们对同一位置(同一像素)的光谱(即不同波段的反射率)进行求导,自变量是波长(对应波段),而因变量则是光谱反射率。这种求导通常用于光谱特征提取,帮助我们识别不同物质在光谱上变化的细节。例如,计算某个像素在各个波段上的反射率变化,以揭示该物质的光谱特性,或者提取物体在特定波长范围内的敏感变化。对于高光谱图像,我们通常关注光谱信息的变化,而这些变化能帮助我们识别不同的物质或物体。例如,某些植被或矿物的光谱特征在某些波段上有明显的变化。如果我们计算光谱的一阶导数,我们能够更精确地捕捉到这些变化的速率。
接下来是具体代码:
import spectral
import numpy as np
import matplotlib.pyplot as plt
def compute_spectral_derivative(hyperspectral_data):
"""
对每个像素的光谱进行一阶导数计算,并生成新的高光谱图像。
hyperspectral_data: 原始高光谱数据 (height, width, bands)
return: 计算后的高光谱数据 (height, width, bands-1)
"""
height, width, bands = hyperspectral_data.shape
spectral_derivative = np.zeros_like(hyperspectral_data) # 创建一个同样形状的零数组用于存储导数结果
for y in range(height):
for x in range(width):
# 对每个像素计算光谱导数(计算相邻波段之间的差异)
spectrum = hyperspectral_data[y, x, :] # 当前像素的所有波段光谱
spectral_derivative[y, x, 1:] = np.diff(spectrum) # 计算每个波段的导数,并保存到新的数组
return spectral_derivative
img = spectral.open_image(r'./176test.hdr')
data = img.load() # 读取数据,返回一个 (height, width, bands) 的 ndarray
spectral_derivative_data = compute_spectral_derivative(data)
这里需要注意的是,np.diff()他实际上是求差分的函数,并不是求导。在高光谱图像中,每个像素的光谱反射率是离散的值,而这些值通常是随着波段变化的,我们不能直接使用连续的微积分公式。但他们的结果是几乎近似的,所以被用来估计每个波段之间的反射率变化率(即近似导数)。np.diff(spectrum)的结果会比原始高光谱数据少一个波段,因为原因在于np.diff()返回的是相邻元素之间的差异,而不包括最后一个元素。所以求导结果(即spectral_derivative)的第一个波段的反射率均设置为0。
##保存结果文件
output_filename = r'./output_derivative_image_test.hdr'
spectral.envi.save_image(output_filename, spectral_derivative_data, dtype='float32', interleave='bil')
这样我们也就保存结束了,这里指定了输出文件output_derivative_image_test.hdr,他会另外生成.img后缀的文件。我们可以用ENVI打开。
在ENVI中打开结果文件,可查看一阶导数结果图的光谱曲线