拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ISCE2输出转GeoTIFF全攻略:从格式原理到ArcGIS出图

说实话ISCE2这个软件跑InSAR是真的强但我用了这么多年最想吐槽的一点就是它的输出格式。跑完topsApp或者stripmapApp得到一大堆.rdr、.h5、.xml在Linux终端里随便看没问题可一旦你想拿到ArcGIS、QGIS里看一眼效果或者把结果整理好交给甲方、给别的项目组做后续分析就绕不开一道坎——转成GeoTIFF。我这篇文章就把ISCE2转tif这件事讲透。不只是给你几条命令而是从输出格式的底层设计逻辑讲起然后给你一套在WSL环境下也能稳定跑的实操方案最后把我踩过的坑——ArcMap 10.2构建金字塔慢成狗、tif导出jpg发灰、相位图转出来花屏——全部捋一遍。适合正在用ISCE2处理Sentinel-1或ALOS数据、需要出图或数据交接的人也适合刚入门InSAR、被输出文件整懵的新手。1. ISCE2的输出格式为什么非要转tif1.1 .rdr/.xml到底是什么ISCE2里最常见的输出格式是.rdr比如filt_topophase.flat、topophase.cor旁边还跟着一个同名.xml文件。很多人第一次看到这堆文件会有点懵数据文件连后缀都没有其实.rdr本质上就是一堆float32的裸二进制数据像极了没有表头的csv而.xml就是它的“表头”描述了数据宽度、高度、起始偏移量、数据类型、像素间距等信息。这里有个很关键的点GDAL是自带ISCE驱动的所以你不需要手动解析二进制。只要把.xml当作输入文件传给GDAL它就能自动按照描述文件去读对应的裸数据。这个驱动是我近两年才发现的在此之前我一直用Python手动读二进制麻烦还容易错。1.2 .h5文件又是怎么回事如果你用的是topsApp流程很多中间结果是放在HDF5文件里的最常见的是interferogram.h5。HDF5是一种层级化的数据容器类似“一个文件里套着一堆文件夹”内部可能有多层路径。ISCE2的干涉图通常存放在/science/SENTINEL1/INTERFEROGRAM/下面。你可以用h5py打开后用list()的方式一层层去看或者用HDFView这个图形工具。HDF5的优势是自描述、支持大数据量、可以存储复杂的数据结构。但对于日常出图、行业软件交换来说它确实有点“学术范”了。ArcGIS不直接认HDF5里的某个数据集QGIS虽然能读但也要你去选子数据集体验一般。1.3 为什么ISCE2不干脆输出tif这个问题我琢磨过。ISCE2的设计思路是一个科研工具不是生产级出图工具。它处理的是雷达坐标系数据很多产品是复数形式包含幅度和相位而GeoTIFF对复数数据本身支持得也没那么好。再说ISCE2的开发者默认用户会在Python环境下做后续分析没必要帮你处理好所有导出需求。另一个原因是雷达数据在未地理编码之前每个像素对应的经纬度不是均匀网格。直接转成GeoTIFF会涉及重采样而这个重采样参数需要用户根据自己的需求去权衡。ISCE2选择把“最后一步”的选择权留给用户。1.4 转成tif之后能解决什么转成GeoTIFF至少有三个实实在在的好处。第一是通用性ArcGIS、QGIS、ENVI、MATLAB、Python的rasterio和gdal都能直接读交付给谁都不需要装ISCE2环境。第二是压缩tif可以选LZW或DEFLATE压缩数据量能小一半以上尤其是浮点数据。第三是坐标信息给tif写入地理参考后就能和矢量数据叠图、做裁剪、做时序分析还能直接扔到地图服务里发布。我敢说只要是做InSAR的人至少有一半时间不是在跑流程而是在折腾数据格式转好tif真的能省下大把时间。2. 环境准备与工具选型2.1 必须装好的三个轮子转tif这件事情我依赖的工具基本就三样GDAL、Python带numpy和osgeo、还有一个能看HDF5结构的h5py。GDAL是核心几乎所有的转换命令都会用到它。如果你用conda管理ISCE2环境可以直接在同一个环境里装GDAL这样不会出现Python版本冲突。conda install -c conda-forge gdal numpy h5py装在同一个环境里的好处是你可以直接调用ISCE2的Python库也能用gdal命令行。我个人不太推荐把ISCE2的数据拷贝到另一个机器上去转格式因为很多时候你还需要ISCE2的辅助脚本配合环境分离后会多出很多沟通成本。2.2 WSL环境下要注意的路径问题我最近很多数据是在WSLWindows Subsystem for Linux里跑的ISCE2用起来整体没问题但路径这一点是真的坑。Windows的D盘在WSL里访问路径是/mnt/d/不是你习惯的D:\。这意味着你从一个ISCE2脚本里输出的路径如果直接拿去Windows下的命令行里执行必然报错。更麻烦的是WSL访问/mnt/目录时I/O性能明显低于访问Linux原生的ext4文件系统尤其大量读写小文件时差距很明显。所以我的建议是ISCE2跑数据时把工作目录放在WSL的home目录下比如~/insar/xxxx等跑完了、转成tif了再拷贝到Windows磁盘上。如果你直接把原始数据放在/mnt/d/下跑处理速度慢是一方面某些步骤还会莫名地中断。还有一个小坑WSL里生成的文件如果路径里带中文或空格部分GDAL版本处理起来很容易出错。我一般强制自己所有目录都用英文小写字母加下划线不给自己找麻烦。2.3 是否需要ISCE2自带脚本ISCE2本身也提供了一些工具辅助格式转换比如imageMath.py可以做波段运算、提取幅度和相位isce2stamps流程里也内置了把结果转成GeoTIFF的逻辑。我的看法是这些自带脚本可以看但别太依赖。一个原因是它们往往对文件命名有假设版本一变就不好使另一个原因是它们的输出方式是按StaMPS的需求设计的不一定符合你自己的出图要求。掌握了通用GDAL转换方法后自带脚本只是锦上添花。3. 核心实操把ISCE2主要产品转成GeoTIFF3.1 最基础的一步无地理参考直接转我先说最简单也最常用的情况你只需要把ISCE2生成的一个float干涉图文件转成tif暂时不关心坐标。比如merged/interferogram/目录下的filt_topophase.flat它对应的描述文件是filt_topophase.flat.xml。gdal_translate -of GTiff -ot Float32 filt_topophase.flat.xml filt_phase.tif这里的-ot Float32是为了确保数据类型不变。如果不加这个参数GDAL会读xml里的数据类型作为参考一般来说也正确但显式指定更稳妥。转换完成后可以先用gdalinfo看看结果gdalinfo filt_phase.tif这时候你会发现Coordinate System is和GeoTransform都是空的这是正常的。我们后面再处理坐标。3.2 复数干涉图怎么处理如果你的干涉图文件是复数SLC级别的干涉图基本是复数直接gdal_translate转出来的tif可能是一个复数类型比如CFloat32。这种tif拿进ArcGIS里基本没法直接看因为ArcGIS对复数栅格支持很差。我建议先把复数分解成幅度和相位两个单波段tif。ISCE2自带的imageMath可以做这件事imageMath.py --evalabs(c) --inputmerged/interferogram/filt_topophase.flat --outputamp imageMath.py --evalatan2(imag(c),real(c)) --inputmerged/interferogram/filt_topophase.flat --outputphase执行之后会生成amp和phase两个二进制文件然后再用gdal_translate分别转tif。如果你更习惯全程用Python也可以直接读取复数后自己算from osgeo import gdal import numpy as np ds gdal.Open(filt_topophase.flat.xml, gdal.GA_ReadOnly) band ds.GetRasterBand(1) data band.ReadAsArray() # 判断是否为复数数组 if np.iscomplexobj(data): amp np.abs(data) phase np.angle(data) else: print(这个文件是实数直接转即可)这个Python思路其实更适合批量处理后面我会给完整脚本。3.3 把DEM和经纬度文件转成tifISCE2在处理时会生成雷达几何下的高程、纬度、经度文件一般在merged/geom_master/目录下比如hgt.rdr、lat.rdr、lon.rdr。这些文件同样带xml转换方式和上面一样gdal_translate -of GTiff hgt.rdr.xml hgt.tif gdal_translate -of GTiff lat.rdr.xml lat.tif gdal_translate -of GTiff lon.rdr.xml lon.tif为什么我要特意强调经纬度文件也要转因为在第4部分做地理配准的时候这两个文件就是“量角器”。没有它们你连参考坐标都找不到。另外hgt.tif转出来后可以很方便地在GIS软件里查看地形起伏也能用来粗看你处理的研究区范围。3.4 从HDF5中提取干涉图如果你的数据来源是interferogram.h5那么直接用gdal_translate读取h5可能会让你面临一堆子数据集选择问题比较繁琐。我更推荐用h5py先摸清数据结构再把关键数组抽出来写tif。一个通用的探查代码import h5py with h5py.File(interferogram.h5, r) as f: def print_attrs(name, obj): print(name, obj.shape, obj.dtype) f.visititems(print_attrs)看完结构后假设干涉图在/science/SENTINEL1/INTERFEROGRAM/interferogram就可以这样写import h5py import numpy as np from osgeo import gdal with h5py.File(interferogram.h5, r) as f: ds f[/science/SENTINEL1/INTERFEROGRAM/interferogram][:] # 如果数据是复数转成相位 phase np.angle(ds) driver gdal.GetDriverByName(GTiff) out driver.Create(interferogram_phase.tif, phase.shape[1], phase.shape[0], 1, gdal.GDT_Float32) out.GetRasterBand(1).WriteArray(phase) out.FlushCache()对HDF5我有个建议转tif之前先把环境里能打的补丁打上别在h5py读大数组时硬等。如果数组太大别一次性读整个数据集用切片分块读避免内存撑爆。3.5 转换时设置NoData值ISCE2的输出里很多无效区域是以0填充的。可是0这个值在相位图里本身也是有效值直接当NoData会误伤。怎么办我通常的做法是结合相干性做掩膜后面会详细讲。如果你只是快速预览可以用-a_nodata把0设为NoDatagdal_translate -of GTiff -a_nodata 0 -ot Float32 filt_topophase.flat.xml filt_phase.tif不过要注意这个操作是“一刀切”如果研究区内正好有0相位值会被错误掩盖。这时候我建议还是先看一眼直方图再决定NoData用多少。3.6 转换时顺手做压缩和金字塔如果你是给大型tif做转换别忘了加压缩参数。这是我常用的组合gdal_translate -of GTiff -ot Float32 -co TILEDYES -co COMPRESSDEFLATE -co PREDICTOR3 -co BIGTIFFIF_SAFER filt_topophase.flat.xml filt_phase.tifTILEDYES表示tif内部按块存储对后续读取和金字塔构建都有好处COMPRESSDEFLATE加上PREDICTOR3对浮点数据压缩效果很好能压缩一大半BIGTIFFIF_SAFER是防止文件超过4GB时生成不了tif。这些参数是单纯的参数含义却能极大地影响后续使用体验特别是当数据要放到ArcGIS里用的时候。4. 坐标与投影处理别让数据“漂移”4.1 为什么ISCE2的输出没有坐标ISCE2输出的雷达坐标文件像素坐标是“行、列”没有WGS84或者UTM的投影信息这是雷达坐标系本身决定的。雷达影像是一个斜距投影不是透视投影每个像素对应的地面位置和距离、多普勒频率、地球椭球参数都有关系。ISCE2的几何文件lat/lon实际上已经做了“每个像素的经纬度”计算但这些经纬度并没有统一写成一个标准GeoTIFF变换矩阵。一句话总结你得先从lat.rdr和lon.rdr里把四个角点的坐标抠出来然后告诉tif“这个文件范围是从左上角到右下角”。4.2 用gdal_translate写入仿射变换一个近似但很快的方法是把经纬度tif读出来取四个角点的经纬度然后直接写进目标tif的仿射变换里。对大多数帧级Sentinel-1干涉图来说经过多视之后像素分辨率已经降到几十米用四角点近似模拟一个均匀网格的误差基本可以忽略。命令层面的思路是这样的gdal_translate -of GTiff -a_srs EPSG:4326 -a_ullr 左上角经度 左上角纬度 右下角经度 右下角纬度 phase.tif phase_wgs84.tif其中-a_ullr后面的四个值分别是左上角X经度、左上角Y纬度、右下角X、右下角Y。注意GDAL遵循的坐标约定是Y轴向上所以左上角纬度通常大于右下角纬度。4.3 从lat/lon文件自动获取角点手动查四个角点太累我一般直接写个Python脚本自动算from osgeo import gdal import numpy as np lon_ds gdal.Open(lon.tif, gdal.GA_ReadOnly) lat_ds gdal.Open(lat.tif, gdal.GA_ReadOnly) lon lon_ds.ReadAsArray() lat lat_ds.ReadAsArray() ul_lon, ul_lat lon[0, 0], lat[0, 0] ur_lon, ur_lat lon[0, -1], lat[0, -1] ll_lon, ll_lat lon[-1, 0], lat[-1, 0] lr_lon, lr_lat lon[-1, -1], lat[-1, -1] print(UL:, ul_lon, ul_lat) print(UR:, ur_lon, ur_lat) print(LL:, ll_lon, ll_lat) print(LR:, lr_lon, lr_lat)拿到角点后你可以用gdal_translate -a_ullr也可以直接用GDAL Python接口写GeoTransformfrom osgeo import gdal, osr # 打开待定标的相位图 ds gdal.Open(phase.tif, gdal.GA_Update) # 近似仿射变换不考虑旋转 pixel_width (lr_lon - ul_lon) / ds.RasterXSize pixel_height (ul_lat - ll_lat) / ds.RasterYSize ds.SetGeoTransform([ul_lon, pixel_width, 0, ul_lat, 0, -pixel_height]) # 设置WGS84 srs osr.SpatialReference() srs.ImportFromEPSG(4326) ds.SetProjection(srs.ExportToWkt()) ds None这个脚本对“用lat/lon做地理参考”的需求已经够用。但要强调这是个近似处理研究区范围特别大或者地形起伏特别剧烈时这种简化会带来一定偏差。如果精度要求高建议用GCP点做精确地理校正或者用ISCE2里的地理编码工具。4.4 投影转UTM出图更好看在GIS里做分析时WGS84经纬度坐标往往不够直观尤其计算面积、距离时会遇到单位是度而不是米的问题。我更习惯把最终产品转成UTM投影。转投影用gdalwarpgdalwarp -t_srs EPSG:32650 -r bilinear phase_wgs84.tif phase_utm50n.tifEPSG:32650是WGS84 UTM 50N对应东经117度到123度区域。你可以根据自己研究区的中央经线替换对应的UTM投影带号。转完之后大多数GIS软件都能直接识别坐标单位是米量距离、算面积都方便。4.5 坐标检查的一个小技巧转换完之后我建议立刻检查一下坐标是否合理。最简单的方法是把研究区的.shp边界文件拖进去叠图看如果偏差明显一眼就能看出来。也可以用gdalinfo看角点坐标是否在预期范围。比如你处理的是北京地区数据那左上角经度应该在115到117附近纬度在39到41附近如果出来的坐标跑到了非洲或者太平洋上肯定是角点顺序搞错了。这个检查步骤我建议每次都做哪怕再熟练也做。踩过一次“全图整体平移了几百公里”的坑之后我就知道这步不能省。5. 常见坑与排查技巧5.1 ArcMap 10.2构建tif金字塔慢到怀疑人生这是个热词也是我当年踩得最深的一个坑。ISCE2转出来的tif如果直接拖进ArcMap 10.2第一次加载它会自动构建金字塔数据量一上来那个进度条能走到你怀疑人生。尤其一个几千乘几千像素的float tif在机械硬盘上构建金字塔动辄十几分钟甚至半小时。后来我学乖了在转tif的时候就直接把金字塔建好gdaladdo -r average --config COMPRESS_OVERVIEW DEFLATE --config BIGTIFF_OVERVIEW IF_SAFER phase.tif 2 4 8 16 32 64这样GDAL会把多个分辨率等级的概视图直接写进tif里ArcMap打开时发现金字塔已经存在就不需要再自己构建了。配合前面提到的TILEDYES和COMPRESSDEFLATEArcMap打开速度能有肉眼可见的提升。另外有个小细节如果你用WSL生成tif后拷贝到Windows金字塔最好在Windows环境下一并生成因为在Linux下生成的overview某些老版本ArcMap识别存在兼容性问题。我遇到过几次“明明有overview但ArcMap还是不认”的情况后来干脆在Windows下用OSGeo4W的命令行再跑一次gdaladdo问题消失。5.2 tif导出jpg发灰的问题这也是一个非常常见的场景。你在ArcMap里看到干涉图色彩还挺丰富但用“文件→导出地图”导出jpg后图片整体发灰对比度极差。原因很简单ISCE2输出的浮点数据动态范围很大但有效信号往往集中在一个很小的数值区间。ArcMap在没有做拉伸的情况下默认按线性全动态范围显示于是大部分像素值被压缩到一个很窄的灰阶区间里看起来就是一片灰。解决思路有两个。第一个是在ArcMap里设置拉伸方式图层属性→符号系统→拉伸→选“百分比截断”或者“标准差”都能有效增强显示。第二个是提前导出8bit增强tif用GDAL的-scalegdal_translate -ot Byte -scale 0 0.5 0 255 phase_wgs84.tif phase_8bit.tif这里的0 0.5是输入数据的有效范围你需要根据数据直方图调整。干涉相位通常范围在[-pi, pi]左右所以-scale -3.14 3.14 0 255也比较常用。导出jpg前如果希望图面更有层次感可以像我一样先转一个8bit增强版本再到ArcGIS里出图这样jpg发灰的问题基本不会出现。5.3 相位图转出来是花屏/噪点很多人第一次转相位图发现看起来全是噪点怀疑自己代码写错了。其实干涉相位在低相干区域本来就是随机相位看起来就是噪点。这是数据本身的问题不是转换的问题。解决办法是先用相干性做掩膜把低相干区域滤掉。gdal_calc.py -A phase_geo.tif -B cor_geo.tif --calcwhere(B0.3,A,0) --outfilephase_mask.tif --NoDataValue0相干性阈值取0.3还是0.5取决于你的目的。如果是快速浏览0.3就行如果是正式成果图我一般取0.4到0.5之间。做完掩膜后再出图视觉效果和成果质量都上一个档次。5.4 坐标偏移或整体漂移这个问题的原因大多是仿射变换里的角点坐标没取对。比如你使用了lat.tif和lon.tif但这两个文件本身没有地理坐标只是纯数据你直接用了它们的数组值当作坐标这样还好但如果你从ISCE2的某个地理编码产品里取坐标可能那里面的行列方向和干涉图不一致一个转置就会导致整幅图翻转。我的排查方法是转换后先在QGIS里叠加一个简单的矢量边界比如研究区的shapefile如果发现平移、翻转、镜像优先检查行列方向是否匹配其次检查角点顺序。还有一个常见错误是经纬度的顺序写反了GDAL的仿射变换顺序是X方向经度在前Y方向纬度在后这个顺序千万别搞混。5.5 大文件超过4GB要开启BigTIFF当你的干涉图范围很大或者波段很多时tif文件很容易超过4GB。标准tif格式限制文件最大4GB基于32位偏移超过就会报错。解决办法很简单在创建tif时加上-co BIGTIFFIF_SAFER这个参数表示如果文件可能超过4GB就自动用BigTIFF格式没超过就用普通tif。ArcGIS 10.2版本支持BigTIFF但如果你要交付给使用老版本GIS的同事建议还是拆分输出或者转成压缩格式免得对方打不开。跟老版本软件打交道能自定义的兼容性问题就尽量避免别给对方添麻烦。5.6 WSL传递文件给Windows时的小问题有时候在WSL里跑完ISCE2转tif把文件拷到Windows后双击打开可能提示没有权限或文件被占用。WSL生成的文件默认权限是Linux用户权限Windows下访问一般不受影响但如果你用VS Code的Remote-WSL编辑过文件可能会有一些锁文件。这个不常见但遇到时先排查文件是否被占用再看路径里是否带特殊字符基本就能解决。还有一点我想单独提醒WSL下使用/mnt/d/挂载盘时大量小文件读写非常慢转tif这种IO密集型操作更是如此。所以我强烈建议先把待处理的ISCE2数据整体复制到WSL内部目录转换完成后再拷回Windows实测速度能提升两三倍。6. 批量自动化与我的日常处理流程6.1 一个可复用的Python批处理脚本处理ISCE2数据时很少只处理一个文件通常是一批。我把自己常用的转换逻辑整理成了一个脚本这里简化后分享出来。脚本做的事情是读取干涉图、提取相位、按四个角点写地理参考、顺手生成带金字塔的压缩tif。#!/usr/bin/env python3 import numpy as np from osgeo import gdal, osr gdal.UseExceptions() def isce_float_to_tif(input_xml, output_tif, nodata_valueNone): ds gdal.Open(input_xml, gdal.GA_ReadOnly) if ds is None: raise RuntimeError(f无法打开: {input_xml}) band ds.GetRasterBand(1) data band.ReadAsArray() # 复数处理 if np.iscomplexobj(data): out_data np.angle(data) # 默认取相位 else: out_data data driver gdal.GetDriverByName(GTiff) out_ds driver.Create( output_tif, out_data.shape[1], out_data.shape[0], 1, gdal.GDT_Float32, options[TILEDYES, COMPRESSDEFLATE, PREDICTOR3, BIGTIFFIF_SAFER] ) out_band out_ds.GetRasterBand(1) out_band.WriteArray(out_data) if nodata_value is not None: out_band.SetNoDataValue(nodata_value) out_band.FlushCache() srs osr.SpatialReference() srs.ImportFromEPSG(4326) out_ds.SetProjection(srs.ExportToWkt()) out_ds None print(f已输出: {output_tif}) # 示例调用 isce_float_to_tif(filt_topophase.flat.xml, filt_phase.tif, nodata_value0)脚本里我只写了最基本的转换和坐标系设置。如果要做第4部分提到的四角点配准你可以在写GeoTIFF之前先读lat.tif和lon.tif把角点算出来再SetGeoTransform。这个逻辑并不复杂完全可以自己加进去。6.2 我的日常处理流程顺序我现在的处理流程已经固定成一套模板了分享给大家参考。跑完ISCE2主流程后第一步先把geom_master目录下的lat、lon、hgt转成tif同时用h5py或者gdal探明干涉图的路径和数据类型。第二步把干涉图复数或float转成相位图tif如果有复数就先用imageMath或numpy提取相位。第三步根据lat/lon计算仿射变换给相位图写入WGS84坐标信息。第四步如果需要分析或出图用gdalwarp转UTM投影同时设置好NoData和掩膜。第五步用gdaladdo预构建金字塔并顺手检查一下压缩率和文件大小。这套流程跑下来从ISCE2原始输出到ArcGIS可直接使用的GeoTIFF十五分钟内基本能搞定数据量大一点也就半小时。比起以前手动一步步转效率提升非常明显。6.3 关于isce2stamps的替代方案如果你用的是isce2stamps流程做时序InSAR那你的结果里其实已经包含了GeoTIFF输出相关的代码路径比如stamps2isce模块会在处理过程中生成一些带坐标的产品。我试用过几次优点是方便缺点是不够灵活——它的输出裁剪范围、命名规则、像元大小都是固定的。如果你只是出个图够用可以试试如果要对成果做精细化处理我建议还是按自己的脚本走一遍。我的体会是工具是死的需求是活的。ISCE2自带的转换功能可以作为备选但自己掌握GDAL转换的核心方法才能应对各种奇怪的交付需求。6.4 一个小技巧保存处理日志最后说一个我自己的习惯。每次跑批量转换时我都会把命令行和脚本输出保存到一个日志文件里python convert_isce_to_tif.py convert.log 21万一转换完发现哪个文件有问题回头翻日志就能快速定位到具体是哪一步出了问题。别小看这一步数据量大时没有日志就等于两眼一抹黑。ISCE2转tif这个过程本身不难难的是批量、稳定、可复现而这些都靠平时积累的这些“笨办法”撑起来。转tif这件事说到底是给数据“换个包装”。但包装换得好不好直接影响后面的使用体验。把这一套流程理顺你就能把更多精力放在InSAR结果的分析上而不是在格式转换里耗时间。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门