cesium添加极地影像(三维渲染)

起因是我的vue项目中需要增加一个cesium三维渲染功能,将遥感影像数据添加到地球上,作为新手小白,一路上踩了不少坑。

目录

一、cesium中添加tif影像的一般流程

1.1 将tif格式转为png格式加载

1.2 具体加载流程

①切片处理加载

②单瓦片加载

二、cesium中添加极地影像

2.1 切片过程中碰到的问题

①未修改坐标系时

②修改了坐标系后

2.2 极地影像的特殊性

2.3 重要的坐标转换

2.4 tif 转 png 可能遇到的坑

三、总结


一、cesium中添加tif影像的一般流程

1.1 将tif格式转为png格式加载

通过查阅相关博文,发现cesium一般不支持直接加载本地geotiff格式的数据,除非是通过在线服务器端进行加载。故要加载tif格式的数据,常规的做法是将之转换为png格式进行加载。

1.2 具体加载流程

①切片处理加载

对于处理大范围、精细化的影像,一般采用此种方法,将一整张影像切割成一块一块小瓦片,再行加载。

具体来说,遥感影像的切片操作可以通过cesiumlab进行(西部世界官网),操作流程比较easy,可参考:【cesium知识梳理】2.cesium加载各类数据 - 掘金 (juejin.cn)

cesium发布切片数据的代码如下:

    // 添加影像数据
    const localImage = viewer.scene.imageryLayers.addImageryProvider(
        new Cesium.UrlTemplateImageryProvider({
            url: 'yourImagePath/{z}/{x}/{y}.png',
            fileExtension: 'png',
        })
    );
    // 设置图层透明度
    localImage.alpha = 0.8;

更为详细的代码可参照:Cesium数据加载_cesium加载csv数据-CSDN博客

②单瓦片加载

如果不想进行切片处理的话,可以直接采用单瓦片发布的方法,代码如下:

    // 添加影像数据
    const rectangle = Cesium.Rectangle.fromDegrees(west, south, east, north);
    const imageryProvider = new Cesium.SingleTileImageryProvider({
        url: 'yourPath/imageName.png',
        rectangle: rectangle,
    });
    const imageryLayer = viewer.imageryLayers.addImageryProvider(imageryProvider, 1);
    // 设置图层透明度
    imageryLayer.alpha = 0.7;

相关方法见cesium官网(SingleTileImageryProvider - Cesium Documentation

west、south、east、north表示所影像覆盖的经纬度范围,如果不确定,可通过ArcGIS的图层属性获取相关信息。

二、cesium中添加极地影像

2.1 切片过程中碰到的问题

使用工具进行切片的过程是相当顺利的,但是将之加载到cesium上时,出现了显示问题,具体来说可以分为以下两种情形:

①未修改坐标系时

不对影像的坐标系做任何处理:

   

②修改了坐标系后

将影像的投影坐标系改为了WGS-1984地理坐标系,再进行切片处理:

可以看到,在修改了坐标系以后,情形有所改善,这就说明,在cesium中加载影像时更改坐标系这一步是必要的。但是另一方面,cesium自始至终都没能加载出影像信息,也许是切片过程存在问题,然而小白的能力实在有限,这就宣告了使用切片处理加载影像的方法行不通,于是后续我们探索使用单瓦片加载影像的方法。

2.2 极地影像的特殊性

对于将tif格式的影像转换为png格式,一开始的想法是用ArcGIS的数据导出为png格式,出现了如下报错:

于是后来改成了直接在ArcGIS上进行地图导出的方法(问就是gpt出的馊主意),这一操作为后续的跌坑埋下了伏笔。

cesium加载得到的结果如下:

当时我一度以为自己已经成功了,仔细一看真是壮士扼腕,不仅图片形变严重,而且北极点的位置都不对呀。此外多提一句,cesium加载png图像有像素限制,最大支持16384 x 16384。

(黄色为理论上的北极点位置,红色为实际上的北极点位置)

出现上述问题是由于极地遥感影像的特殊性导致的,这一区域涵盖了所有的经度线,横跨了北纬30°~90°的大片区域,因此直接添加png的方式会产生较大的形变。

2.3 重要的坐标转换

被上面这个问题困扰了许久,由于转换png的方式是错误的,致使我认为没有更改坐标系的必要。后来请教了专业人员,得到的回答是尝试更改坐标系以后再进行加载。于是我首先在ArcGIS中将影像的原始的投影坐标系(epsg为3413)改为了地理坐标系WGS-1984(epsg为4326)(这一操作应该可以在cesium中实现),接着换用更科学的方法将tif影像转为png格式,我这里使用的是Python的GDAL和PIL库。

在cesium中加载得到如下结果:

(可以依稀看到有影像信息,但是颜色对比不够明显)

2.4 tif 转 png 可能遇到的坑

为了让结果得到更良好的呈现,我决定在将数据保存为png格式之前多做一步渲染的操作,这里采用的是matplotlib库的colormap功能来实现,对图像进行伪彩色渲染,将单波段图像转化为彩色图像的方式(它通过将图像的灰度值映射到RGB颜色空间来实现),色带选择可参照python官网:Choosing Colormaps in Matplotlib — Matplotlib 3.8.3 documentation

当然在这个地方也是遇到了一个坑,后来挣扎许久发现是因为没有对影像数据进行预处理。下面直接给出预处理操作前后的加载结果对比:

   

我这里的特殊值处理是去掉NaN值,并将负值替换为0,下附一段简单的tif转png的python代码:

from osgeo import gdal
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm


def convert_tiff_to_png(tiff_filepath, png_filepath):
    # 使用GDAL打开TIFF文件
    dataset = gdal.Open(tiff_filepath)

    # 读取TIFF文件的第一个波段
    band = dataset.GetRasterBand(1)
    arr = band.ReadAsArray()

    # 去除NaN值
    arr = np.nan_to_num(arr)

    # 将小于0的元素值重新赋值为0
    arr[arr < 0] = 0

    # 将数据规范化到0-1的范围(也可以用对数变换或百分值法等)
    arr = (arr - arr.min()) * 1.0 / (arr.max() - arr.min())

    # 使用matplotlib的colormap进行伪彩色渲染
    arr = cm.coolwarm(arr)

    # 将数组转换为PIL图像
    img = Image.fromarray((arr * 255.0).astype(np.uint8))

    # 保存为PNG
    img.save(png_filepath)


convert_tiff_to_png('yourTifPath/tifImageName.tif', 'yourPngPath/PngImageName.png')

三、总结

总的来说,在cesium中加载tif格式的极地遥感影像的一般步骤是:

①将极地影像的投影转换为地理坐标系WGS-1984;

②将极地影像数据格式由tif转换为png;

③在cesium中使用单瓦片加载的方式(SingleTileImageryProvider)加载png。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值