十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ENVI shp转ROI与栅格掩膜提取批量避坑指南

ENVI shp转ROI与栅格掩膜提取批量避坑指南 做遥感影像处理的人早晚会撞上这么一个需求手上有一份矢量边界文件shp想把栅格影像里跟它对应的那一块单独抠出来做后续的统计、分类或者建模。这个动作在ENVI里通常被拆成两步——shp转roi再用ROI对栅格做掩膜提取。听起来简单两步操作而已但真到动手的时候坐标系对不上、ROI跑到影像外面、掩膜出来一片空白、背景值把有效数据覆盖掉各种状况轮番上阵。这篇东西写给两类人一类是刚开始用ENVI做区域裁剪的在校生和刚入行的技术人员另一类是已经会手动点鼠标、但一遇到批量任务就头疼的老手。我不打算把ENVI的帮助文档抄一遍而是把这条链路上真正会出问题的地方、参数背后的逻辑、以及批量脚本怎么写按我自己的处理习惯捋一遍。文中涉及的函数名和参数在不同ENVI版本里会有出入写脚本之前先在IDL命令行敲一下帮助以本机版本为准这是基本习惯。1. 先把链路想清楚shp转ROI到底解决什么问题很多人一上来就问哪个按钮能转其实更应该先问我为什么要转。ENVI里的ROI感兴趣区本质上是建立在某个栅格文件坐标系之上的矢量或像素集合它跟独立的shp文件最大的区别在于ROI必须依附于一个参考影像它的坐标表达是相对于这张影像的。理解这一点后面80%的报错都能自己推出来。1.1 三个最常见的落地场景区域统计与制图。手里有一份行政边界或者流域边界的shp要把覆盖全省或者全流域的影像裁成一个个单元分别统计NDVI均值、地表温度、水体面积。这类需求的特点是要素数量中等几十到几百个但每个要素都要单独出一份结果。分类结果的后期提取。影像已经做完了监督分类现在要按地块矢量把分类结果提取出来算各地块的类别构成甚至进一步做土地利用转移矩阵。这时候shp往往来自二调、三调或者自己矢量化的小班数据多边形数量可能上千形状也很琐碎。样本区的圈定与复用。做纹理特征提取或者机器学习分类时训练样本经常是用shp整理好的。把shp转成ROI之后可以在ENVI里反复叠加显示、随时增删、导出成样本文件比每次都去翻shp方便得多。这三个场景对精度和速度的要求完全不一样。第一个场景更在意边界像元怎么算第二个场景更在意批量效率第三个场景更在意ROI能不能灵活编辑。想清楚自己属于哪一类后面的参数选择就有方向了。1.2 三条技术路线别死磕一条我见过太多人认准了shp必须转成ROI结果几百个多边形转了半个多小时还没转完。其实同样的目标有三条路可以走各有各的适用区间。路线核心操作优势代价建议场景Ashp→ROI→掩膜ENVI内部完成ROI可视化可反复调整、可叠加检查、ROI能存能复用要素多时转换慢ROI文件体积大要素少于500个需要人工核对Bshp→栅格化→掩膜先用外部工具把shp烧成0/1栅格再Apply Mask速度快结果确定适合几百上千要素需要额外工具边界处理要自己定规则大批量、规则明确、无人值守C外接矩形裁剪直接用shp的范围框裁影像最快一步到位只保留矩形边界外的无效数据还在前期快速预览、临时出图路线A是这篇的重点因为它是ENVI用户最自然的路径也是坑最多的路径。路线B我会在掩膜那一节详细说因为很多人不知道掩膜不一定非得有ROI。路线C严格说不算掩膜只是裁剪范围但实际工作中用它先缩小数据量、再走A或B效率会高很多。提示如果只是为了让影像小一点、后续处理快一点先用外接矩形把范围压下来再做精细掩膜。我处理全省范围的影像时这一步能省掉一半以上的内存占用。2. 动手前的数据体检九成的翻车都埋在这里跳过这一步直接开干大概率会在转ROI或者掩膜的时候卡住。ENVI的报错信息通常很简短Unable to open shapefile或者ROI is empty不会告诉你到底是哪出了问题。所以与其事后排查不如提前把数据过一遍。2.1 坐标系对不上是最贵的一课shp转ROI的核心动作是把shp的几何坐标换算到参考影像的坐标系里。如果两边坐标系不一致而且ENVI又没法自动完成转换结果只有两种ROI完全落在影像范围外一片空白或者位置严重偏移错位几百米到几公里。判断方法很直接打开shp的属性看它有没有投影信息。一套完整的shp至少包含.shp、.shx、.dbf三个文件如果还有.prj说明带了坐标系定义。没有.prj的shp就是裸坐标ENVI只能按数值硬套这时候如果shp是经纬度而影像是投影坐标单位是米那转出来的ROI坐标数值会小得可怜直接跑到影像原点附近。我的处理习惯是宁可先重投影shp也不让ENVI自己猜。用外部工具把shp的坐标系调整到与栅格完全一致再进ENVI转换。有一类情况特别隐蔽——shp和影像都是同一个地理坐标系名称但一个是WGS84经纬度另一个是CGCS2000投影坐标看起来都是2000国家大地坐标系实际上一个是度一个是米转过去必然错位。判断标准不是坐标系名字而是单位。2.2 shp文件完整性检查清单在ENVI里打开shp之前我会按下面这几项过一遍。这些项目用任何一款矢量软件或者简单的文件检查都能完成。文件成套性.shp、.shx、.dbf三个缺一不可少任何一个都可能报打不开。带.prj的更保险。字符编码.dbf里如果有中文字段值需要配套的.cpg文件声明编码否则属性表里的中文会变成乱码。字段名乱码会影响后续按属性分组转ROI。几何有效性自相交、悬挂节点、重复点这些几何问题在矢量软件里看着没问题转ROI的时候可能产生面积为零的退化多边形。做一次拓扑检查比事后排查便宜。字段名长度部分旧版工具对字段名长度有限制超过10个字符的字段名可能被截断导致按字段分组时找不到目标字段。多部件多边形一个要素里包含多个不相连的多边形multipart转成ROI后可能变成一个ROI里的多个部分也可能被拆成几个独立ROI取决于工具设定。这个差异会直接影响后面掩膜的结果数量。注意路径里带中文、空格、特殊符号在老版本ENVI里是经典翻车点。把工作目录换成纯英文加下划线能避开一大堆莫名其妙的问题。这个习惯我一直保持到现在。2.3 栅格侧要确认的三件事矢量检查完了参考影像本身也有几个点要确认。第一是影像的坐标系和单位道理同上。第二是影像的地理范围可以先在ENVI里打开看一眼记下左上角右下角的坐标等ROI转出来之后对照一下位置是否落在范围内一目了然。第三是影像的数据类型这决定了后面掩膜时背景值能填什么。整型影像没法存NaN浮点影像可以这个细节在掩膜那一节会展开讲。还有一个容易被忽略的点影像是否已经做过几何校正。如果影像本身还有几何形变shp叠上去是对的但影像内部的像素位置是偏的这时候掩膜出来的边界看着没问题实际对应的地物已经跑偏了。这种情况在老影像、无人机拼接成果上比较常见。3. shp转ROI的实操流程与脚本写法数据体检做完进入正题。图形界面的操作适合少量要素和需要人工核对的情况脚本适合批量。我两条都写你按自己的量级选。3.1 图形界面手动转换的完整步骤以ENVI 5.x为例大致路径是这样先在主界面打开作为参考的栅格影像让影像处于激活状态。然后在ROI工具面板里找到导入矢量相关的入口选择目标shp文件。弹出来的对话框里最关键的一项是参考影像的选择——一定要选对那张栅格选错了坐标系ROI就白转。对话框里通常还有几个选项值得注意是否按属性字段拆分ROI、是否为每个要素生成独立ROI、ROI的名称来源字段、颜色分配方式。我的建议是名称来源选一个能唯一标识要素的字段比如编码或者名称不要用默认的ROI #1这种否则后面几十个ROI叠在一起根本分不清谁是谁。转换完成后先别急着做掩膜。把ROI叠加到影像上看一眼这一步花不了一分钟但能省掉后面半小时的返工。检查三个点位置对不对、形状对不对、有没有哪个要素明显缺失或者多出来一块。要素特别多的时候可以只显示其中几个用Go to功能放大到ROI范围看。ENVI 5.x之后的版本图层管理器里可以直接把shp图层转成ROI操作更顺手但批量场景下还是脚本更省事。3.2 用IDL做批量转换要素超过五十个手动点就开始烦了。写个循环把整个文件夹的shp批量转成ROI文件一次跑完。; ENVI Classic 接口下的批量shp转ROI示意 ; 函数签名请以本机帮助文档为准IDL命令行输入 ?envi_shp_to_roi 查看 pro batch_shp_to_roi compile_opt idl2 shp_dir D:\work\shp\ out_dir D:\work\roi\ files file_search(shp_dir, *.shp, count n) if n eq 0 then begin print, 目标目录下没有找到shp文件 return endif for i 0, n - 1 do begin shp_file files[i] base file_basename(shp_file, .shp) out_file out_dir base .roi roi_id 0L roi_names roi_colors 0L ; 关键这个函数需要一个明确的空间参考 ; 不同版本对坐标系参数的写法不同务必核对本机文档 envi_shp_to_roi, shp_file, roi_id roi_id, $ roi_names roi_names, roi_colors roi_colors if roi_id eq 0 then begin print, base 转换失败跳过 continue endif ; 保存ROI到文件 envi_save_roi_file, out_file, roi_id ; 释放资源避免循环里越积越多 envi_delete_roi, roi_id print, base 转换完成 endfor print, 全部处理结束 end这段代码有几个地方要说清楚。第一envi_shp_to_roi这个函数在ENVI Classic接口里是存在的但从ENVI 5.x开始官方更推荐用任务Task的形式函数名和参数结构都变了。所以不要照抄先去IDL命令行敲帮助看一下本机签名这是我一直强调的习惯。第二循环里一定要显式释放ROI对象不释放的话处理几十个文件之后内存会涨得很厉害最后直接崩掉。第三保存ROI文件这一步ENVI 5.x保存出来的.roi其实是XML格式跟Classic的二进制.roi文件不通用跨版本使用的时候要注意。还有一个实用技巧如果shp里有几十上百个要素可以先在矢量软件里按属性筛选只留需要的部分再转而不是全转完再在ENVI里删。ROI的删除操作在数量大的时候同样很卡。3.3 转换结果的验证方法脚本跑完之后别直接进入下一环节先做三重验证。数量验证shp里有多少个要素理论上应该转出多少个ROI对不上就说明有要素被吞了或者被合并了。多部件要素、面积为零的退化多边形是最常见的被吞对象。范围验证随机抽几个ROI用定位功能跳过去看跟shp在原软件里的位置对比。这一步能抓出坐标系问题。属性验证如果ROI名称来自shp字段检查一下中文是否正常显示编码问题在这一步就能发现。4. 栅格掩膜提取参数选对了才算真正做完ROI有了接下来是用它去抠影像。ENVI里跟这个动作相关的工具有好几个名字很像功能有重叠选错了要么结果不对要么多绕一大圈。我按使用频率从高到低说。4.1 用ROI直接裁剪最常用的一条路ENVI Classic里有个专门按ROI裁剪栅格的工具ENVI 5.x对应的菜单项通常叫Subset Data via ROIs或者类似的名字。这个工具的核心逻辑是以ROI为界保留ROI内或外的像元其余置为背景值。对话框里几个参数值得细说。输出范围可以选择按ROI限定输出范围这样输出的文件是ROI的外接矩形不是原图那么大能省很多空间也可以选保持原图范围把ROI之外的地方全部填背景值。前者适合做要素级分析后者适合保持整体对齐。掩膜方向保留ROI内还是保留ROI外看需求做区域统计就是保留内。背景值这个参数在下一小节单独讲。边界像元处理是只保留像元中心落在ROI内的像元还是把与ROI相交的像元都算进来这个选择会直接影响面积的统计结果。我最常犯的疏忽是输出文件名重复。批量跑的时候如果不给每个输出文件拼上要素名后一个会把前一个覆盖掉跑完发现只剩一个文件白干。4.2 Build Mask加Apply Mask更灵活的组合拳这是另一条路径先用ROI生成一个掩膜文件一张0/1的图再用这个掩膜去套影像。好处是掩膜可以复用——一次生成的掩膜可以套在同一区域的多期影像上做时序分析的时候特别省事。Build Mask工具里ROI通过ROI_ID传入同时指定是ROI内部为1还是外部为1。生成的掩膜文件本身也是一张栅格跟参考影像同样大小、同样坐标系值只有0和1或者你设定的两个值。有了它之后Apply Mask把掩膜和待处理影像叠加输出就是掩膜过的结果。这条路还有个隐藏优势掩膜文件可以手工编辑。有时候shp的边界跟影像实际情况差那么一两行像元与其回矢量软件改shp再重转一遍ROI不如直接在掩膜文件上画两笔改完再应用。这个技巧在处理边界模糊的水体、云覆盖区域时很好用。对应的经典接口里生成掩膜和应用掩膜有各自的_DOIT函数参数名和ROI结构跟上面说的一致写脚本前同样先查帮助。4.3 批量掩膜的脚本骨架一次要处理几十张影像和几十个要素手动点是不可能的。批量脚本的骨架长这样外层循环遍历影像内层循环遍历ROI或者反过来。选择依据是哪个维度的计算量更大——通常影像数量少、要素数量多那就外层影像、内层要素。核心逻辑就是三句话读取当前影像用当前ROI生成掩膜或直接裁剪把结果写到带命名的输出文件里。真正麻烦的是错误处理——某一张影像的坐标系跟ROI对不上某张影像损坏打不开脚本不能因为一个失败就整个中断要能跳过并记录。我一般会在循环里加一个日志数组把失败的组合记下来跑完之后统一检查而不是中途不停弹窗打断。批量处理还要考虑内存。同一时间只保留一张影像和一个ROI在内存里处理完立刻释放。高分辨率大区域影像一张就可能占几个G堆着不释放跑到第十几张必然崩。4.4 背景值到底填什么一个决定成败的小参数这个参数看着不起眼填错了后面所有统计都是错的。常见的选择有三种各有各的适用条件。填0最省事但危险。如果研究区里本身就有0值比如NDVI里的水体、反射率里的阴影掩膜后的0和原始的0混在一起你根本分不清哪些是真正的数据哪些是填充的。做统计的时候这些0会被当成真实值算进去均值直接被拉低。填NaN浮点影像的优选。NaN在计算中会自动传播做均值、求和的时候会被自动忽略省去手工剔除的步骤。代价是某些格式比如GeoTIFF对NaN的支持不完整存出去再打开可能变成极小的负数或者被当成有效值。稳妥做法是内部处理用NaN最终交付的时候转成其他格式再指定NoData。填一个研究区不可能出现的值比如-9999或者-32768。这是工程上最通用的做法兼容性好任何格式都能存。代价是后续每个统计步骤都要记得把这个值排除掉一旦漏了结果就偏了。所以填这种值的时候一定要在输出文件的元数据里标注清楚或者干脆在文件名上带个标记。我自己的习惯是中间过程用NaN最终成果用-9999并在交付说明里写清楚。这个规则保持统一交接给别人的时候不容易出错。5. 常见报错与排查实录这一节是整篇里最值钱的部分因为大部分内容在帮助文档里查不到都是踩出来的。5.1 问题速查表现象最可能的原因排查顺序shp打不开提示无法读取缺少.shx或.dbf路径含中文或特殊字符先查文件成套性再换纯英文路径ROI转出来是空的坐标系不匹配ROI落在影像范围外对比shp与影像的坐标系和单位ROI位置整体偏移投影带号错误经纬度与投影坐标混用检查两者的坐标单位ROI数量少于shp要素数多部件要素被合并退化多边形被丢弃检查面积为零的要素ROI名称乱码.dbf编码未声明缺.cpg文件补.cpg或统一转UTF-8掩膜结果全是一片背景值掩膜方向选反了保留了ROI外检查保留内/外的设置边界有明显锯齿保留了全部相交像元改用像元中心判定结果面积比理论面积大用了相交像元判定同上统计均值明显偏低背景值0混入了有效值检查背景值设置大批量跑到一半崩掉ENVI对象未释放内存耗尽循环内显式释放ROI和影像对象5.2 边界像元的账怎么算一个被低估的细节shp的边界是光滑的连续曲线影像是离散的格子两者永远不可能完全重合。ENVI处理这个矛盾的方式通常是看像元中心点是否落在ROI内部。落在里面就算落在外面就不算边界上的像元要么全进要么全出。这个规则带来的后果是同一份shp用不同的判定方式做掩膜得到的像元数量和面积可能差百分之几。对于大范围统计比如全省的耕地面积这个误差可以接受但对于小图斑——尤其是比一个像元还小的图斑——可能一个像元中心都没落进去整个图斑直接消失了。反过来如果图斑只比像元大一点点可能只保留下一两个像元形状完全不规则。处理办法有两个方向。一是接受这个误差但在报告里说明用的是像元中心判定让读者知道精度边界在哪。二是对关键的小图斑改用像元相交判定宁可多算一点也要保证图斑不丢然后在属性统计阶段再按面积加权修正。哪种更合理取决于业务要求没有绝对正确的答案最怕的是两种混用而不自知。还有一种情况值得单独说相邻图斑的缝隙。如果两个shp多边形是严格共边的按中心点判定之后公共边界上的像元可能被划给左边也可能划给右边取决于中心点偏向哪边。如果这个像元的数据类型是浮点的NDVI或者温度本身没有问题但如果是要做面积汇总同一个像元只能算一次不会重复这个反而不用担心。真正需要担心的是shp本身存在细微的缝隙或者重叠这种情况下严格按照中心点判定反而能把问题暴露出来比在矢量软件里强行合并更可靠。5.3 几条不写在文档里的经验先小范围试跑。不管多大的批量任务先拿一个要素、一张影像跑通完整链路确认坐标系、参数、输出格式都没问题再放大到全量。这一步十分钟能避免几小时的无效计算。输出命名规则提前定。要素编码加影像日期加处理类型三段式中间用下划线。跑完几百个文件之后名字不清楚等于白跑。我吃过这个亏后来所有批量任务都强制带要素标识。保留中间产物。转出来的ROI文件、生成的掩膜文件都不要删。后面做多期对比或者换参数重跑的时候直接复用就行。ROI文件比shp小掩膜文件占地方但删掉重建的时间成本更高。版本兼容性要留个心眼。ENVI 5.x之前的ROI文件格式跟之后的不一样脚本在旧版本上写完拿到新版本可能直接报错。跨版本交接项目的时候把版本号写进文档比什么都强。掩膜之后做一次目视检查。随机挑三五个结果把掩膜后的影像打开看一眼边界是不是贴着矢量走的有没有明显多出来或者少一块。这一步花五分钟能发现脚本里隐藏的逻辑错误。6. 从单次操作到可复用流程的收尾把这套东西串起来看shp转ROI加掩膜提取这件事真正难的不是操作本身而是在动手之前把数据的坐标系关系、边界判定规则、背景值策略这三个问题想清楚。这三个问题定了剩下的都是体力活写成脚本一遍过。定不下来无论手动还是脚本都是反复返工。我现在处理这类任务的固定动作是数据体检坐标系、文件成套性、几何有效性→ 小范围试跑一遍 → 确认输出参数和命名规则 → 写批量脚本 → 抽样目视检查 → 全量执行。这套流程看起来慢实际上比边跑边改快得多尤其是在要素多、影像大的情况下。最后分享一个我自己一直在用的小习惯每做完一个批处理任务把当时的坐标系、ENVI版本、掩膜参数、背景值这几项记在一个简单的记事本里。下次遇到类似的任务直接翻记录不用重新推一遍。日积月累下来这份记录比任何教程都好用因为它是针对你自己的数据环境长出来的。
返回列表