ARTICLE DETAIL

资讯详情

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

空间数据格式全解析:矢量、栅格、点云与转换实践

空间数据格式全解析:矢量、栅格、点云与转换实践 你有没有被一堆文件后缀搞到崩溃的瞬间处理过空间数据的人基本都经历过这个阶段客户丢来一个文件夹里面是.shp、.dbf、.prj、.cpg你打开发现属性表乱码同事给了一个GeoJSON你用ArcGIS打开发现只有一堆线稿还有人让你把几百GB的影像转成“通用的格式”可到底哪种才算通用我入行前几年就是在这种“空间数据格式”的坑里爬出来的。今天这篇就把它们一次性讲清楚尽量覆盖矢量、栅格、点云三大类把格式背后的设计逻辑、适用场景、常见坑和实操转换路径都过一遍。1. 空间数据格式的底层逻辑从数据本质到存储目的1.1 矢量、栅格、点云三种数据“方言”空间数据格式本质上解决一个问题把现实世界的地理对象变成计算机能读、能算、能画的东西。现实世界太复杂计算机只能“简化”。目前主流简化方式就三种矢量、栅格、点云。矢量的核心是几何对象加属性。比如一栋房子在矢量世界里就是一组坐标点围成的面再加上“楼号、层数、用途”这些表格字段。它的优点是精度高、占存储小、支持拓扑关系适合做规划分析、地籍管理、路网建模。你平常用的Shapefile、GeoJSON、GeoPackage基本都是这一类。栅格的核心是像元也就是像素。遥感影像、全球DEM、土地利用分类图本质都是一张张格网每个格子里填一个数值。你可以把栅格理解成照片只不过每个像素带的是“海拔”“温度”“反射率”这类物理量而不是颜色值。栅格的优点是数据结构简单、非常适合连续表面的分析和图像处理缺点也是明显的——文件往往很大放大到一定比例尺会发虚。点云就比较特殊了它是一大群三维坐标点每个点还带有强度、颜色、分类等信息。用激光雷达扫一遍街区得到的不是面也不是格子而是几千万甚至上亿个点。点云的好处是能精确表达三维结构和细节坏处是数据量极大必须依赖压缩和高效索引才能正常操作。常见后缀.las、.laz就属于这一类。为什么开头先强调这三种因为几乎所有空间数据格式都能归到这三类之一。但很多人搞不清格式是因为先搞不清数据类型。拿着一个GeoTIFF去问“为什么不能像Shapefile那样用”本质是拿栅格格式去套矢量需求那当然不行。先想清楚你的数据是点线面、是格网、还是三维点云再去选格式方向就不会偏。1.2 文件、数据库、网络服务格式设计的三重目标空间数据格式并不仅仅是文件后缀它背后有三种完全不同的设计目标。第一种是文件交换和分发。比如一个城市的地块数据要交给合作伙伴最自然的形式就是打包成一个Shapefile或GeoPackage发过去。这类格式追求的是“别人能直接打开”兼容性最重要什么拓扑、版本管理都得往后靠。第二种是数据库存储。当数据量达到百万级要素、需要多人并发编辑时把数据丢进一个文件就不合适了。PostGIS就是PostgreSQL的“空间版”它把几何信息做成专门的二进制类型配合空间索引能实现秒级查询和并发事务。你会接触到的空间数据格式其实也包括这种“数据库内部格式”比如PostGIS的geometry类型以及Esri FileGDB。第三种是网络服务。浏览器里刷在线地图背后是瓦片、矢量瓦片还有WMS、WFS、WMTS这类OGC标准接口。这些格式设计出来就不是给你直接拷贝的而是为了在网络上高效传输和实时渲染。最常见的例子就是GeoJSON前端拿到一个请求就能画出一片地图。理解了这个分类你就明白为什么老工程师总爱强调“按场景选格式”这句话——没有最好的格式只有最合适的格式。这句话不是套话因为不同格式根本不是一个维度上的东西。你要做在线可视化你偏要下个Shapefile再导入绕一大圈你要做长期归档你偏用在线瓦片服务那也不行。1.3 从专有格式到开放标准历史如何影响选型空间数据格式的历史其实就是一条从“厂商锁定”到“开放标准”的演进线。早年ArcGIS影响太大Shapefile、Coverage、FileGDB都是Esri定义的你离开Esri生态就很难受。后来Google Earth普及KML被推了一把再后来Web GIS兴起GeoJSON、TopoJSON这类格式因为JavaScript天然亲和成了前端事实标准。现在OGC开放地理空间联盟推出GeoPackage希望用一个SQLite文件统一矢量、栅格和瓦片不少国家的基础测绘已经把GeoPackage定为分发标准。这条历史线对实际选型有一个重要启发优先拥抱开放、有标准背书的格式尽量别碰没文档的私有格式。不是说私有格式不能用而是数据要活几十年格式的生命力远比你的项目周期长。我见过不少老项目数据用ArcGIS打包好版本一换打不开了数据全部干瞪眼。开放格式至少给了你一种“逃命”的可能——哪怕原软件没了开源社区还有工具链能把它捞出来。2. 矢量格式深度拆解Shapefile、GeoJSON、GeoPackage及冷门格式2.1 Shapefile一个文件不算文件暗坑一大堆说Shapefile是空间数据的“祖宗”一点不过分。1990年代Esri设计了它直到今天它仍然是整个行业默认的交换格式之一。但绝大多数新手不知道Shapefile根本不是单个文件而是至少三个文件的集合——.shp存几何.shx存索引.dbf存属性.prj存坐标系.cpg存编码。你只拷一个.shp给别人对方大概率打不开纯粹就是少了“兄弟文件”。这还不是最坑的。Shapefile有几个硬伤我整理一下字段名长度限制10个字符中文或者长英文直接被截断属性类型很弱日期经常被当成字符串。.dbf默认编码是ANSI在不同环境下打开中文乱码是家常便饭。单个文件上限2GB对大矢量数据不友好。一个文件只能存一种几何类型点线面不能混装。不自带空间索引规模一大范围查询速度就让人着急。既然这么麻烦为什么还在用因为兼容性强到夸张几乎所有GIS软件都能打开Shapefile哪怕是20年前的老古董。所以我的建议是Shapefile可以作为“交换格式”但别拿它当“工作格式”。真要长期干活尤其涉及大数据量我一般直接进PostGIS或GeoPackage。如果你必须用Shapefile交付记得打包成zip里面完整带上.prj和.cpg。.cpg里写UTF-8能避免相当一部分中文乱码。还有一个经验是交付之前用QGIS重新打开一次确认能正常显示再发出去。这一步看着笨但能拦住80%的返工。2.2 GeoJSONWeb地图的“通用语”但不是万能药GeoJSON是JSON格式的地理数据规范2016年更新为RFC 7946。它最大的好处是文本化、人类可读、JavaScript天然能解析。Leaflet、Mapbox、OpenLayers这些前端库喂给它们的矢量数据有一半以上是GeoJSON。但正因为它是文本所以有两个明显的短板文件体积大——几何是双精度浮点十万个点存成文本几十MB轻轻松松没有空间拓扑——同一个点重复出现多次数据冗余严重修改一个公共边界要改动很多地方。GeoJSON的坐标顺序也值得单独说规范要求是“经度纬度”也就是先x后y对应EPSG:4326。很多人习惯写“纬度经度”尤其是在科学计算里翻车概率极高。我遇到过前端画出来的线直接跑到海上去了最后发现是坐标对调。如果你的GeoJSON要用来长期存储或大数据分析建议把它当“中间格式”就好——在脚本流程里转来转去用一下最终落库还是转成GeoPackage或者PostGIS。临时使用没问题永久归档别选它。2.3 GeoPackage我目前最推荐的新一代容器如果你只能记住一个新格式那我希望是GeoPackage。它是OGC在2014年发布的标准底层是一个SQLite数据库文件后缀.gpkg。这意味着你所有的矢量图层、栅格瓦片、属性表都能装进这一个文件里用标准SQL去查。相比ShapefileGeoPackage没有字段名10字符限制没有2GB硬限制理论支持非常大的数据量实际受文件系统管理支持空间索引RTree支持矢量栅格混装也支持分块瓦片。我实测过同样一份全国路网数据GeoPackage比Shapefile体积小大概两到三成查询却快了很多。更重要的是GeoPackage是纯开放标准有OGC背书GDAL、QGIS、GeoPandas等一堆开源库都原生支持。交给别人的时候只有一个文件不会出现“少了.prj”这种破事。我现在做项目分发第一选择就是GeoPackage。劣势也得讲清楚SQLite的并发写性能一般不适合多人同时在线编辑如果数据特别巨大比如几十GB以上单文件管理反而吃亏不如直接进PostGIS。选型没有银弹但GeoPackage在绝大多数中小型项目的确是那个“最不后悔”的选项。2.4 KML/KMZ、FileGDB、WKT/WKB快速扫盲KML是Google Earth的“母语”本质是XMLKMZ则是压缩打包过的KML。它在三维地表展示里很好用Google Earth和Google Maps都支持嵌套样式、气泡弹窗是它的独有能力。但要正经做空间分析KML就太笨重了解析慢坐标还是经纬度无投影不适合大数据处理。FileGDB是Esri的文件地理数据库表面看是.gdb文件夹里面一堆文件。它支持拓扑、网络、注记、版本管理这些复杂结构在ArcGIS生态里功能很强。但开源软件读写FileGDB受限GDAL目前只能读写文件地理数据库基本要依赖Esri官方SDK或商用许可。你的工具链如果偏开源碰FileGDB会很痛苦。WKT/WKB是几何对象的文本和二进制表示方式不属于文件格式却无处不在。PostGIS入库、坐标输出、API返回结果都可能遇到WKT或WKB。WKT长这样POINT (116.39 39.9)WKB是二进制形式紧凑且高效。这个知识点建议牢记因为你会不断在数据库日志和报错信息里看到它们。3. 栅格与点云格式深度拆解GeoTIFF、NetCDF、LAS/LAZ3.1 GeoTIFF与COG遥感影像的主流与进化GeoTIFF本质上是TIFF图像加上了地理参考信息。它可以是一个波段也可以是多波段比如红绿蓝加近红外。每个像素是一个数值数值的含义完全取决于你的数据类型。举个例子高程模型DEM像素值就是海拔单位米遥感影像像素值可能是DN值数字量化值需要定标公式转成反射率。很多人做遥感时把像素值当“颜色”直接看图只能看个大概真正做分析必须理解像素背后的物理含义。GeoTIFF之所以是事实标准是因为几乎所有遥感软件和几乎所有数据处理库都原生支持包括GDAL、Rasterio、ENVI、ArcGIS、QGIS。它支持内部压缩也支持金字塔概览和分块存储。从实践角度看GeoTIFF就是栅格界的“Shapefile”——兼容性極高但本身也存在一些性能问题。这里要重点讲一个变体COGCloud Optimized GeoTIFF也就是云优化GeoTIFF。COG的核心不是压缩算法而是把数据组织成“可随机访问”的结构。想象一本厚书普通TIFF你要从头翻到尾才能找到某一页而COG就像带详细目录和页边索引的书你翻到哪一页都很快。配合HTTP Range请求服务器不需要加载整个文件就能把你要的那块影像发给客户端做在线预览流畅得多。生成COG用GDAL一行命令就够gdal_translate input.tif output_cog.tif -of COG -co COMPRESSDEFLATE -co BLOCKSIZE512BLOCKSIZE512很关键它决定分块大小。分块太小HTTP请求次数太多太大则浪费带宽。512是社区实践下来比较稳妥的折中。3.2 NetCDF自描述的多维科学数据NetCDF通常出现在气候、海洋、大气分析等科学领域文件后缀.nc。它和GeoTIFF最大的区别是NetCDF能存多维数组。比如全球气温数据维度是时间、纬度、经度、高度四个维度叠在一起你随时可以沿任意维度切片。而GeoTIFF只能表达二维平面时间序列你得一个时相一个文件地堆。NetCDF还是自描述的文件内部就带变量名、单位、坐标轴、属性。哪怕没有外部说明文档你也能读出来“这个变量是温度单位是开尔文时间轴是每月”。这一点在很多科学数据集里非常救命——最怕给一堆二进制数据没有解释文档谁也不知道里面是什么。处理NetCDFPython生态最常用的是xarray一句xr.open_dataset(data.nc)就能打开。GDAL其实也能读但它看到的往往只是其中一个时间片用起来不方便。如果你要做气候预测、洋流模拟这类科学计算建议直接学xarray配合维度重排和插值效率比在GIS软件里硬啃高得多。3.3 LAS/LAZ点云压缩存储与处理点云格式最常遇到的是LAS由ASPRS组织维护后缀.las。LAS文件里每个点记录坐标X、Y、Z还有强度、颜色、分类等。分类值是整数例如2是地面点5是植被6是建筑具体分类号含义有标准规定。LAS是二进制读取效率高但完全没有压缩动辄几个GB。后来出现了LAZ也就是对LAS做无损压缩压缩率通常能达到3到5倍。3GB的LAS压缩成LAZ后可能只有700MB。做点云处理和传输如果没有特殊原因我都建议用LAZ。点云不像栅格那样方便直接“看图”需要依赖专门的索引结构。PDAL是点云处理的经典工具支持过滤、分类、切片、格式转换。把LAS转成LAZpdal translate input.las output.laz --writers.las.compressionlaszip我接过一个机载LiDAR项目原始点云185GB全部转成LAZ配合PDAL流式处理和切片整个工作流从“磁盘不够”变成了“半小时跑完”。压缩格式在这里帮了大忙。4. 实操环节用Python打通格式转换全流程4.1 环境安装别再一个个pip了要玩转空间数据格式绕不开开源地理计算库。核心是GDAL几乎所有矢量栅格读写都靠它。Python生态里Fiona负责矢量Rasterio负责栅格GeoPandas把矢量数据直接变成DataFrame。有些朋友习惯pip install但GDAL其实是有C底座的pip装很容易踩版本坑。我强烈建议用conda统一装conda create -n geo python3.11 conda activate geo conda install -c conda-forge geopandas rasterio pyproj shapely fionaconda-forge上的预编译包非常成熟装完就能用基本不会碰到“找不到libgdal”这类问题。装好之后验证python -c from osgeo import gdal; print(gdal.VersionInfo())能打印出版本号说明GDAL已经就绪。4.2 矢量转换演练Shapefile转GeoJSON和GeoPackage先用GeoPandas把Shapefile读进来再转成GeoJSONimport geopandas as gpd gdf gpd.read_file(rD:\data\building.shp) print(gdf.head()) gdf.to_file(rD:\data\building.geojson, driverGeoJSON)这段代码看起来很轻松但有几个细节值得注意。第一read_file会自动读取.prj里的坐标系信息但如果原始Shapefile没有.prjGeoPandas默认会把数据当成EPSG:4326坐标很可能错得离谱。第二写GeoPackage只需要换drivergdf.to_file(rD:\data\building.gpkg, layerbuilding, driverGPKG)GeoPackage支持分层一个文件里可以放多个图层。我给别人的工作文件里经常一个.gpkg同时放建筑、道路、边界三个图层接收方在QGIS里一目了然不用再管理一堆散文件。4.3 栅格转换演练GeoTIFF转COG栅格转COG用Rasterio和命令行GDAL都行。Rasterio版本大致这样import rasterio with rasterio.open(input.tif) as src: profile src.profile.copy() profile.update(driverCOG, compressDEFLATE) with rasterio.open(output_cog.tif, w, **profile) as dst: dst.write(src.read())命令行GDAL更简单直观gdal_translate input.tif output_cog.tif -of COG -co COMPRESSDEFLATE -co BLOCKSIZE512转完COG之后我建议再试一下gdalinfo output_cog.tif检查输出的Metadata里有没有LayoutCOG字样。如果没显示多半是版本不支持COG驱动需要升级GDAL到3.1以上。还有一个容易被忽略的点COG应该保留原始坐标系如果原影像坐标系就已经“飞”了转COG只是换容器并不会修复坐标问题。4.4 坐标系与数据校验动手前必须做的两件事空间数据格式另一个容易翻车的点是坐标系。先明确经纬度数据一般对应EPSG:4326Web Mercator投影是EPSG:3857国内常见坐标系包括CGCS2000以及一些投影分带坐标系。不同坐标系之间必须做转换否则图层叠加时位置全部偏移。用GeoPandas转坐标系gdf_wgs84 gdf.to_crs(epsg4326) gdf_web gdf_wgs84.to_crs(epsg3857)转换本身不复杂复杂的是“你根本不知道原数据是哪个坐标系”。.prj文件丢失但坐标值看起来像投影坐标这种情况一定别硬猜。建议用已知控制点做交叉验证或者让数据来源方补充坐标系信息。坐标系的脏活在没有可靠说明的情况下宁可停下来问清楚也不要继续处理。还有一个老生常谈某些国内互联网地图平台使用的坐标基准和WGS84不完全一样存在非线性偏移。这类坐标必须通过对应技术文档给出的方法处理不能单纯用一个固定差值平移。如果项目里能不用这类坐标就尽量不用如果必须接入一定要在文档里确认它的坐标基准否则数据进了GIS就是“满天飞”。提示做完任何格式转换先输出一遍数据的边界范围total_bounds。如果范围数值非常离谱比如经度跑到几百万那几乎可以断定坐标系搞错或坐标顺序反了回到源头排查。5. 常见问题与排查技巧实录5.1 中文乱码与路径问题先说最简单的坑中文路径。Windows下GDAL对中文路径的历史支持一直不太好。最省心的方案是项目目录尽量用英文和数字。实在避免不了在Python里处理路径时也要明确告诉GDAL文件路径的编码方式尽量减少乱码和“无法识别”的问题。然后是属性表乱码。Shapefile的.dbf属性默认编码不是UTF-8而是本地系统代码页。如果打开中文乱码先看文件夹里有没有.cpg文件。有.cpg的内容一般是UTF-8或GBK没有则用QGIS手动指定编码再读。你可能会问为什么前面反复强调弃用Shapefile因为转成GeoPackage或GeoJSON之后编码问题基本消失.cpg、.dbf这类历史包袱统统不用管了。5.2 几何无效与坐标漂移前阵子处理一份全国社区边界数据用GeoPandas计算面积时频繁报错最后排查发现里面全是无效多边形。矢量数据的多边形可能自相交、有重复节点、形成空洞这跟坐标系无关是数据本身“脏”。检查几何有效性用一条语句print(gdf.geometry.is_valid.sum(), len(gdf))出现无效几何经典修复手段是buffer(0)gdf[geometry] gdf.geometry.buffer(0)buffer(0)的原理是给几何做一个宽度为0的缓冲利用图形修复规则把自相交等异常清理掉。但要注意对拓扑关系极复杂的数据buffer(0)也可能让边界形状轻微变化所以修复前一定要备份原始数据。坐标漂移则是另一类高频问题。明明底图是CGCS2000坐标你把WGS84数据叠上去发现位置偏移十几米甚至几百米。这不是“格式”问题是“坐标系”问题。不管建筑、道路还是POI跨应用前都要先确认坐标系再做精确转换别用附近地区的近似参数。5.3 大数据量性能优化空间数据动辄GB级格式选对之后还得会优化性能。对矢量数据第一建议是建空间索引。Shapefile需要重建.shx索引GeoPackage会自动维护RTree索引PostGIS要手动CREATE INDEX ON table USING GIST (geom);。索引建好之后范围查询速度能提升好几个数量级。没有索引的空间数据就跟没有目录的书一样找一页要翻遍全书。对栅格数据COG的“分块概览”是最核心的优化手段。生成COG时GDAL会自动创建概览金字塔前端显示小比例尺时直接引用低分辨率层不用解析高分辨率层速度自然快。如果数据是上千个零散GeoTIFF更聪明的做法是先建VRT虚拟栅格gdalbuildvrt mosaic.vrt *.tifVRT只保存元数据和路径不复制数据既能统一读取又省空间。确认无误之后再决定要不要嵌合成一个大COG。5.4 项目选型速查按场景对号入座使用场景优先选择原因避免Web地图可视化GeoJSON / MVT前端解析方便流式加载Shapefile桌面GIS分析GeoPackage / Shapefile兼容性广QGIS/ArcGIS都能开无科学数据处理NetCDF / GeoTIFF支持多维数组和自描述Shapefile点云存储与交换LAZ压缩率高无损工具链成熟未压缩LAS大型企业级生产库PostGIS并发、权限、索引、事务单个GeoPackage长期归档GeoPackage / GeoTIFF / LAZ开放标准生命周期长FileGDB等私有格式这张表不是金科玉律但它覆盖了我这些年遇到的大多数场景。真正选型的时候再结合团队工具链、甲方交付要求、数据更新频率去调整会更稳妥。踩过这么多坑之后我现在接到任何涉及空间数据的项目第一件事永远是问清数据来源、坐标系、精度、更新频率然后统一归档成GeoPackage加COG这套组合。不是因为它们最“新”而是因为它们都是开放、稳定、有完整工具链支撑的格式十年后大概率还活着数据也还能打开。空间数据格式这件事说白了就是“用稳定的方式描述复杂世界”。希望这篇梳理能帮你少走弯路下次再有人丢给你一堆文件后缀你能一眼看出该在哪里下功夫。
返回列表