很久之前我就计划、开始学三维可视化,初步目标是建一个科学又好看的三维地球模型。为什么“计划”和“开始”之间是顿号呢?这个原因可就复杂了,但简而言之就是技术选型很纠结,于是每个都想尝试(最终现阶段决定pyvista+Blender,将来UE、Babylon.js)。那你又要问了,这和你的标题有关系吗?

一个技术选型就纠结这么久的人,难道数据选择就不会纠结吗?我搜罗各种全球dem数据(甚至有月球的dem)就花了很久,到今天还有很多细节没搞明白,但勉强搞出了带DEM的三维地球模型。接下来就是上色了,最简单的应该就是用地表类型数据上色了,于是开始搜罗land cover/land use数据。最终决定用我国的2020globeland30数据,够可信且文档还比较清楚,虽然申请起来怪费劲的,但谁让我这么能纠结呢。

没想到吧,正文这会儿才开始。

2020globeland30

产品介绍详见http://www.globallandcover.com/Page/sysFrame/dataIntroduce.html?columnID=81&head=product&para=product&type=data

总的来说,主要数据是含有投影的GeoTIFF格式,一共966个,每个tif连同对应的坐标信息文件、分类影像接图表文件、元数据文件压缩成一个zip,然后所有zip再压缩成一个zip。整个压缩包有7.18G大。

目的

将966个tif拼接成全球经纬度数据。

过程

计划用gdal读取tif然后xarray拼接,如果gdal能直接读取压缩包里指定数据当然是最好,可惜不能。那么就只把tif解压出来,“没用的”其他文件就不必浪费心情解压出来了。

解压

import zipfile
from os.path import exists, basename
from os import makedirsglobeland30_zippath = 'G:/GEO_DATA/landcover/globeland30/2020LC030.zip'
globeland30_tifdir = 'G:/GEO_DATA/landcover/globeland30/tif'
if not exists(globeland30_tifdir):makedirs(globeland30_tifdir)
globeland30_zipfile = zipfile.ZipFile(globeland30_zippath)
for zipinfo in globeland30_zipfile.filelist:a_zipfile = zipfile.ZipFile(globeland30_zipfile.open(zipinfo))for zipinfo in a_zipfile.filelist:if zipinfo.filename.endswith('.tif'):# 去掉中间多余的文件夹zipinfo.filename = basename(zipinfo.filename)a_zipfile.extract(zipinfo, path=globeland30_tifdir)print(zipinfo.filename)

解压完得到一个满是tif的文件夹

对应经纬度网格

根据数据的产品介绍,从tif文件名中可以获得该tif的纬度范围和经度范围,那么就可以在读取tif文件时把对应的目标经纬度网格准备好。只不过不同纬度文件的经度范围不同,加判断呗。

import numpy as npres = 0.25def get_lonlat(tif_path):tif_name = basename(tif_path)ns = tif_name[0]slice_id = int(tif_name[1 : 3])lat_start = int(tif_name[4 : 6])lat = np.arange(5 / res + 1) * res + lat_startif ns == 'n':lat = lat[::-1]else:lat *= -1if lat_start < 60:lon = np.arange(6 / res + 1) * res + (slice_id - 1) * 6 - 180elif lat_start < 85:lon = np.arange(12 / res + 1) * res + (slice_id - 1) * 6 - 180else:lon = np.arange(360 / res + 1) * res - 180return lon, lat

我设置了0.25度的分辨率

读取、投影转换、插值

接下来就是遍历读取所有tif,获得对应的经纬度网格,将经纬度网格转到这个tiff的投影坐标上,再最邻近插值插值出来。

读tif用gdal,虽然xarray也可以读tif,但目前这个功能仍然是实验性质的且要装其他依赖包。

投影转换用pyproj,如果你看过我之前的分享,你会发现我一开始投影转换是用的gdal,后来用cartopy,这也是技术选型的纠结。一开始用gdal是因为它既能读写常用的数据格式,又能投影,就觉得不必引进其他第三方包,后来用cartopy是考虑到方便画图,现在用pyproj是因为always_xy。技术选型真的很重要,尤其对不熟悉的技术

插值用xarray,这个包真的是太好用了

from glob import glob
from os.path import exists, basenamefrom osgeo import gdal
import xarray as xr
from pyproj import CRS, Transformerglobeland30_tifpaths = glob('G:/GEO_DATA/landcover/globeland30/tif/*.tif')
das = []
nn = len(globeland30_tifpaths)
for n, tif_path in enumerate(globeland30_tifpaths):tif_file = gdal.Open(tif_path)data = tif_file.ReadAsArray()upper_left_x, pixel_width, _, upper_left_y, _, pixel_height = tif_file.GetGeoTransform()x = np.arange(tif_file.RasterXSize) * pixel_width + upper_left_xy = np.arange(tif_file.RasterYSize) * pixel_height + upper_left_yif tif_file.GetMetadataItem('AREA_OR_POINT').upper() == 'POINT':x += pixel_width / 2y += pixel_height / 2prj = CRS.from_wkt(tif_file.GetProjection())del tif_filedata = xr.DataArray(data, coords=(('y', y), ('x', x)), name='GlobeLand30_V2020')lon, lat = get_lonlat(tif_path)lon_mesh, lat_mesh = np.meshgrid(lon, lat)lonlat2prj = Transformer.from_crs('WGS84', prj, always_xy=True)x, y = lonlat2prj.transform(lon_mesh, lat_mesh)x = xr.DataArray(x, coords=(('lat', lat), ('lon', lon)))y = xr.DataArray(y, coords=(('lat', lat), ('lon', lon)))das.append(data.interp(y=y, x=x, method='nearest').astype(np.uint8).drop_vars(['x', 'y']))print(f'{n}/{nn}')

拼接

拼接完先保存为nc格式快速用panoply看一眼

ds = xr.merge(das)
ds.to_netcdf('GlobeLand30_V2020.nc')

panoply打开是这样:

保存为tif

可以看到,xarray自动拼接后缺失部分(海洋)自动用nan补齐了,而海洋看样子应该是用255填充的。另外由于只保留了数值,并没有颜色信息,用panoply默认色标比较阴间。还有个小问题,新西兰东南海上有一段诡异的0值,顺便也用255填上吧

另存一份tif文件,把原始tif文件的ColorTable也“偷”过来

from osgeo import osr# 读取ColorTable
tif_path = globeland30_tifpaths[0]
tif_file = gdal.Open(tif_path)
rb = tif_file.GetRasterBand(1)
ct = rb.GetColorTable()data = ds['GlobeLand30_V2020'].fillna(255).astype(np.uint8).values
data[data==0] = 255
rows, columns = data.shape
driver = gdal.GetDriverByName('GTiff')
dataset = driver.Create('GlobeLand30_V2020.tif', columns, rows, 1, gdal.GDT_Byte)  # 创建文件
dataset.SetGeoTransform([-180.125, 0.25, 0,-90.125, 0, 0.25])
dataset.SetMetadataItem('AREA_OR_POINT', 'Point')
rb = dataset.GetRasterBand(1)
rb.WriteArray(data)
rb.SetColorTable(ct)  # 写入ColorTable
sr = osr.SpatialReference()
sr.SetWellKnownGeogCS('WGS84')
dataset.SetProjection(sr.ExportToWkt())  # 写入WGS84
dataset.FlushCache()
dataset = None

现在可以直接双击打开

纬度是升序的,导致作为图片南北颠倒了,不碍事,用QGIS打开就是这样的了:

搞定

blahblah

本文是将多幅投影影像拼接成一幅“没有投影”的影像,其实也可以拼接成任意投影的影像,只不过投影转换和插值方式要琢磨一下,拼接估计也不能用xarray这么方便的merge了。

在科学可视化(scientific visualization)方面渴望交流学习的同好请联系我,尤其是地球科学领域、技术栈为Python(pyvista、Blender)、UE(虚幻)、Babylon.js(WebGL、WebGPU)的,我瞎学瞎搞虽然还挺好玩儿,但总是效率很低。

Python3.拼接2020globeland30相关推荐

  1. python3 拼接字符串的7种方法

    1. 直接通过(+)操作符拼接 >>> 'Hello' + ' ' + 'World' + '!' 'Hello World!' 使用这种方式进行字符串连接的操作效率低下,因为pyt ...

  2. Python3 拼接符+和join效率对比测试

  3. python3 bytes拼接

    在python3中,bytes和str是不相同的两种类型 bytes bytes与str bytes与str bytes拼接 In [16]: b1 = bytes("hello" ...

  4. Python3.7总结字符串的print和拼接

    这里写目录标题 1.print()打印 2.使用加号(+)拼接字符串 3. 通过占位符进行字符串拼接 3.1 通用占位符 %s 3.2 小数占位符 %f 3.3 %d 整数占位符 4. 格式化字符串f ...

  5. Python3字符串拼接

  6. Python3 字符串拼接

  7. python3字符串拼接_Python3基础 str + 字符串变量拼接

    ? ????   Python : 3.7.0 ??????   OS : Ubuntu 18.04.1 LTS ??????  IDE : PyCharm 2018.2.4 ????? Conda ...

  8. Python3操作EXCEL,取汉字首字母,拼接全拼

    开发需求: 将EXCEL中某列特殊字符之前的汉字取首字母,特殊字符之后的汉字取全拼,然后用下划线"_"相连,写入下一列 把*******.xls中的汉字人名转成用户名,写到后面的单 ...

  9. python3版本代码大全_python3中的

    出品 | FlyAI 编译 | 林椿眄 编辑 | Donna Python 已经成为机器学习及其他科学领域中的主流语言.它不但与多种深度学习框架兼容,而且还包含优秀的工具包和依赖库,方便我们对数据进行 ...

最新文章

  1. R语言计算每个分组的行数并将结果添加到dataframe中实战
  2. QT QSqlTabModel 学习,用于从数据库中存取修改等操作。
  3. 产品网络推广方案浅谈网站的相关性对优化的影响!
  4. Android 架构 -- Room
  5. 关于用 ABAP 代码手动触发 SAP CRM organization Model 自动决定的研究
  6. hash table(全域散列法实现的哈希表)
  7. 状压动规_(POJ2817)
  8. Oracle 日志解析ogg,对一段OracleGoldenGate(OGG)传输进程日志(.rpt文件)的解
  9. php excel 保护工作表,PHPExcel 指定列表锁定受保护加密不可更改方法
  10. SHON WEBB:搞好人际关系的5点小技巧
  11. 天蝎项目整机柜服务器技术规范v1.01,第九章 天蝎项目整机柜服务器技术规范v1.01.pdf...
  12. 亲测,2023年私藏的免费好用的磁力网盘资源搜索网站,找资源不用愁
  13. Excel中提取单元格中的部分内容或单元格中的数字公式大全(提取数字,提取前几位,提取指定文字之间的内容等等)
  14. Nessus之——Nessus的整理
  15. STM32HAL库RTC闹钟事件
  16. 在国企的日子(第三章中部 出差)
  17. win7计算机窗口无法最小化,win7系统任务栏无法显示网页最小化窗口的解决方法...
  18. 程序的Squeeze函数的功能是删除字符串s中所出现的与变量c相同的字符
  19. sqlserver存储过程报错:当前事务无法提交,而且无法支持写入日志文件的操作。请回滚该事务
  20. ubuntu16.04安装IDEA

热门文章

  1. php设置图标,如何做一个设置图标
  2. 智能驾驶——传感器布置
  3. 用javascript 动态改变iframe 的src 属性
  4. Relation Networks for Object Detection算法笔记
  5. 中望CAD二次开发环境配置及使用
  6. python的艰难学习之路-打印一个菱形
  7. Greenplum数据库分享
  8. 大厂历年的网络安全面试真题总结(附答案)
  9. AVTECH摄像监控存漏洞 可被控组建僵尸网络发起DDoS攻击
  10. 生成过程中EVT, DVT, PVT分别是什么意思