文章目录
一、Application介绍
- 如下代码可以查看OTB工具箱可访问的应用程序数目与具体名称
import os
import otbApplication as otb
print("otb可访问的应用程序数量:",len(otb.Registry.GetAvailableApplications()))
print("otb可访问的应用程序:\n",str(otb.Registry.GetAvailableApplications()))
- 如下图,共有117个应用程序
二、Application调用方法
2.1 传参方法
2.1.1 可配置参数查看
- 以平滑工具:Smoothing为例,创建实例并查看其可配置参数
os.chdir("E:\\data_manage\\image\\OTB") # 更改当前工作路径
app = otb.Registry.CreateApplication("Smoothing") # 注册"Smoothing"工具
print(app.GetParametersKeys()) # 查看可配置参数
- 如下图,Smoothing工具的基本参数包括:输入、输出、平滑类型以及各平滑类型下的参数等
2.1.2 逐个传参
- 调用Smoothing工具对DEM进行均值平滑,半径设为3,即执行7×7矩形窗口的均值滤波。
app.SetParameterString("in", "./AW3D/DEM-AW3D30.tif") # 输入文件路径
app.SetParameterString("type", "mean") # String类型参数
app.SetParameterInt("type.mean.radius", 3) # Int类型参数
app.SetParameterString("out", "./AW3D/DEM_smooth.tif") # 输出文件保存路径
app.ExecuteAndWriteOutput() # 执行并写入文件
- 如下图,为原始DEM与7×7均值平滑后DEM对比
2.1.3 字典传参
- 通过字典传递参数,更为方便
params = {"in": "./AW3D/DEM-AW3D30.tif"
, "type": "mean"
, "type.mean.radius": 3
, "out": "./AW3D/DEM_smooth1.tif"}
app.SetParameters(params) # 字典传参
app.ExecuteAndWriteOutput()
2.2 Numpy数组连接
-
OTB支持以numpy数组作为图像数据传入Application,故可将其插入gdal、opencv等第三方库的图像处理链中,下面举例说明插入方式。
-
如下所示,使用cv2读取图像,使用降维工具:DimensionalityReduction生成前3个主成分,通过Set/GetVectorImageAsNumpyArray()方法输入或输出numpy格式图像,利用plt成图显示结果。
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
import otbApplication as otb
① 利用cv2读取图片
dog = cv2.imread('E:\\project_manage\\opencv\\images\\dog.jpg',flags=1)
cv2.imshow("dog",dog)
cv2.waitKey(0)
cv2.destroyAllWindows()
② 注册“降维”工具并输出可配置参数
app = otb.Registry.CreateApplication("DimensionalityReduction")
print (app.GetParametersKeys())
③ 设置参数、执行PCA降维、获取输出的numpy图像
app.SetVectorImageFromNumpyArray('in',dog) # 设置多波段numpy为输入
params = {
"method": "pca" # 降维方法为主成分分析
, "method.pca.whiten": "true" # 是否执行"白化",默认为true
, "nbcomp": 3 # 输出主成分个数
, "rescale": "minmax" # 调整输出图像灰度范围,默认0~255
}
app.SetParameters(params)
app.Execute() # 仅执行
dog_pca = app.GetVectorImageAsNumpyArray('out') # 获取app输出的多波段numpy
print('图片尺寸:', dog_pca.shape)
④ PCA降维结果出图
fig,axes = plt.subplots(figsize=(5,4),dpi=200,nrows=2, ncols=2)
plt.subplots_adjust(left=0.02, bottom=0.02, right=0.98, top=0.95, wspace=0.1, hspace=0.15)
axes[0,0].set_title('(a) dog',fontsize=10)
axes[0,0].set_axis_off()
dog_rgb = cv2.cvtColor(dog, cv2.COLOR_BGR2RGB)
axes[0,0].imshow(dog_rgb)
axes[0,1].set_title('(b) dog_pca1',fontsize=10)
axes[0,1].set_axis_off()
axes[0,1].imshow(dog_pca[: , : , 0],cmap='gray')
axes[1,0].set_title('(c) dog_pca1',fontsize=10)
axes[1,0].set_axis_off()
axes[1,0].imshow(dog_pca[: , : , 1],cmap='gray')
axes[1,1].set_title('(d) dog_pca1',fontsize=10)
axes[1,1].set_axis_off()
axes[1,1].imshow(dog_pca[: , : , 2],cmap='gray')
os.chdir("E:\\data_manage\\image\\OTB") # 更改当前工作路径
plt.savefig('./Figure/dog_pca.jpg')
plt.show()
⑤ 制图结果
2.3 内存连接
-
在使用多个Application处理图像的流程中,应用程序之间频繁的图像读/写耗费时间巨大。为提高性能,OTB允许将一个应用程序的输出临时保存至内存,作为下一个应用程序的输入,仅需最后一个应用程序负责写入最终处理结果。
-
如下所示,首先使用降维工具:DimensionalityReduction对遥感影像执行主成分分析,使用GetParameterOutputImage()方法获取主成分输出,对第一主成分执行局部统计特征提取:LocalStatisticExtraction,并利用影像连接工具:ConcatenateImages将第一主成分和局部特征组合为多通道图像。
import os
import otbApplication as otb
① 注册Application
os.chdir("E:\\data_manage\\image\\OTB") # 更改当前工作路径
app1 = otb.Registry.CreateApplication("DimensionalityReduction")
app2 = otb.Registry.CreateApplication("LocalStatisticExtraction")
app3 = otb.Registry.CreateApplication("ConcatenateImages")
② PCA降维
app1.IN = './Sentinel-2/S2B_MSIL2A.tif'
params_1 = {
"method": "pca" # 降维方法为主成分分析
, "method.pca.whiten": "true" # 是否执行"白化",默认为true
, "nbcomp": 1 # 输出主成分个数
, "rescale": "minmax" # 调整输出图像灰度范围,默认0~255
}
app1.SetParameters(params_1)
app1.Execute()
③ 局部特征提取
# 提取4个局部特征:均值(Mean),方差(Variance), 偏度(Skewness)和峰度(Kurtosis)
app2 = otb.Registry.CreateApplication("LocalStatisticExtraction")
# 连接 app1的输出 和 app2的输入
app2.SetParameterInputImage("in",app1.GetParameterOutputImage("out"))
app2.SetParameterInt("channel", 1) # 以输入图像中第1个主成分统计局部特征
app2.SetParameterInt("radius", 2) #窗口大小为:5 =2*radius +1
app2.Execute()
④ 读取输入图像列表(单通道或多通道)并生成单个多通道图像
app3.AddImageToParameterInputImageList("il",app1.GetParameterOutputImage("out")) # 将第1主成分推入app3的输入图像列表
app3.AddImageToParameterInputImageList("il",app2.GetParameterOutputImage("out")) # 将第1主成分的局部统计结果推入app3的输入图像列表
app3.SetParameterString("out", "./Sentinel-2/S2B_PCA_LSE.tif") # 输出文件保存路径
app3.ExecuteAndWriteOutput()
2.4 混合连接(内存/磁盘)
- 混合连接作为OTB应用程序连接的扩展,可以轻松在以下两种模式之间轻松切换,具有更简便的语法:
- in-memery内存模式:可以避免不必要的读写
- on-disk硬盘模式:可以保留中间输出到硬盘上
2.4.1 内存模式
- 该模式使用ConnectImage()方法连接上一个应用程序的输出与当前应用程序的输入,上游应用程序无需调用Execute()方法,仅需对最后一个应用程序执行ExecuteAndWriteOutput()便可嵌套执行所有上游程序,相比2.3中标准内存连接方式更加简便。
- 如下示例,首先利用辐射指数工具:RadiometricIndices 计算植被、水体、建筑表面指数,输出多波段数据,然后利用波段拆分工具:SplitImage 获得每个指数的单通道输出。
① 注册辐射指数工具并输出可配置参数
os.chdir("E:\\data_manage\\image\\OTB") # 更改当前工作路径
app1 = otb.Registry.CreateApplication("RadiometricIndices") # 注册"RadiometricIndices"工具
print(app1.GetParametersKeys()) # 查看可配置参数
② 使用“in-memery”模式连接两个工具,输出指数
params = {"in": "./Sentinel-2/S2B_MSIL2A.tif"
, "list": ['Vegetation:NDVI', 'Water:NDWI2', 'BuiltUp:ISU']
, 'channels.blue' : 1
, 'channels.green' : 2
, 'channels.red' : 3
, 'channels.nir' : 4
}
app1.SetParameters(params)
# 注册波段拆分工具
app2 = otb.Registry.CreateApplication("SplitImage") # "波段拆分"应用程序
app2.ConnectImage("in", app1, "out") # 以app1的输出(多通道指数)作为app2的输入
app2.OUT = './Sentinel-2/S2B_Index.tif'
app2.ExecuteAndWriteOutput()
③ 输出结果
④ RadiometricIndices可计算的遥感指数
2.4.2 硬盘模式
- 对上述代码的最后一个应用程序执行app2.PropagateConnectMode(False)即可切换内存模式为硬盘模式,False表示硬盘模式,True表示内存模式(默认)。
- 此外,当指定混合连接为硬盘模式时,需设置中间应用程序的输出路径,如果不设置,则回退为内存模式。更改后的代码与输出结果如下:
params = {"in": "./Sentinel-2/S2B_MSIL2A.tif"
, "out": "./Sentinel-2/S2B_Indices.tif"
, "list": ['Vegetation:NDVI', 'Water:NDWI2', 'Soil:BI2']
, 'channels.blue' : 1
, 'channels.green' : 2
, 'channels.red' : 3
, 'channels.nir' : 4
}
app1.SetParameters(params)
# 注册波段拆分工具
app2 = otb.Registry.CreateApplication("SplitImage") # "波段拆分"应用程序
app2.ConnectImage("in", app1, "out") # 以app1的输出(多通道指数)作为app2的输入
app2.OUT = './Sentinel-2/S2B_Index.tif'
app2.PropagateConnectMode(False)
app2.ExecuteAndWriteOutput()
2.5 与OTB pipeline进行交互
- 我们知道,使用gdal读取遥感影像、DEM等栅格数据时,可以通过属性或方法获取数据附带的元数据,如投影、仿射变换参数、像素大小与图像的尺寸等等。
- OTB也可实现上述功能,可以与每个Application内部的处理管线进行交互,适用于有输出和输入参数的应用程序。这可作为OTB图像与numpy数组的桥梁,首先保存图像的基本元数据,以numpy格式实现图像处理后,重新将图像元数据赋予处理结果。下方是使用ReadImageInfo工具读取影像元数据的简单示例:
① 注册工具,查看参数
os.chdir("E:\\data_manage\\image\\OTB") # 更改当前工作路径
app = otb.Registry.CreateApplication("ReadImageInfo")
print(app.GetParametersKeys()) # 查看可配置参数
② 读取影像数据并执行,输出元数据
app.SetParameterString("in", "./Sentinel-2/S2B_MSIL2A.tif")
app.Execute()
③ 利用GetParameterValue()方法逐个获取元数据信息
# 查看影像尺寸、像素长宽、传感器、数据类型、投影与坐标系
someKeys = ['sizex', 'sizey', 'spacingx', 'spacingy', 'sensor', 'datatype', 'projectionref']
for key in someKeys:
print(key + ' : ' + str(app.GetParameterValue(key)))
三、总结与展望
- 本篇博客是在参考OrfeoToolBox官方文档的基础上撰写的,本人对示例代码进行了重写,以更全面的展示OTB应用程序的使用技巧,具有一定的参考价值。下方总结了OTB工具箱的特点与优势,并对后续的博客撰写进行了展望。
3.1 OTB的特点与优势
- OTB操作简单,Python API的调用非常容易。
- OTB计算效率非常高,特别适用于循环处理海量遥感影像与栅格数据。
- OTB 能够轻松插入gdal、opencv等空间、图像数据处理库的处理链中,提高工作效率。
- 相比ENVI等可视化遥感应用软件,OTB的功能可能没那么全面,但更适用于科研、开发者。
3.2 展望
- OrfeoToolBox初探系列前两节已经对OTB工具箱的Python绑定、API调用与图像处理链条进行了较为细致的介绍,后续博客的重点则在于对重点应用程序的详细介绍,并会与同类型软件工具在计算效率、计算结果与操作便捷性等方面进行对比。