云优化cog提出的背景是未来解决遥感影像上云面临的问题。
遥感影像的特点,主要是大。一般一张图片在5~10GB,单卫星每天增加TB级,全球每天增加PB级。随着卫星传感器精度增加,单个影像文件越来越大。
大,带来的问题就是不容易保存,本地数据中心存不下,就得上云。但是大量的遥感数据上云后,面临不少挑战:
大量的既有软件,无法远程读取云上的(特别是对象存储,如S3)影像文件。必须先Download到本地,然后才能打开分析。
即使为软件增加S3驱动。远程分析一个文件,也不得不全量读取文件内容(因为它是链表式的文件)。注意这个是通过网络进行的,所以很影响效率。
单独取影像文件中的部分区域(瓦片,或者缩略图),也不得不全量下载or访问整个文件。即使瓦片仅占全影像的1/N。
所以,能不能在访问云上的遥感影像数据的时候,只访问部分(尽可能小的)内容呢?
这里分享一下 TIFF文件的格式:
TIFF是一个灵活适应性强的文件格式,能够在一个文件中保存多幅图像。然后每幅影像带一个标签目录(多个标签),记录它的像素深度、每像素波段信息,RGB编码等详细信息。
注意:上图属性之间没有顺序要求,都通过offset查找。实际上是链表的形式:
因此,TIFF文件内部各Block块之间的顺序可以很灵活自由。
要达成这个目的,需要有以下能力:
云存储协议上支持以 Range方式读取云上的文件。
GeoTIFF影像文件,支持先读取“所有标签数据”,然后以Offset偏移读取目标数据。
这2个条件里面的第1个,目前各大云厂商的对象存储(如S3)都已经支持。
关键是第2个条件。首先,能不能把GeoTIFF的“元数据”,全部放到文件头部,把实际Data数据放到文件尾部。
这样的话,访问一个超大的GeoTIFF遥感影像,只需先发送HTTP GET获取文件头部16K字节,然后文件中剩余内容位置就都知道了。接下来想要访问什么,再根据偏移,发送HTTP GET访问目标XX字节的影像数据,就够了。
然后,将图像切成小片,可以根据“瓦片”的方式访问目标区域。因为已经有了头部的标签信息,所以再访问具体区域,只需要根据Offset,直接读取云上文件的指定偏移就行。
在这种模式下,该遥感影像文件,还是一个标准的GeoTIFF格式,只是它更适应云化访问。也就是cog格式的tiff文件
为了让云优化的GeoTIFF格式更加的普及,专门成立了COG(Cloud optimized GeoTIFF)标准。
规范可以参考:https://www.cogeo.org/
介绍文章可以参考:https://medium.com/planet-stories/cloud-native-geospatial-part-2-the-cloud-optimized-geotiff-6b3f15c696ed
COG使用的两种主要的数据组织技术是瓦片和概览图,数据的压缩也使得数据在线传输变得更高效。
瓦片切片在影像中创建了内置了切片,当切片可以被在指定区域快速被获取到成为可能之后,只需要访问数据的特定部分就可以了。
概览图创建了同个影像的向下采样的多个版本。向下采样的意思是当从一个原始影像'缩小'时,有很多细节消失掉了(当前的1个像素在原始影像中可能存在100个甚至1000个像素),同时它的数据量也更小。通常一个GeoTIFF会有多个概览图来匹配不同缩放等级。这使得服务端的响应变得更快,因为渲染时只需要返回这个特定的像素值即可,无需再来找出用哪个像素值来表示这1000个像素,但是这也会使得整个文件的体积变大。
COG所需的GeoTIFF,主要技术是在文件内部构建瓦片和概览,辅以图像压缩。就是将完整的影像像拼图一样按照横竖的格网拆分成瓦片,只加载需要范围内的一个个瓦片而不是完整的巨大TIFF。
全分辨率的tiff文件格式见链接BigTIFF, TIFF breaking the 4 gigabyte boundary
GeoTIFF将瓦片和概览按规则进行组织,存放放在云端(比如用Nginx),以便HTTP范围请求可以只请求相关的文件部分。
当客户端想要渲染整个文件的概览图像时,它不必下载每个像素,它可以只请求更小的、已经创建的概览。HTTP范围请求支持服务器上的 GeoTIFF 文件的结构使客户端能够轻松找到所需的整个文件的一部分。
当整个文件的一小部分需要处理或可视化时,瓦片就会发挥作用。这可能是概览的一部分,也可能是全分辨率。但是瓦片将一个区域的所有相关字节组织在文件的同一部分,因此范围请求可以获取它需要的内容。
如果 GeoTIFF 没有通过概览和瓦片进行“云优化”,那么对数据进行远程操作仍然有效。只是当实际只需要很小一部分数据时,他们可能会下载整个文件或大部分文件。
假如在http响应头中存在 Accept-Ranges 为bytes ,那么表示该服务器支持范围请求。 Content-Length 提供了要检索的图片的完整大小。
假如服务器支持范围请求的话,你可以使用 Range 头来生成该类请求,下图示例的就是请求的该TIFF的0-65536字节。
可以使用GDAL生成COG。这里简单介绍下GDAL,它是一个基于C++的空间数据功能库,我这里有基于JAVA和Python的安装介绍,见Java安装GDAL依赖,python安装GDAL。
基于Java或Python开发可以将COG生成的功能比较方便地集成到现有工程里,除此之外也可以使用GDAL现成的脚本,这些脚本可以先按照Java安装GDAL依赖里下载的压缩包,解压后在release-1928-x64-dev
elease-1928-x64bingdalapps下找到。
使用脚本将普通tif转成COG可以这样操作:
CD到脚本目录
执行以下脚本,生成概览
执行以下脚本,生成COG
主要参数的含义:
TILED=YES 生成瓦片
COMPRESS=DEFLATE 使用DEFLATE方法压缩
COPY_SRC_OVERVIEWS=YES 从原数据中拷贝概览
6.2使用Python程序生成的代码
生成的COG有多种方法检验和查看,比如使用validate_cloud_optimized_geotiff.py检验
qgis查看
右键图层窗口里的图层对象,查看Properties,可以查看该COG的属性信息,如范围,波段信息,空间参考等
Openlayers更新了WebGLTile图层和GeoTIFFSource数据源,用geotiffjs解析tif源数据,再用WebGL渲染,实现了前端渲染GeoTIFF图像并进行波段组合,拉伸等功能。
下面是用到的组件
获取元信息
COG文件里存储的波段信息和nodata值可以通过geotiffjs获取。
注意,这里获取是为了演示功能,如果仅为了显示不需要提前获取并使用自己指定的像素真实值范围,OL的GeoTIFFSource默认开启了normalize属性,将波段像素范围自动标准化为0-1之间的比例。
结果如下:
编写渲染表达式
OL的WebGL图层使用表达式配置图层的渲染样式,具体的语法详见ExpressionValue
加载图层
显示效果