当前位置: 首页 > article >正文

【ArcGIS技巧】天地图下载瓦片并合并成图片

下载高等级的卫星影像图在很多方面都需要,高德与百度的影像时效差,而且存在坐标纠偏问题。今天就下载天地图影像并合并下载的图片做期分享。

1、瓦片的原理

1.1 web墨卡托投影

用一张纸卷成圆柱,围住地球仪;然后在地球仪的球心放一个发光的灯泡,地球仪上的地图会在圆柱纸上形成投影;把这张纸平展开,就是我们常见平面世界地图上面所讲的投影法叫墨卡托投影(Mercator Projection)。

1.2 瓦片的定义

瓦片:指将一定范围内的地图按照一定的尺寸和格式,按缩放级别或者比例尺,切成若干行和列的正方形栅格图片,对切片后的正方形栅格图片被形象的称为瓦片(Tile)。

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

经过Web墨卡托投影后,地图就变为平面的一张地图。为此,我们对这张地图进行等级切分。在最高级(zoom=0),需要的信息最少,只需保留最重要的宏观信息,因此用一张256x256像素的图片表示即可;在下一级(zoom=1),信息量变多,用一张512x512像素的图片表示;以此类推,级别越低的像素越高,下一级的像素是当前级的4倍。这样从最高层级往下到最低层级就形成了一个金字塔坐标体系。

1.3 瓦片的层级与像素比例

谷歌XYZ:Z表示缩放层级,Z=zoom;XY的原点在左上角,X从左向右,Y从上向下。

Level of DetailMap Width and Height (pixels)Ground Resolution (meters / pixel)Map Scale(at 96 dpi)
151278271.5171 : 295,829,355.45
2102439135.75851 : 147,914,677.73
3204819567.87921 : 73,957,338.86
440969783.93961 : 36,978,669.43
581924891.96981 : 18,489,334.72
6163842445.98491 : 9,244,667.36
7327681222.99251 : 4,622,333.68
865536611.49621 : 2,311,166.84
9131072305.74811 : 1,155,583.42
10262144152.87411 : 577,791.71
1152428876.4371 : 288,895.85
12104857638.21851 : 144,447.93
13209715219.10931 : 72,223.96
1441943049.55461 : 36,111.98
1583886084.77731 : 18,055.99
16167772162.38871 : 9,028.00
17335544321.19431 : 4,514.00
18671088640.59721 : 2,257.00
191342177280.29861 : 1,128.50
202684354560.14931 : 564.25
215368709120.07461 : 282.12
2210737418240.03731 : 141.06
2321474836480.01871 : 70.53

2、天地图申请key

2.1 注册账号

网址:https://www.tianditu.gov.cn/。

2.2 申请key

找到控制台——创建新任务——选择浏览器端,这样就申请了一个key.

2.3 在线影像网址解析

打开天地图的在线地图——打开浏览器的开发者工具——选择network,这样能清楚的看到地图是通过加载瓦片显示在前端.

复制瓦片的地址,url的地址有4个重要参数,列号(tilecol),行号(tilerow),层级(tilematrix),密钥(tk)。

天地图地图api里也提供了瓦片获取的请求示例。

3、瓦片下载

3.1 经纬度反算瓦片的行列号

可以通过网址:https://map.jiqrxx.com/jingweidu/,去获取瓦片左上与右下角的经纬度号。

计算左上与右下角的瓦片行列号后,我们可通过行列号相减,再通过行乘列获得总共有多少瓦片。

3.2 下载瓦片

第二节讲的4个参数通过计算全部获取,请求的url对应相应的瓦片,直接下载图片。

3.3 具体代码

from urllib import request
import urllib.request
import os, sys
import math
import urllib.request
import urllib
import random

agents = [
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
    "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
    "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
    "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
    "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",
]


# 经纬度反算切片行列号 3857坐标系
def deg2num(lat_deg, lon_deg, zoom):
    lat_rad = math.radians(lat_deg)
    n = 2.0 ** zoom
    xtile = int((lon_deg + 180.0) / 360.0 * n)
    ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
    return (xtile, ytile)


# 下载图片
def getimg(Tpath, Spath, x, y):
    try:
        f = open(Spath, 'wb')
        req = urllib.request.Request(Tpath)
        req.add_header('User-Agent', random.choice(agents))  # 换用随机的请求头
        pic = urllib.request.urlopen(req, timeout=60)

        f.write(pic.read())
        f.close()
        print(str(x) + '_' + str(y) + '下载成功')
    except Exception:
        print(str(x) + '_' + str(y) + '下载失败,重试')
        getimg(Tpath, Spath, x, y)

path = r"/Users/longwei/PycharmProjects/mapdownload/imagesMerge"
if not os.path.exists(path):
    os.mkdir(path)

zoom = 18  # 下载切片的zoom
lefttop = deg2num(28.00584478191142, 112.94649124145508, zoom)  # 下载切片的左上角角点
rightbottom = deg2num(27.971586828415163, 113.00880432128906, zoom)

print(str(lefttop[0]))
print(str(rightbottom[0]))
print(str(lefttop[1]))
print(str(rightbottom[1]))
print("共" + str(lefttop[0] - rightbottom[0]))
print("共" + str(lefttop[1] - rightbottom[1]))

for x in range(lefttop[0], rightbottom[0]):
    for y in range(lefttop[1], rightbottom[1]):
        tilepath = "http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=18&TILEROW="+ str(y)+"&TILECOL="+str(x)+"&tk=xxxxxx"
        getimg(tilepath, os.path.join(path, str(y) + "_" + str(x) + ".jpg"), x, y)
print('完成')

4、瓦片合并

下载好的瓦片以row_col.jpg命名,根据命名的顺序进行瓦片合并,代码如下:

# -*- coding: utf-8 -*-
#!/usr/bin/env python
'''
下载好的文件按照ROW_COL.jpg格式统一保存在imagesMerge文件夹中,需按照行列号次序将瓦片图片拼接成完整的瓦片图片。基于Python PIL库实现此功能。
'''
import glob, re
from PIL import Image
# 按照x、y顺序对文件名进行排序
files = glob.glob('./imagesMerge/*.jpg')
files.sort(key=lambda x: tuple(int(i) for i in re.findall(r'\d+', x)[:2]))
# 将每一行文件名保存到一个数组中
imagefiles = {}
for item in files:
    match = re.search(r'\d+', item)
    pre = int(match.group())
    if not imagefiles.get(pre):
        imagefiles[pre] = []
    imagefiles[pre].append(item)
# print(list(imagefiles.keys())[-1])
# 键值对转排序后的列表
imagefiles = sorted(zip(imagefiles.keys(), imagefiles.values()))
# print(len(imagefiles[0][1]))
# 预先生成合并后大小的空图片
total_width = len(imagefiles) * 256
total_height = len(imagefiles[0][1]) * 256
new_image = Image.new("RGB", (total_height, total_width))
# 逐行拼接
y_offset = 0
for item in imagefiles:
    x_offset = 0
    images = list(map(Image.open, item[1])) # 映射函数,返回列表
    for subitem in images:
        new_image.paste(subitem, (x_offset, y_offset))
        x_offset += subitem.size[0]
    y_offset += images[0].size[0]
new_image.save('merge.jpg', quality = 100)


http://www.kler.cn/a/441785.html

相关文章:

  • RV1126+FFMPEG推流项目(8)AENC音频编码模块
  • 微服务知识——4大主流微服务架构方案
  • .Net Core微服务入门全纪录(六)——EventBus-事件总线
  • Linux磁盘空间不足,12个详细的排查方法
  • React 中hooks之useDeferredValue用法总结
  • Ubuntu 24.04 LTS 空闲硬盘挂载到 文件管理器的 other locations
  • Hive-4.0.1数据库搭建(可选配置用户名密码远程连接,涵盖切换为tez引擎)
  • FFmpeg 4.3 音视频-多路H265监控录放C++开发二十一.3,RTCP协议, RTCP协议概述,RTCP协议详情
  • 图数据库 | 15、可扩展的图数据库设计(上)
  • C# 读取EXCEL的数据批量插入单个PDF里的多个位置
  • 系统可观测性——Logback日志框架
  • Spring Boot 3.x:自动配置类加载机制的变化
  • 如何在Linux上搭建DHCP服务
  • 解决Docker拉取镜像报错问题的详细步骤
  • win10配置子系统Ubuntu子系统(无需通过Windows应用市场)实际操作记录
  • Python中构建全局字典的详细指南
  • docker快速实现ELK的安装和使用
  • Centos gcc 12.3 安装
  • 使用CNN模型训练图片识别(键盘,椅子,眼镜,水杯,鼠标)
  • docker 拉取镜像 | 创建容器 | 容器运行
  • k8s,理解容器中namespace和cgroups的原理
  • Android Scratch分区
  • 力扣hot100——哈希
  • ESP8266 Ubuntu 安装
  • vue2 项目webpack 4升5
  • docker xxxx is using its referenced image ea06665f255d