光谱库读写+光谱处理及交互式采集
上一篇我们介绍了利用Python对不同格式的高光谱数据进行读写,本章将介绍如何从图像中交互式的采集光谱,sli格式光谱库的读写方式以及一阶微分、光谱平滑、多项式拟合、吸收深度计算等光谱处理方法。
- 交互式工具的制作
- 光谱库文件读写,头文件编辑等
- 光谱一阶微分、平滑、多项式拟合、吸收深度计算等处理
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
import os,glob,time
import spectral.io.envi as envi
import importlib
from utils import * #之前分享过的function都放到了utils里,此文档不在展示,文末回复关键字获取
import sys,importlib
reload(sys.modules['utils'])# 在需要重新加载的地方调用 reload() 函数
importlib.# !pip install ipywidgets
# !jupyter nbextension enable --py widgetsnbextension
<module 'utils' from 'x:\\WRSDP\\Second Week\\TASK2\\utils.py'>
1. 光谱数据处理
# 用sepctral库来加载sli光谱库数据
=envi.open('./data/cuprite_end.hdr') # 读取cuprite端元光谱库
Cuprite_em=Cuprite_em.spectra.transpose()
spec_data= envi.read_envi_header('./data/cuprite_end.hdr') #读取光谱库的头文件
spec_meta =spec_meta['spectra names']
spec_name=spec_meta['wavelengths']
spec_wl'Spectral Signature of Endmembers') show_spectral(spec_data,spec_name,
2. 光谱分析
光谱分析方法有很多,这里展示常用的一些方法
# 吸收深度计算
from scipy.signal import *
def depthcal(band,spec_wl,l, r,x=None):
if x==None:
=np.argmin(band[l:r])+l
x=(spec_wl[x], spec_wl[l], spec_wl[r])
xwl, lwl, rwl= 1 - (rwl - xwl) / (xwl - lwl)
a = (rwl - xwl) / (xwl - lwl)
b = 1 - band[x] / (a * band[l] + b * band[r])
result return result
=np.array( [float(x) for x in spec_wl])
mus_wl =spec_data[:,6]
mul_data=145
l=165
r=np.argmin(mul_data[l:r])+l
x=depthcal(mul_data,mus_wl,l,r)
specdepthprint(x,specdepth)
# 利用scipy光谱平滑和微分运算
= savgol_filter(spec_data[:,6], window_length=25, polyorder=7)
smooth_spec = np.diff(spec_data[:,6], axis=0) spec_data_diff
157 0.28345667940108465
# 结果可视化展示,为了方便对比,将平滑曲线与一阶微分曲线就做了y轴数值的偏移处理
= plt.figure(figsize=(7, 4))
fig 'seaborn')
plt.style.use(-0.2, label='smooth spectrum', color='black')
plt.plot(smooth_spec+0.2, label='diff spectrum', color='orange')
plt.plot(spec_data_diff6], label='original spectrum', color='darkgreen')
plt.plot(spec_data[:,range(l,r), spec_data[l:r,6], 'blue', label='interval spectrum')
plt.plot(range(l,r),np.max(spec_data), color='lightblue', alpha=0.3)
plt.fill_between(=x, color='r', linestyle='--',label='absorption position')
plt.axvline(x'Bands', fontweight='bold', fontname='Times New Roman', fontsize=12)
plt.xlabel('Reflectance', fontweight='bold', fontname='Times New Roman', fontsize=12)
plt.ylabel('Diagnostic Spectral Features')
plt.title(='upper left', bbox_to_anchor=(1, 1))
plt.legend(loc plt.show()
# 多项式拟合光谱曲线
from scipy.optimize import curve_fit
def fit_func(x, a, b, c):
return a * x**2 + b * x + c
= curve_fit(fit_func, np.arange(len(spec_wl)), spec_data[:,8])
params, params_cov =fit_func(np.arange(len(spec_wl)), *params)
pred
= plt.figure(figsize=(7, 4))
fig 'seaborn')
plt.style.use(8], label='original spectrum', color='darkgreen')
plt.plot(spec_data[:,'orange', label='fitted spectrum')
plt.plot(pred, 'Bands', fontweight='bold', fontname='Times New Roman', fontsize=12)
plt.xlabel('Reflectance', fontweight='bold', fontname='Times New Roman', fontsize=12)
plt.ylabel('Curve Fitting')
plt.title(='upper left', bbox_to_anchor=(1, 1))
plt.legend(loc plt.show()
3. 影像光谱交互采集
# 影像光谱采集
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from IPython.display import display,HTML
import ipywidgets as widgets
%matplotlib widget
def display_image_with_mouse_click(image,rgb):
# 存储点的坐标和通道像元值
= []
selected_points = ['#1f77b4', '#aec7e8', '#ff7f0e', '#ffbb78', '#2ca02c', '#98df8a', '#d62728', '#ff9896']
color_strings
def on_click(trace, points, state):
nonlocal selected_points
if points.point_inds:
= points.xs[0]
x_index = points.ys[0]
y_index
# 添加一个散点图
fig.add_trace(go.Scatter(=[x_index], # 点的横坐标
x=[y_index], # 点的纵坐标
y='markers',
mode=dict(size=10, color=color_strings[len(selected_points)], opacity=1),
marker
))
fig.update()
# 记录点的坐标和通道像元值
= int(x_index)
x_value = int(y_index)
y_value = image[y_value, x_value]
pixel_values 'x': x_value, 'y': y_value, 'pixel_values': pixel_values})
selected_points.append({# 更新多波段像元值曲线
display_pixel_values(fig_pixel_values, selected_points, rgb, color_strings)
# 绘制像元值曲线
def display_pixel_values(fig, points, rgb, colors):
if len(points) == 0:
return
for i, point in enumerate(points):
if len(fig.data) > i:
# 如果曲线已存在,则更新数据
= np.arange(len(point['pixel_values']))
fig.data[i].x = np.array(point['pixel_values'])
fig.data[i].y = colors[i]
fig.data[i].marker.color else:
# 如果曲线不存在,则添加新的曲线
fig.add_trace(go.Scatter(=np.arange(len(point['pixel_values'])),
x=np.array(point['pixel_values']),
y='lines',
mode='Point {}'.format(i+1),
name=dict(color=colors[i])
marker
))
fig.update()= image.shape
rows, cols, channels
= go.FigureWidget(data=go.Image(z=rgb, colormodel='rgb'))
fig ='Image',
fig.update_layout(title=dict(title='Columns'),
xaxis=dict(title='Rows'),
yaxis='event+select')
clickmode= go.FigureWidget()
fig_pixel_values ='Spectrum Collection',
fig_pixel_values.update_layout(title=dict(title='Band'),
xaxis=dict(title='Reflectance'))
yaxis= cols / rows # 宽高比
aspect_ratio if aspect_ratio > 1:
=500, width=int(500 * aspect_ratio))
fig.update_layout(heightelse:
=int(500 / aspect_ratio), width=500)
fig.update_layout(height
0].on_click(on_click)
fig.data[# 设置鼠标悬停时显示的坐标信息
='X: %{x}<br>Y: %{y}')
fig.update_traces(hovertemplate
=500, width=800)
fig_pixel_values.update_layout(height
# 将FigureWidget放入HBox布局中
= widgets.Layout(display='flex', flex_flow='row', justify_content='space-between')
box_layout = widgets.HBox([fig, fig_pixel_values], layout=box_layout)
hbox
display(hbox)return selected_points
# 定义读取文件
def read_tiff(file):
= Load_image_by_Gdal(file)
img_arr,meta if meta['img_bands'] > 1:
=img_arr.transpose(( 1, 2,0))
img_arrreturn img_arr,meta
='./data/Cuprite_ref188.img'
filepath= read_tiff(filepath)
img_arr,img_meta print(img_arr.shape,img_meta.keys())
(500, 500, 188) dict_keys(['img_bands', 'geomatrix', 'projection', 'wavelengths', 'wavelength_units'])
# 对图像进行增强处理
=linear_stretch(img_arr[:,:,[27,18,9]],True)*255
rgb= display_image_with_mouse_click(img_arr,rgb)
selected_points # 通过交互式选点,可以更准确的获取影像光谱数据,图片可以放大缩小
%matplotlib inline
HBox(children=(FigureWidget({
'data': [{'colormodel': 'rgb',
'hovertemplate': 'X: %{x}<br>Y:…
4. 光谱数据保存为光谱库
# 采集的光谱数据进行保存
=np.array([point['pixel_values'] for point in selected_points])
spectralsprint(spectrals.shape)
show_spectral(spectrals.T)
# 与刚刚光谱库中获取的个端元光谱进行整合,输出为一个样本库集合,注意不同的数据格式不统一,需要进行转换
= np.stack((spec_data[:,6],smooth_spec-0.2,pred), axis=1)
newspec =np.concatenate((newspec*10000,spectrals.T),axis=-1)
newspec_lib show_spectral(newspec_lib)
=['original','smooth','fitting','select1','select2','select3','select4']
spec_name
={}
em_meta'wavelengths']=spec_wl
em_meta['wavelength units']='Micrometers'
em_meta['spectra names'] = spec_name
em_meta[
=envi.SpectralLibrary(newspec_lib.transpose(), em_meta)
spec'./data/new_cuprite_end') spec.save(
请关注微信公众号【45度科研人】获取更多精彩内容,欢迎后台留言!