坐标系统与投影变换:从 WGS84 到 Web Mercator

本文系统讲解遥感与 GIS 中的坐标系统与投影变换,覆盖 WGS84 与 CGCS2000 基准差异、地理坐标与投影坐标的区别、EPSG 编码体系、Web Mercator 的工程妥协与面积失真、GCJ-02 偏移成因,以及 GDAL 与 PROJ 的重投影实操、仿射变换参数与栅格重采样选型、瓦片金字塔分辨率计算与跨带拼接的精度控制要点。

引言

每一份遥感影像都同时携带两套坐标语言:一套描述「地球上的哪个位置」,即地理坐标;另一套描述「栅格里的第几行第几列」,即像素坐标。这两套语言之间的翻译层,就是坐标系与投影。工程上几乎所有棘手的空间数据问题,追根溯源都能落到这一层:两份影像叠不上、面积算不准、瓦片错位几百米、跨带拼接出现缝隙。

难点不在于公式,而在于选择。地球是不规则椭球,把它铺平成平面必然产生变形,而变形只能被转移、不能被消灭。等角投影保住形状却扭曲面积,等积投影反过来,等距投影只在特定方向上成立。工程师要做的不是找到完美投影,而是判断当前业务真正在意哪一个量,然后接受剩下两个量的损失。

第二个难点是一致性。数据在流水线里经过重采样、切片、拼接、入库,每一次坐标变换都可能引入微小舍入误差,误差会在层级间放大。生产环境里最常见的事故不是投影选错,而是坐标系标注与实际不符,也就是元数据撒谎:文件头写着 EPSG:4326,实际数据却是 GCJ-02 偏移过的坐标。

本文按「基准到投影,再到工程落地」的顺序展开。先讲椭球与基准,再讲投影变形与 Web Mercator 的取舍,然后覆盖国内坐标系偏移、GDAL 与 PROJ 重投影实操、仿射变换与栅格重采样,最后落到瓦片分辨率与金字塔计算。想先建立整体图景的读者,可回看 遥感与空间数据总览 ;涉及文件读写细节的部分,参见 GDAL 栅格数据读写 。

目录

  1. 大地基准与参考椭球
  2. 地理坐标系与投影坐标系
  3. EPSG 编码与坐标系识别
  4. 投影变形的数学本质
  5. Web Mercator 的工程妥协
  6. 国内坐标系与偏移问题
  7. GDAL 与 PROJ 重投影实操
  8. 仿射变换与栅格重采样
  9. 瓦片金字塔与分辨率计算

1. 大地基准与参考椭球

坐标系的第一层是椭球体。地球并非正球,赤道半径约 6378137 米,极半径约 6356752 米,扁率约 1/298.257。不同历史时期、不同国家测得的椭球参数略有差异,常见的有 WGS84、GRS80、Krassovsky 1940、Clarke 1866 等。椭球本身只是几何形状,还不足以定位。

第二层是基准(Datum),它规定了椭球如何与真实地球对齐,包含椭球参数、原点位置与定向。WGS84 是 GPS 使用的全球基准,历经多次精化,现在实际等同于 ITRF 的某个历元实现。CGCS2000 是中国 2008 年启用的国家大地基准,椭球参数与 WGS84 极为接近(长半轴完全相同),两者在米级精度上通常可互换,但严格来说 CGCS2000 是 ITRF97 历元 2000.0 的实现,与 WGS84 存在厘米到分米级差异。

椭球对比(长半轴 a / 扁率倒数 1/f)
WGS84        6378137.0 / 298.257223563
GRS80        6378137.0 / 298.257222101
CGCS2000     6378137.0 / 298.257222101
Krassovsky   6378245.0 / 298.3

工程含义很直接:把 CGCS2000 与 WGS84 视为同一套坐标,在米级应用中安全;但在厘米级测量或长距离控制网中必须做基准转换,用七参数或格网改正。北京 54 与西安 80 使用的是 Krassovsky 椭球,与 WGS84 差异可达百米量级,绝不能混用。

1.1 基准转换的两种路径

基准转换有解析与格网两条路线。解析法用布尔沙-沃尔夫七参数模型,包含三个平移、三个旋转和一个尺度因子,适合大区域、精度要求到分米级的场景。

七参数模型(X,Y,Z 为地心直角坐标)
| X' |   | Tx |        |  1   -Rz   Ry |   | X |
| Y' | = | Ty | + (1+s)|  Rz   1   -Rx | · | Y |
| Z' |   | Tz |        | -Ry   Rx   1  |   | Z |

格网法用密集的格网点存储残差,插值精度可达厘米级,代价是数据体积大、依赖特定区域。国内常用的 CGCS2000 到西安 80 转换就提供格网文件。选择原则是:跨洲或全球用七参数,单国高精度用格网,同一基准内换投影则完全不需要基准转换。

需要强调的是,基准转换与投影变换是两个独立步骤,顺序不能颠倒。先做基准转换把坐标落到目标椭球上,再做投影把椭球展平。把两步合成一次操作是常见错误来源,因为大多数工具库的 -s_srs 到 -t_srs 会自动串起这两步,手工拼接变换链时容易漏掉其中一环。

1.2 高程基准

水平坐标之外还有高程基准,国内用 1985 国家高程基准,基于黄海平均海平面;GPS 直接给出的是椭球高,两者相差一个大地水准面差距(geoid undulation),在国内范围约为 -10 米到 +40 米。

gdalinfo -stats dem.tif | grep -i "no data\|band"   # 查看统计与 NoData

gdalwarp -s_srs "+proj=longlat +datum=WGS84 +geoidgrids=egm96_15.gtx" \
  -t_srs EPSG:4326 in.tif out.tif   # 用 EGM96 格网把椭球高转正高

DEM 与影像配准、洪水淹没分析、土方计算都依赖正确的高程基准。忽略大地水准面差距会带来十几米的系统性偏差,这在平原地区足以决定一片区域是否被判定为淹没区。

2. 地理坐标系与投影坐标系

地理坐标系(GCS)用经纬度描述位置,单位是度,坐标范围经度 -180 到 180、纬度 -90 到 90。它的关键性质是角度单位不可直接用于量算:一度经度在赤道约 111.32 公里,在北纬 60 度只剩约 55.66 公里。因此「缓冲区半径 1000 度」这类写法毫无意义。

投影坐标系(PCS)把椭球展平到平面,单位是米或英尺,可以直接计算距离、面积、方向。常见的有 UTM(通用横轴墨卡托,全球分 60 带)、高斯-克吕格(国内 3 度带与 6 度带)、Web Mercator(EPSG:3857)、Albers 等积圆锥(常用于全国统计)。

选择顺序通常是:先按精度需求确定基准,再按业务量算需求确定投影。需要面积统计就用等积投影,需要导航和形状保持就用等角投影,需要局部高精度距离就用局部横轴墨卡托并控制离中央经线的距离。投影坐标系还带假东假北偏移,例如 UTM 的东偏移固定加 500000 米以避免负值,国内高斯投影常在 Y 坐标前加带号。

2.1 投影按保真属性分类

类型保真量失真量典型投影适用场景
等角局部角度与形状面积墨卡托、横轴墨卡托导航、地形图
等积面积角度与形状Albers、Lambert 方位等积面积统计、密度图
等距特定方向距离其他方向距离等距圆柱、方位等距航程、雷达覆盖
折中各项均不保真但误差可控全部Robinson、Winkel Tripel世界地图出版

没有投影能同时保角又保积,这是高斯绝妙定理的直接推论。工程上选择投影的第一步永远是问「这个业务最终要算什么量」。

2.2 度与米的换算陷阱

在 EPSG:4326 下用缓冲区、相交、距离等操作时,GEOS 与 PostGIS 会按平面几何处理,把度当米算。纬度 30 度处一度约 96 公里,一度经度约 111 公里,误差量级是十万倍。

-- 错误:在 4326 上按度数做缓冲区
SELECT ST_Buffer(geom, 0.01) FROM parcels;

-- 正确:转成米制投影后再缓冲,或使用 geography 类型
SELECT ST_Buffer(geom::geography, 1000)::geometry FROM parcels;

-- 或显式投影到 UTM
SELECT ST_Transform(ST_Buffer(ST_Transform(geom, 32650), 1000), 4326)
FROM parcels;

geography 类型内部按球面计算,适合跨带、跨大洲的距离与缓冲区,代价是计算比平面几何慢数倍,且部分函数不支持。频繁查询的场景应预先投影到米制坐标系并建空间索引。

3. EPSG 编码与坐标系识别

EPSG 数据集是坐标系的事实标准注册表,用整数编码标识一套完整定义。日常打交道最多的几个:

EPSG名称单位典型用途
4326WGS 84 经纬度度数据交换、GPS、GeoJSON
3857WGS 84 / Pseudo-Mercator米Web 地图瓦片
4490CGCS2000 经纬度度国内基础地理数据
32650WGS 84 / UTM zone 50N米华东区域量算
4547CGCS2000 / 3 度带 117E米国内工程测量
3395WGS 84 / World Mercator米需要真实墨卡托时

识别数据真实坐标系不能只看元数据。实践中用三重校验:一是读文件头里的 WKT 或 EPSG;二是抽查已知地物的坐标是否落在合理范围,比如上海应该在东经 121 度附近,如果出现 12100000 这类数字说明是加了带号的投影坐标;三是把数据与底图叠加目视检查,偏移规律若是整体平移,多半是基准或偏移算法问题。

gdalinfo -json input.tif | jq '.coordinateSystem.wkt'   # 读 WKT 定义

gdalsrsinfo EPSG:4547                                  # 查 EPSG 定义详情

gdalsrsinfo -o proj4 EPSG:4326                         # 输出 proj 字符串

需要注意坐标系缺失的情形:很多裁剪或格式转换工具会丢掉投影信息,得到的文件仍可显示但无地理意义。流水线里应当把「坐标系非空且符合预期」作为一道校验门禁,而不是等下游出错再回溯。

3.1 WKT 的版本差异

坐标系的文本描述用 WKT 表达,存在 WKT1 与 WKT2 两个不兼容的版本。GDAL 3 默认输出 WKT2:2019,而很多老系统只认 WKT1。差异体现在轴序、单位声明与参数命名上,例如 WKT2 显式写出 ORDER[1], LENGTHUNIT 等节点。

WKT1 片段
PROJCS["CGCS2000 / 3-degree Gauss-Kruger CM 117E",
  GEOGCS["China Geodetic Coordinate System 2000",
    DATUM["China_2000", SPHEROID["CGCS2000",6378137,298.257222101]],
    UNIT["degree",0.0174532925199433]],
  PROJECTION["Transverse_Mercator"],
  PARAMETER["central_meridian",117],
  UNIT["metre",1]]

跨系统交换时如果对方只支持 WKT1,用 gdalsrsinfo -o wkt1 显式降级,不要依赖自动转换。PROJ 6 之后 EPSG 定义会在转换时自动规范化,但这一步在极少数自定义坐标系上会改变参数,需要在接入新坐标系时做一次往返测试。

3.2 自定义坐标系

当 EPSG 注册表里没有合适的定义时,用 proj 字符串或 WKT 自定义。常见于特定工程的局部坐标系、需要调整中央经线的横轴墨卡托、以及带特殊假东假北的矿区坐标。

from pyproj import CRS

local = CRS.from_proj4(
    "+proj=tmerc +lat_0=0 +lon_0=117 +k=1 +x_0=500000 +y_0=0 "
    "+ellps=GRS80 +units=m +no_defs")
print(local.to_epsg())        # None 表示无对应 EPSG 编码
print(local.to_wkt()[:80])

自定义坐标系必须随数据一起分发定义文件,否则下游无法解析。实践中更稳妥的做法是把它注册到本地 EPSG 库或封装成带 WKT 的 GeoPackage,避免每次靠字符串传参。

4. 投影变形的数学本质

墨卡托投影的公式是 x = R·λ,y = R·ln(tan(π/4 + φ/2))。它的等角性质来自纬度方向的拉伸正好补偿经度方向的拉伸,代价是面积随纬度急剧放大。比例因子在纬度 φ 处为 sec φ,也就是 1/cos φ。

import math

def mercator_scale(lat_deg):
    return 1.0 / math.cos(math.radians(lat_deg))

for lat in (0, 30, 45, 60, 75, 85):
    print(f"lat={lat:>3}  scale={mercator_scale(lat):.3f}")

输出会显示北纬 60 度面积放大 2 倍,北纬 75 度放大约 3.86 倍,北纬 85 度放大约 11.5 倍。这解释了一个著名现象:在 Web Mercator 底图上格陵兰看起来比非洲还大,而非洲实际面积是格陵兰的 14 倍。

各典型纬度的面积放大系数:

纬度比例因子 sec φ面积放大典型城市
0°1.0001.00×新加坡
23.5°1.0901.19×广州
39.9°1.3031.70×北京
51.5°1.6062.58×伦敦
60.0°2.0004.00×赫尔辛基
75.0°3.86414.93×北极科考站

要在 Web Mercator 上得到近似真实面积,可以把面积乘以 cos²φ 校正,但这只在局部小范围内有效,跨纬度的大区域必须重新投影。

4.1 横轴墨卡托的分带逻辑

横轴墨卡托把圆柱横放,使圆柱面切于某条经线(中央经线),从而在南北方向拉长覆盖范围。分带是为了把离中央经线的距离控制在变形可接受范围内。

高斯-克吕格 3 度带
带号 n = round(L / 3)
中央经线 L0 = 3n
东偏移 = 500000 m + 带号 × 1000000(部分规范)
最大离中央经线距离 = 1.5° ≈ 167 km
边缘变形 ≈ 1/3000

UTM 6 度带
带号 n = floor((L + 180) / 6) + 1
中央经线 L0 = 6n - 183
比例因子 k0 = 0.9996
东偏移 = 500000 m,南半球北偏移 = 10000000 m

带号与中央经线的换算是高频出错点。3 度带 117E 对应带号 39,6 度带 117E 对应带号 50,两者容易混淆。工程上建议直接用 EPSG 编码(4547 对应 CGCS2000 3 度带 117E,32650 对应 UTM zone 50N)而不手工推导。

高斯-克吕格与 UTM 用横轴墨卡托加中央经线分带的方式控制变形,把变形限制在带内。3 度带在中央经线处比例因子为 1,边缘最大变形约 1/3000;6 度带边缘变形约 1/800,所以高精度量算应选 3 度带。UTM 则刻意把中央经线比例因子设为 0.9996,让变形在带内分布更均匀,代价是中央经线上距离被压缩 0.04%。

变形规律决定了使用纪律:面积统计不要在 Web Mercator 上做,跨带量算必须先统一到同一投影,全国范围统计优先用 Albers 或等积方位投影。

5. Web Mercator 的工程妥协

Web Mercator(EPSG:3857)是 2005 年前后由 Google Maps 推广的投影,本质上不是严格的墨卡托:它把椭球当作正球处理,直接使用 WGS84 的长半轴 6378137 米作为球半径,忽略扁率。这导致它在同一位置上与真实墨卡托(EPSG:3395)有最大约 20 公里的位置偏差,但换来一个巨大的工程优势——正球墨卡托公式极简,瓦片切分与像素映射可以纯整数运算。

具体规格:坐标范围 x 与 y 均为 ±20037508.34 米(即 π·R),纬度截断在 ±85.05112878 度,因为再往极地方向 y 趋于无穷。这个截断值是使地图成为正方形的纬度,atan(sinh(π)) 的度数形式。

Web Mercator 关键常量
R              = 6378137.0 m
x/y 范围       = ±20037508.342789244 m
纬度截断       = ±85.0511287798066°
瓦片尺寸       = 256 px(或 512 px 高清瓦片)
层级 0 覆盖    = 1 张瓦片覆盖全球

层级 z 的分辨率公式是 resolution = 2·π·R / (256 · 2^z)。层级 0 约为 156543 米/像素,每加一级减半,层级 18 约 0.6 米/像素,层级 22 约 0.037 米/像素。这个公式是所有切片服务的公共基础,细节见 瓦片服务与切片金字塔 。

工程取舍很清楚:Web Mercator 适合显示与交互,不适合量算与统计。如果业务既要在网页上展示又要在后端统计面积,正确做法是存两份几何或做实时投影转换,而不是在 3857 上直接算面积。

6. 国内坐标系与偏移问题

国内最容易被忽视的是 GCJ-02 与 BD-09。GCJ-02 是国测局在 WGS84 基础上加非线性偏移得到的加密坐标,俗称火星坐标;BD-09 是百度在 GCJ-02 上再叠一层偏移。偏移量在 300 到 700 米之间随机分布,没有公开的解析公式,只能靠拟合算法近似还原。

坐标系来源与 WGS84 偏差常见数据源
WGS84全球基准0GPS 原始、卫星影像
GCJ-02国测局加密300~700 m高德、腾讯地图
BD-09百度二次加密GCJ 基础上再偏百度地图
CGCS2000国家基准厘米~分米级国家基础测绘成果

实践中的判定方法:把数据叠加到天地图或高德底图上,如果道路与影像整体错开几百米且方向随机,就是坐标系不一致。处理原则是整条流水线统一到一套坐标,转换集中在入口做一次,中间环节不再反复变换。反算 GCJ-02 到 WGS84 用迭代逼近即可收敛到厘米级。

import math

X_PI = math.pi * 3000.0 / 180.0
A = 6378245.0                 # Krassovsky 长半轴
EE = 0.00669342162296594323   # Krassovsky 第一偏心率平方

def out_of_china(lng, lat):
    return not (73.66 < lng < 135.05 and 3.86 < lat < 53.55)

def gcj_to_wgs(lng, lat, iterations=3):
    wlng, wlat = lng, lat
    for _ in range(iterations):
        glng, glat = wgs_to_gcj(wlng, wlat)
        wlng += lng - glng    # 残差回代,逐次逼近
        wlat += lat - glat
    return wlng, wlat

注意偏移算法的常数基于 Krassovsky 椭球而非 WGS84,这是历史实现遗留,改动它反而会与主流库不兼容。这类数据合规与偏移问题在测绘领域属于敏感话题,工程实现时应当保留原始坐标并做可追溯的转换记录。

7. GDAL 与 PROJ 重投影实操

GDAL 3.x 之后坐标转换统一由 PROJ 6+ 承担,最大的行为变化是轴序处理:EPSG:4326 官方定义是纬度在前经度在后(lat, lon),而绝大多数工具和习惯用法是经度在前。GDAL 3 默认遵循官方轴序,但在 gdalwarp 与 ogr2ogr 等命令行工具中会做兼容处理,编写代码时则要显式指定。

gdalwarp -s_srs EPSG:4326 -t_srs EPSG:4547 \
  -r bilinear -tps \
  -tr 10 10 -te 400000 3450000 500000 3550000 \
  -of GTiff -co TILED=YES -co COMPRESS=DEFLATE \
  input.tif output.tif

gdalwarp -t_srs EPSG:3857 -r near input.tif webmerc.tif   # 切片前重投影

ogr2ogr -f GeoJSON -t_srs EPSG:4326 out.geojson in.shp    # 矢量重投影

-tps 启用薄板样条变换,适合控制点重投影;-r 指定重采样算法;-tr 与 -te 明确输出分辨率与范围,避免默认按输入外接矩形推导出奇怪的网格。批量处理时用 gdalwarp 的 -overwrite 配合 xargs -P 并行,比写 Python 循环快得多。

Python 侧用 rasterio 或 pyproj:

import rasterio
from rasterio.warp import calculate_default_transform, reproject, Resampling

with rasterio.open("input.tif") as src:
    transform, width, height = calculate_default_transform(
        src.crs, "EPSG:4547", src.width, src.height, *src.bounds)
    kwargs = src.meta.copy()
    kwargs.update(crs="EPSG:4547", transform=transform,
                  width=width, height=height, compress="deflate")
    with rasterio.open("output.tif", "w", **kwargs) as dst:
        for i in range(1, src.count + 1):
            reproject(
                source=rasterio.band(src, i),
                destination=rasterio.band(dst, i),
                src_transform=src.transform, src_crs=src.crs,
                dst_transform=transform, dst_crs="EPSG:4547",
                resampling=Resampling.bilinear)

calculate_default_transform 会自动处理外接矩形与像元大小,是重投影的标准入口。pyproj.Transformer 则用于点级转换,构造一次可复用,比反复调 transform 函数快一个量级。

8. 仿射变换与栅格重采样

栅格的像素坐标与地理坐标通过仿射变换关联,GDAL 用六个参数描述:左上角 x、x 方向像素宽、行旋转、左上角 y、列旋转、y 方向像素高(通常为负)。

GeoTransform = (x0, dx, rx, y0, ry, dy)
x_geo = x0 + col * dx + row * rx
y_geo = y0 + col * ry + row * dy

正常北朝上的影像 rx 与 ry 为 0,dy 为负值。若 rx 与 ry 不为零,说明影像有旋转,很多切片工具和显示库不支持旋转,需要先用 gdalwarp -r near 摆正。行列为零时得到左上角坐标,这也是为什么 GDAL 的 bounds 需要显式减去半个像素来得到像元中心。

重采样算法决定了重投影后的信息损失:

算法适用数据特点
near分类图、掩膜、标签不产生新值,保类别纯净
bilinear连续光谱数据平滑,会轻微模糊边缘
cubic影像产品比双线性锐,可能过冲
cubicspline高质量影像更平滑,计算量大
lanczos降采样保高频,可能振铃
average升尺度按面积加权,适合统计
mode分类图降采样取众数,保类别
sum计数类栅格汇总而非平均

分类结果、云掩膜、土地覆盖必须用 near 或 mode,用双线性会造出不存在的类别值。光谱数据用 bilinear 或 cubic。做区域统计降采样时用 average 或 sum,取决于量纲。

9. 瓦片金字塔与分辨率计算

切片前的准备工作有一套固定流程:统一投影到 EPSG:3857、摆正旋转、按目标层级重采样、对齐到瓦片网格。最后一步最容易出错,因为瓦片网格要求影像的左上角坐标必须是瓦片尺寸的整数倍。

gdalwarp -t_srs EPSG:3857 -r bilinear -of GTiff \
  -co TILED=YES -co BLOCKXSIZE=512 -co BLOCKYSIZE=512 \
  -co COMPRESS=JPEG -co JPEG_QUALITY=85 \
  input.tif aligned.tif

gdal2tiles.py --profile=mercator --zoom=8-16 \
  --resampling=bilinear --processes=8 \
  --webviewer=none aligned.tif ./tiles

--profile=mercator 生成标准 XYZ 瓦片,--zoom 指定层级范围。生成的目录结构是 z/x/y.png,注意 TMS 与 XYZ 的 y 轴方向相反,混用会导致上下颠倒,这是切片环节最经典的 bug。

分辨率与层级的关系需要背下来:resolution(z) = 156543.03392804097 / 2^z 米/像素(256 像素瓦片)。要在网页上显示 1 米分辨率影像,需要 z ≥ 18;要显示 0.5 米,需要 z ≥ 19。反过来,如果数据源本身只有 10 米分辨率,切到 z=19 只是把每个像元放大成 4×4 的色块,白白增加存储与传输。

import math

R = 6378137.0
ORIGIN = math.pi * R           # 20037508.342789244

def tile_bounds(z, x, y):
    size = 2 * ORIGIN / (2 ** z)
    minx = -ORIGIN + x * size
    maxx = minx + size
    maxy = ORIGIN - y * size     # XYZ 规范 y 向下增长
    miny = maxy - size
    return minx, miny, maxx, maxy

def resolution(z, tile_px=256):
    return 2 * ORIGIN / (tile_px * 2 ** z)

print(tile_bounds(10, 843, 388))   # 上海一带瓦片范围
print(resolution(10))              # 约 152.87 m/px

注意瓦片尺寸 512 时分辨率翻倍,同一层级覆盖范围不变但像素数变四倍。矢量瓦片常配 512 以避免高 DPI 屏上的模糊。

跨带拼接是另一个高频问题。国内用 3 度带时,一个省可能横跨三到四个带,各带坐标差异达数十万米。正确做法是先把所有分带数据转成经纬度,再统一投影到覆盖全域的等积投影(如 Albers)或按业务需求选定的单一投影。直接拼接不同带的数据,会在带边界出现明显错位。多时相分析中同样要注意这一点,参见 变化检测工程实践 。

权衡取舍

  • 基准选择:全球业务用 WGS84 最省事,国内合规数据用 CGCS2000,两者米级可互换,厘米级必须做七参数转换。
  • 投影选择:显示与交互用 Web Mercator,面积统计用 Albers,局部高精度量算用 3 度带高斯投影。
  • 存储坐标系:源数据保留原始坐标系,只在服务层重投影,避免多次变换累积误差。
  • 重采样算法:分类数据一律 near,光谱数据 bilinear,统计降采样 average,不要一套算法走到底。
  • 精度与体积:切片层级每加一级体积翻四倍,按数据源真实分辨率设上限,避免切出无信息的高层级。
  • 偏移处理:GCJ-02 转换集中在入口做一次并留痕,流水线中不允许出现多套坐标系混存。
  • 动态转换 vs 预转换:实时转换省存储但每次查询有开销,预转换快但占空间,按查询频率决定。

常见坑清单

  • 元数据坐标系错误:现象是数据叠不上底图,原因是文件头 WKT 与实际不符,规避方法是用已知地物坐标做双重校验。
  • 轴序颠倒:现象是点位跑到南极或坐标反号,原因是 EPSG:4326 官方轴序为纬度在前,规避方法是在代码里显式声明 always_xy 或统一用 Transformer。
  • Web Mercator 算面积:现象是极区面积虚高数倍,原因是墨卡托面积随纬度放大,规避方法是改用等积投影后再统计。
  • 分类图用双线性重采样:现象是掩膜出现 0.5 这类不存在的类别值,原因是插值产生了中间值,规避方法是分类数据只用 near。
  • TMS 与 XYZ 混淆:现象是瓦片上下颠倒,原因是 y 轴方向定义相反,规避方法是统一使用一种规范并在配置里注明。
  • 旋转影像未摆正:现象是切片后出现黑色斜边,原因是 GeoTransform 含旋转项,规避方法是切片前用 gdalwarp 摆正。
  • 跨带直接拼接:现象是省界处出现阶梯状错位,原因是不同带假东偏移不同,规避方法是先统一到同一投影再拼。
  • 重复重投影累积误差:现象是数据经过多次转换后位置缓慢漂移,原因是每次重采样都有插值损失,规避方法是保存原始数据只做一次变换。
  • 无投影信息文件进库:现象是下游渲染空白,原因是裁剪工具丢掉了 CRS,规避方法是在流水线入口加 CRS 非空校验。
  • 分辨率与层级不匹配:现象是瓦片体积巨大但画面模糊,原因是切片层级超过源数据真实分辨率,规避方法是按源分辨率倒推最大层级。

小结

坐标系统的核心矛盾是「三维地球到二维平面的不可逆损失」。理解椭球与基准的层级关系、等角与等积投影的取舍、Web Mercator 为何牺牲精度换取简洁,是做出正确工程决策的前提。国内项目还要额外处理 GCJ-02 偏移,把它当作数据治理问题而不是纯算法问题。

落地层面,GDAL 3 与 PROJ 6 之后的重投影行为有明确规范,记住轴序、显式指定分辨率与范围、按数据类型选择重采样算法,可以避免绝大多数事故。切片与跨带拼接的关键都在「先统一、再处理」这个顺序上。

下一步建议结合 影像基础与元数据 理解各传感器产品的坐标系约定,再通过 瓦片服务与切片金字塔 把坐标知识落到服务端实现;涉及点云数据时,投影选择还会影响高程精度,可参考 LiDAR 点云处理 。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「遥感与空间数据」更多文章

  1. 云原生遥感处理
  2. 卫星平台与任务规划
  3. 高光谱遥感处理