惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
Security Latest
Security Latest
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
C
Cybersecurity and Infrastructure Security Agency CISA
Cloudbric
Cloudbric
T
Threat Research - Cisco Blogs
大猫的无限游戏
大猫的无限游戏
C
CXSECURITY Database RSS Feed - CXSecurity.com
阮一峰的网络日志
阮一峰的网络日志
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网
C
Cisco Blogs
V
Vulnerabilities – Threatpost
S
Security Archives - TechRepublic
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
J
Java Code Geeks
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Know Your Adversary
Know Your Adversary
博客园 - 叶小钗
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy International News Feed
P
Palo Alto Networks Blog
博客园_首页
V
V2EX
WordPress大学
WordPress大学
Schneier on Security
Schneier on Security
月光博客
月光博客
博客园 - 司徒正美
Google DeepMind News
Google DeepMind News
TaoSecurity Blog
TaoSecurity Blog
博客园 - 聂微东
酷 壳 – CoolShell
酷 壳 – CoolShell
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
The Cloudflare Blog
罗磊的独立博客
美团技术团队
N
News | PayPal Newsroom
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Last Week in AI
Last Week in AI
K
Kaspersky official blog
Google Online Security Blog
Google Online Security Blog
S
SegmentFault 最新的问题
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tailwind CSS Blog

又见苍岚

COLMAP PatchMatch Stereo 算法详解 事件驱动的状态机框架:从理论到工程实践 Git 在国内网络环境下无法 Push 的排查与修复 —— 配置 Clash 代理 分段五次多项式插值原理详解 路径插值方法深度对比研究 Claude Code 使用指南 OpenClaw 记忆管理与技能创建指南 CBS(Conflict-Based Search)算法详解 A* 算法及其变种详解 OpenClaw 配置多 Agents Windows Powershell 无法加载文件,因为在此系统上禁止运行脚本问题的解决方案 MaxClaw 安装流程 大模型 AI 名词介绍 AList 网盘聚合工具简介 Protobuf 简介与测试 Claude Code 简介以及 GLM 4.7 模型接入 Github 歌词下载工具 163MusicLyrics Python __getattr__ 懒加载 Python TypedDict 机器人仿真平台 Gazebo 安装记录 机器人仿真平台 Gazebo 简介 多机器人路径规划问题(Multi-Agent Path Finding, MAPF)简介 Python exifread 读取修改过的 jpeg 信息错误问题修复 3D 坐标系变换的理解 3D 旋转矩阵基本概念 MongoDB Compass 介绍 Python 环境管理工具 uv Flutter 开发指南 Snipaste 安装下载与黑屏问题解决方案 全局路径规划算法记录 2025 Python 版本性能测试 Flutter Hello World Flutter 安装环境配置 Ubuntu VMware 硬盘扩容后 SMBus Host controller not enabled 报错问题解决 Python NetworkX 教程 Docker GPU 报错 - Failed to initialize NVML Unknown Error 解决方案 Python matplotlib 图表绘制 cuda-toolkit 安装替代 Cuda 与 Cudnn Jinja2 Python 利用 docxtpl 和 Jinja2 生成基于模板的 Word 文档 Docker 实现 CPU 核心隔离 LoFTR 基于 Transformer 的特征提取匹配算法 OmniGlue 特征匹配 SuperGlue 使用图神经网络学习特征匹配 Ubuntu 下将 xlsx 文件按照 sheet 转换为 图片 Python 使用 SQLAlchemy Python FastAPI 教程 openwrt 软路由配置安装 Nav2 地图文件(PGM/YAML)规范标准 3D OBJ 模型转换为 glb 瓦片格式 Python 源码 Redis 数据库介绍 Ubuntu 22.04 内核自动升级导致 MongoDB 7.0.12 错误记录 ubuntu 20.04 安装 ROS Noetic ubuntu 18.04 安装 ROS Melodic VMware Workstation Pro 个人免费版下载、安装、使用指南 Hybrid A-star 路径规划 Reeds-Shepp 曲线 Dubins 曲线 Linux kvm 虚拟机网络不通的问题解决方法 Ubuntu 自动内存清理 BiliBili 缓存视频转 mp4 Python 求解线性规划 3D Gaussian Splatting 官方源码实践记录 ImageMagick 教程 Ubuntu 22.04 安装 Colmap 对数几率 odds Ubuntu nmcli 网络管理工具使用指南 SuperPoint 自监督深度学习特征点提取 SyncTV Music Tag Web 在线音乐信息整理工具 ncm 格式转 mp3 MusicBrainz 音乐元数据百科数据库 Ubuntu 网络流量监控工具 私人云音乐平台 Navidrome 入门 手眼标定 四元数(Quaternions) OHTTPS 实现免费自动 https 证书申请、更新、部署 ubuntu 22.04 安装 CloudCompare 单机 KVM 虚拟机冷迁移 Ubuntu 22.04 使用 mdadm 实现软 raid 小鱼 一键安装 ROS-humble Fluid -46- 基于 Simpletex API 构建公式识别页面 公式识别 API 简介 -- Simpletex 使用 Python web 部署库 waitress 3D Gaussian Splatting for Real-Time Radiance Field Rendering Ubuntu Swap 简介与空间扩展 Ubuntu 24.04 安装 forticlient Clash Verge 使用 MongoDB 7.0.17 集群 Docker 构建源码 Error code - 2013. Lost connection to MySQL server during query 问题解决 Python 日志记录库 loguru 使用指北 Python 实现 Web 日志查看服务 MySQL LOAD DATA LOCAL INFILE 极速数据加载 Image size exceeds limit of 89478485 pixels 解决方案 Docker 使用 NVIDIA GPU 驱动错误解决 阿里云 docker 镜像仓库 Ubuntu中没有wired connected的解决方案 MinIO 简介 subconverter 代理订阅格式转换 修复 node –openssl-legacy-provider is not allowed in NODE_OPTIONS 错误
国内地图瓦片坐标系
Yiwei Zhang · 2025-01-07 · via 又见苍岚

在进行地图开发时,为获取特定经纬度所在区域的瓦片和获取瓦片上像素点对应的经纬度,经常需要进行经纬度坐标与瓦片坐标、像素坐标的相互转换,本文将介绍瓦片坐标相关知识。

瓦片地图

互联网地图服务商的在线地图都通过瓦片的方式提供,称为瓦片地图服务。最常见的地图瓦片是图片格式的,现在有的地图服务商也提供了矢量的瓦片数据,然后在用户端使用Canvas渲染成图片,如node-canvas实现百度地图个性化底图绘制

主要经纬度坐标系

国际标准的经纬度坐标是WGS84,Open Street Map、外国版的Google Map都是采用WGS84;高德地图使用的坐标系是GCJ-02;百度地图使用的坐标系是BD-09。高德地图和百度地图都提供了在线的单向坐标转换接口,将其他坐标系换化到自己的坐标系,但这种转换受限于http url请求字段长度和网络请求延迟,批量处理并不实用。离线相互转换可以通过开源JavaScript库 coordtransform 实现,误差在10米左右。
虽然各地图服务商经纬度坐标系不同,但某一互联网地图的经纬度坐标与瓦片坐标相互转换只与该地图商的墨卡托投影和瓦片编号的定义有关,跟地图商采用的大地坐标系标准无关。

墨卡托投影

墨卡托投影法

瓦片切割和瓦片坐标

对于经过墨卡托投影为平面的世界地图,在不同的地图分辨率(整个世界地图的像素大小)下,通过切割的方式将世界地图划分为像素为$256\times256$的地图单元,划分成的每一块地图单元称为地图瓦片。
地图瓦片具有以下特点:

  • 具有唯一的瓦片等级(Level)和瓦片坐标编号(tileX, tileY)。
  • 瓦片分辨率为 256$\times$256。
  • 最小的地图等级是0,此时世界地图只由一张瓦片组成。
  • 瓦片等级越高,组成世界地图的瓦片数越多,可以展示的地图越详细。
  • 某一瓦片等级地图的瓦片是由低一级的各瓦片切割成的4个瓦片组成,形成了瓦片金字塔。

瓦片切割(瓦片金字塔)

经纬度范围

地理经度的取值范围是 [-180,180],纬度不可能到达90°,通过纬度取值范围为[20037508.3427892,20037508.3427892] ,反计算可得到纬度值为 85.05112877980659。

因此纬度取值范围是[-85.05112877980659,85.05112877980659]。

因此,地理坐标系(经纬度)对应的范围是:最小地理坐标(-180,-85.05112877980659),最大地理坐标(180, 85.05112877980659)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import math

# Given values
y = 20037508.3427892
R = 6378137

# Inverse Mercator projection formula to calculate latitude
# y = R * ln(tan(pi/4 + phi/2))
# Solving for phi
phi = 2 * math.atan(math.exp(y / R)) - math.pi / 2

# Convert the result to degrees
latitude = math.degrees(phi)
print(latitude)
pass

# 输出: 85.05112877980658

地面分辨率(Ground Resolution)

地图以瓦片 (Tile) 方式保存数据,最常用的尺寸是 $256\times256$。

地面分辨率是以一个像素 (pixel) 代表的地面尺寸(米)。以微软 Bing Maps 为例,当 Level 为 1 时,图片大小为$512 \times 512$(4个Tile),那么赤道空间分辨率为:赤道周长/512。其他纬度的空间分辨率则为 纬度圈长度/512。

Level为2时,赤道的空间分辨率为 赤道周长/1024,其他纬度为 纬度圈长度1024。

很明显,Ground Resolution取决于两个参数,缩放级别Level和纬度latitude ,Level决定像素的多少,latitude决定地面距离的长短。

地面分辨率的公式为,单位:米/像素:
$$
\text{ground resolution} = (\cos(latitude * \pi/180) * 2 \pi * 6378137) / (256 * 2 ^\text{ level pixels})
$$
最低地图放大级别(1级),地图是 $512 \times 512$ 像素。每下一个放大级别,地图的高度和宽度分别乘于 2。

2 级是 $1024 \times 1024$像素,3 级是 $2048 \times 2048$ 像素,4 级是 $4096\times 4096$ 像素,等等。

通常而言,地图的宽度和高度可以由以下式子计算得到:
$$
\text{map width }= \text{map height} = 256 \times 2^\text{level pixels}
$$

地图比例尺(Map Scale)

地图比例尺是指测量相同目标时,地图上距离与实际距离的比例。通过地图分辨率在计算可知由Level可得到图片的像素大小,那么需要把其转换为以米为单位的距离,涉及到DPI(dot per inch),暂时可理解为类似的PPI(pixel per inch),即每英寸代表多少个像素。

$256 \times 2 ^{level} / DPI$ 即得到相应的英寸 inch,再把英寸 inch 乘以 0.0254 转换为米。

实地距离仍旧是:$\cos(latitude * \pi/180) * 2 \pi * 6378137 \text{ meters}$; 因此比例尺的公式为:
$$
\text{map scale} = (256 * 2^ {level} / \text{screen dpi} × 0.0254) / (cos(latitude * \pi/180) * 2 \pi * 6378137)
$$
地面分辨率和地图比例尺之间的关系:
$$
\text{map scale} = 1 : \text{ground resolution} * \text{screen dpi} * 0.0254 \text{ meters/inch}
$$

缩放级别 地图宽度、高度(像素) 地面分辨率(米/像素) 地图比例尺(以96dpi为例)
1 512 78,271.5170 1 : 295,829,355.45
2 1,024 39,135.7585 1 : 147,914,677.73
3 2,048 19,567.8792 1 : 73,957,338.86
4 4,096 9,783.9396 1 : 36,978,669.43
5 8,192 4,891.9698 1 : 18,489,334.72
6 16,384 2,445.9849 1 : 9,244,667.36
7 32,768 1,222.9925 1 : 4,622,333.68
8 65,536 611.4962 1 : 2,311,166.84
9 131,072 305.7481 1 : 1,155,583.42
10 262,144 152.8741 1 : 577,791.71
11 524,288 76.4370 1 : 288,895.85
12 1,048,576 38.2185 1 : 144,447.93
13 2,097,152 19.1093 1 : 72,223.96
14 4,194,304 9.5546 1 : 36,111.98
15 8,388,608 4.7773 1 : 18,055.99
16 16,777,216 2.3887 1 : 9,028.00
17 33,554,432 1.1943 1 : 4,514.00
18 67,108,864 0.5972 1 : 2,257.00
19 134,217,728 0.2986 1 : 1,128.50
20 268,435,456 0.1493 1 : 564.25
21 536,870,912 0.0746 1 : 282.12
22 1,073,741,824 0.0373 1 : 141.06
23 2,147,483,648 0.0187 1 : 70.53

像素坐标系和地图图片编码(Bing Maps)

为了优化地图系统性能,提高地图下载和显示速度,所有地图都被分割成 $256 \times 256$ 像素大小的正方形小块。由于在每个放大级别下的像素数量都不一样,因此地图图片(Tile)的数量也不一样。每个tile都有一个XY坐标值,从左上角的 $(0, 0)$ 至右下角的 $(2^{level}–1, 2^{level}–1)$。

例如在3级放大级别下,所有tile的坐标值范围为(0, 0)至(7, 7),如下图:

已知一个像素的XY坐标值时,我们很容易得到这个像素所在的Tile的XY坐标值:

$$ \begin{array}{c} tileX = floor(pixelX / 256) \\ tileY = floor(pixelY / 256) \end{array} $$

为了简化索引和存储地图图片,每个tile的二维XY值被转换成一维字串,即四叉树键值(quardtree key,简称quadkey)。每个quadkey独立对应某个放大级别下的一个tile,并且它可以被用作数据库中B-tree索引值。为了将坐标值转换成quadkey,需要将Y和X坐标二进制值交错组合,并转换成4进制值及对应的字符串。

例如,假设在放大级别为3时,tile的XY坐标值为(3,5),quadkey计算如下:

  • tileX = 3 = 011(二进制)

  • tileY = 5 = 101(二进制)

quadkey = 100111(二进制) = 213(四进制) = “213”

Quadkey 还有其他一些有意思的特性。第一,quadkey 的长度等于该 tile 所对应的放大级别;第二,每个 tile 的 quadkey 的前几位和其父 tile(上一放大级别所对应的tile)的 quadkey 相同,下图中,tile 2是tile 20至23的父tile,tile 13是tile 130至133的父级:

图中每个区域的红色的数字编码,可以记做TileXY。

高德地图瓦片坐标

坐标系定义

**高德地图瓦片坐标与Google Map、Open Street Map相同。**高德地图的墨卡托投影截取了纬度(约85.05ºS, 约85.05ºN)之间部分的地球,使得投影后的平面地图水平方向和垂直方向长度相等。将墨卡托投影地图的左上角作为瓦片坐标系起点,往左方向为X轴,X轴与北纬85.05º重合且方向向左;往下方向为Y轴,Y轴与东经180º(亦为西经180º)重合且方向向下。瓦片坐标最小等级为0级,此时平面地图是一个像素为256*256的瓦片。在某一瓦片层级Level下,瓦片坐标的X轴和Y轴各有$2{Level}$个瓦片编号,瓦片地图上的瓦片总数为$2{Level}\times2^{Level}$。

高德地图 level2 瓦片坐标编号

如上图所示,此时X方向和Y方向各有4个瓦片编号,总瓦片数为16。中国大概位于高德瓦片坐标的(3,1)中。

坐标转换图解

从高德地图坐标转换图解中可以看出,高德地图的坐标转换具有以下特点:

  • 所有坐标转换都在某一瓦片等级下进行,不同瓦片等级下的转换结果不同。
  • 经纬度坐标可以直接转换为瓦片坐标和瓦片像素坐标。
  • 瓦片像素坐标需要结合其瓦片坐标才能得到该像素坐标的经纬度坐标。

坐标转换公式

方法参考:Slippy map tilenames

  • 经纬度坐标(lng, lat)转瓦片坐标(tileX, tileY):

$$
tileX=\lfloor\frac{lng + 180}{360}\times{2^{Level}}\rfloor
$$

$$
tileY=\lfloor{(\frac{1}{2}-\frac{\ln(\tan(lat\times\pi/180)+\sec(lat\times\pi/180))}{2\timesπ}})\times{2^{Level}}\rfloor
$$

  • 经纬度坐标(lng, lat)转像素坐标(pixelX, pixelY):

$$
pixelX=\lfloor\frac{lng + 180}{360}\times{2^{Level}}\times256%256\rfloor
$$

$$
pixelY=\lfloor{(1-\frac{\ln(\tan(lat\times\pi/180)+\sec(lat\times\pi/180))}{2\timesπ}})\times{2^{Level}}\times256%256\rfloor
$$

  • 瓦片(tileX, tileY)的像素坐标(pixelX, pixelY)转经纬度坐标(lng, lat)

$$
lng=\frac{tileX+\frac{pixelX}{256}}{2^{Level}}\times360-180
$$

$$
lat=\arctan({\sinh({\pi-2\times\pi\times\frac{tileY+\frac{pixelY}{256}}{2^{Level}}})})\times\frac{180}{\pi}
$$

百度地图瓦片坐标

坐标系定义

百度地图的瓦片坐标系定义与高德地图并不相同,其墨卡托投影的参数也不同。百度地图瓦片坐标以墨卡托投影地图中赤道与0º经线相交位置为原点,沿着赤道往左方向为X轴,沿着0º经线向上方向为Y轴。
百度瓦片坐标定义了另一种二维坐标系,称为百度平面坐标系。百度平面坐标系的坐标原点与百度瓦片坐标原点相同,以瓦片等级18级为基准,规定18级时百度平面坐标的一个单位等于屏幕上的一个像素。平面坐标与地图所展示的级别没有关系,也就是说在1级和18级下,同一个经纬度坐标的百度平面坐标都是一致的。

此时X方向和Y方向各有4个瓦片编号,但是外围的某些瓦片只有部分区域有地图或完全没有地图。没有地图的区域也可以认为其瓦片是无效的,即百度地图中X方向或Y方向的有效瓦片不一定达到$2^{Level}$个。
中国大概位于百度瓦片坐标的 $(0,0)$ 中。

坐标转换图解

从百度地图坐标转换图解中可以看出,百度地图的坐标转换具有以下特点:

  • 百度经纬度坐标与百度平面坐标可以直接相互转换,并且与瓦片地图等级无关。
  • 经纬度坐标需要先转换为平面坐标,然后才能在某一瓦片等级下转换为瓦片坐标和瓦片像素坐标。
  • 瓦片像素坐标需要结合其瓦片坐标才能得到该像素坐标的平面坐标,然后再转换为经纬度坐标。

坐标转换公式

方法参考:百度地图API详解之地图坐标系统

  • 平面坐标(pointX, pointY)转瓦片坐标(tileX, tileY):

$$
tileX=\lfloor\frac{pointX\times2^{Level-18}}{256}\rfloor
$$

$$
tileY=\lfloor\frac{pointY\times2^{Level-18}}{256}\rfloor
$$

  • 平面坐标(pointX, pointY)转像素坐标(pixelX, pixelY):

$$
pixelX=\lfloor{pointX\times2{Level-18}-\lfloor\frac{pointX\times2{Level-18}}{256}\rfloor\times256}\rfloor
$$

$$
pixelY=\lfloor{pointY\times2{Level-18}-{\lfloor\frac{pointY\times2{Level-18}}{256}\rfloor\times256}}\rfloor
$$

  • 瓦片(tileX, tileY)的像素坐标(pixelX, pixelY)转平面坐标(pointX, pointY):

$$
pointX=\frac{tileX\times256+pixelX}{2^{Level-18}}
$$

$$
pointY=\frac{tileY\times256+pixelY}{2^{Level-18}}
$$

经纬度坐标与瓦片坐标、像素坐标的相互转换,以平面坐标为中间量进行转换。

Web Map 坐标系

对于 Web Map 开发人员来说,最熟悉的应该是EPSG:4326 (WGS84) and EPSG:3857(Pseudo-Mercator)。

EPSG:4326 (WGS84)

前面说了 WGS84 是目前最流行的地理坐标系统。在国际上,每个坐标系统都会被分配一个 EPSG 代码,EPSG:4326 就是 WGS84 的代码。GPS是基于WGS84的,所以通常我们得到的坐标数据都是WGS84的。一般我们在存储数据时,仍然按WGS84存储。

EPSG:3857 (Pseudo-Mercator)

伪墨卡托投影,也被称为球体墨卡托,Web Mercator。它是基于墨卡托投影的,把 WGS84坐标系投影到正方形。我们前面已经知道 WGS84 是基于椭球体的,但是伪墨卡托投影把坐标投影到球体上,这导致两极的失真变大,但是却更容易计算。这也许是为什么被称为”伪“墨卡托吧。另外,伪墨卡托投影还切掉了南北85.051129°纬度以上的地区,以保证整个投影是正方形的。因为墨卡托投影等正形性的特点,在不同层级的图层上物体的形状保持不变,一个正方形可以不断被划分为更多更小的正方形以显示更清晰的细节。很明显,伪墨卡托坐标系是非常显示数据,但是不适合存储数据的,通常我们使用WGS84 存储数据,使用伪墨卡托显示数据。

Web Mercator 最早是由 Google 提出的,当前已经成为 Web Map 的事实标准。但是也许是由于上面”伪“的原因,最初 Web Mercator 被拒绝分配EPSG 代码。于是大家普遍使用 EPSG:900913(Google的数字变形) 的非官方代码来代表它。直到2008年,才被分配了EPSG:3785的代码,但在同一年没多久,又被弃用,重新分配了 EPSG:3857 的正式代码,使用至今。

参考资料

文章链接:
https://www.zywvvd.com/notes/study/gis/gis-map-org/gis-map-org/