COG云原生优化遥感影像,瓦片切分的最佳实践


摘要:云上遥感影像文件Cloud optimized GeoTIFF(COG)格式的详细介绍,大量数据上云面临的挑战,并分享了获得云原生影像最佳性能的实践经验。

本文分享自华为云社区《COG云原生优化遥感影像,瓦片切分的最佳实践》,作者: tsjsdbd 。

1 遥感影像文件格式

遥感影像就是地球自拍照,一般文件很大,一张文件5GB左右。

这些影像文件大多数都保存为 TIFF 格式(而不是JPEG),因为TIFF格式记录的内容是比较原始的多个波段的信息,也不会因为压缩丢失信息。

1.1 TIFF格式

这里分享一下 TIFF文件的格式:

TIFF是一个灵活适应性强的文件格式,能够在一个文件中保存多幅图像。然后每幅影像带一个标签目录(多个标签),记录它的像素深度、每像素波段信息,RGB编码等详细信息。

注意:上图属性之间没有顺序要求,都通过offset查找。实际上是链表的形式:

因此,TIFF文件内部各Block块之间的顺序可以很灵活自由。

1.2 TIFF标签目录格式

每幅影像,带有一组标签目录,记录该图形的各种属性。

标签目录的格式如下:

每个标签(属性),由于信息内容不一样,其值大小有区别。有些信息小,它的标签值(Value)直接在标签里面。有些信息量比较大的,它的标签值(Value),在标签里放不下,需要记录在文件的其他位置上,通过offset便宜对应。

1.3 TIFF单标签格式

1个标签,就是记录图片的一个属性。主要是:属性名+属性值。

具体格式如下:

一般一幅图片,大概10几个属性。

可以看到,整个TIFF文件,是分块分散的记录图像数据的。所有信息之间都是通过offset偏移量关联。

ps:这里我先给“分块分散”标个粗。 这是它灵活性的优势,也是后续主题要讨论的。

关于TIFF详细格式,可参考:

1.4 GeoTIFF格式

正是因为TIFF这种标签化的格式,非常的好扩展,为图片添加地理信息也很方便。 所以GeoTIFF就在TIFF的标签规范里面,增加一系列(地理信息相关的)扩展标签,用来记录一幅影像的地理坐标信息。

可以看到,一个GeoTIFF,也是正常的TIFF文件。所以它的内容,也是分散分块在文件内保存的。只是多了一系列的地理信息标签。

所有标签解释,见:

1.5 TIFF格式灵活

由于TIFF文件内部都是链表的形式,所以文件标准中并没有要求各Block块之间彼此的顺序。

有时候它是这样的:

更常见的则是这样的:

少数还有可能是这样的:

无论哪种组织形式,都是符合标准的TIFF文件。

1.6 TIFF文件调试

由于我个人的编程语言是GO语言,所以这里我选用了

这个包(谷歌开源的TIFF文件解析包),函数调用使用 tiff.Parse() 就行。

解析完打个断点,就可以看到TIFF文件的各种属性啦:

上图可以看到,当前分析的这个TIFF文件里面,有5幅图片。

如上图,第一幅图片,有21个属性。这是原始图片,带有地理信息属性(标签ID值大于3000),各属性如下:

其余的4幅,都只有15个属性。是 overview,没有地理信息,单纯的图片(不带Geo地理属性,标签ID都是 2xx~3xx的),如下:

我们打开其中一个标签,看它的值:

这里看到这个属性ID是256,查询规范:

得知这个表示图片的宽度,然后大小端属性,我们算出:第2个字节是28,第1个字节是174,实际值等于:28 * 256 + 174 = 7342 像素的宽度。

可以查看实际图片的像素,就是 7342。

其余属性,都可以按照这个方式一一查看。

2 遥感影像上云面临的问题

遥感影像的特点,主要是大。一般一张图片在5~10GB,单卫星每天增加TB级,全球每天增加PB级。随着卫星传感器精度增加,单个影像文件越来越大。

大,带来的问题就是不容易保存,本地数据中心存不下,就得上云。但是大量的遥感数据上云后,面临不少挑战:

  1. 大量的既有软件,无法远程读取云上的(特别是对象存储,如S3)影像文件。必须先Download到本地,然后才能打开分析。
  2. 即使为软件增加S3驱动。远程分析一个文件,也不得不全量读取文件内容(因为它是链表式的文件)。注意这个是通过网络进行的,所以很影响效率。
  3. 单独取影像文件中的部分区域(瓦片,或者缩略图),也不得不全量下载or访问整个文件。即使瓦片仅占全影像的1/N。

所以,能不能在访问云上的遥感影像数据的时候,只访问部分(尽可能小的)内容呢?

2.1 GeoTIFF适合云的优化

要达成这个目的,需要有以下能力:

  1. 云存储协议上支持以 Range方式读取云上的文件。
  2. GeoTIFF影像文件,支持先读取“所有标签数据”,然后以Offset偏移读取目标数据。

这2个条件里面的第1个,目前各大云厂商的对象存储(如S3)都已经支持。

关键是第2个条件。首先,能不能把GeoTIFF的“元数据”,全部放到文件头部,把实际Data数据放到文件尾部。

即:

这样的话,访问一个超大的GeoTIFF遥感影像,只需先发送HTTP GET获取文件头部16K字节,然后文件中剩余内容位置就都知道了。接下来想要访问什么,再根据偏移,发送HTTP GET访问目标XX字节的影像数据,就够了。

然后,将图像切成小片,可以根据“瓦片”的方式访问目标区域。因为已经有了头部的标签信息,所以再访问具体区域,只需要根据Offset,直接读取云上文件的指定偏移就行。

即:

在这种模式下,该遥感影像文件,还是一个标准的GeoTIFF格式,只是它更适应云化访问。

2.2 COG格式(Cloud optimized GeoTIFF)

为了让云优化的GeoTIFF格式更加的普及,专门成立了COG(Cloud optimized GeoTIFF)标准。规范可以参考:

介绍文章可以参考:

目前该标准得到了业界很多公司的认可:

重要的是,一个COG影像文件,也是一个标准的 GeoTIFF文件,可以兼容已有的各种软件生态。

TIFF 和 GeoTIFF和COG 这三种文件格式之间的关系。

3 COG文件最佳实践

有了COG文件格式的背景介绍,接下里我们详细分析一下一个COG文件,怎么样才能做到云化性能最优?

3.1 取文件头字节数

一幅影像文件,目前远程读取的最常用的底层库就是 gdal了。它在第一次访问文件的时候,默认是先取 16KB的内容。大多数的GeoTIFF文件头,取16KB肯定是够了的,如下(取1次头就可以Open):

但是也有些GeoTIFF文件信息太多,使得文件头很大。gdal就会不得不再次取一次文件头,如下图(取了2次头才能Open):

2次HTTP请求,才能获得完整的TIFF文件头,显然访问效率大打折扣。

这个时候,就得通过底层 gdal库的配置,来控制首次获取文件头的字节数了。

环境变量:GDAL_INGESTED_BYTES_AT_OPEN=2000

可以使得首次请求的时候,获取更大的文件头,如下图:

但是如果影像文件的实际头都很小,你首次取太大肯定也浪费。

所以请根据自己的影像规格,以及影像的属性,恰当的选择首次取文件头的字节数。避免每次都额外发送一次HTTP请求,浪费效率。

3.2 瓦片大小的影响

一图影像,举个例子,原始像素是 512*512的图片。

如果我们按照 256*256的Tile(瓦片)进行保存,那么就会有4个瓦片。

如果按照 512*512的Tile(瓦片)保存,那么只有1个瓦片。

这2种保存方式,会导致文件头需要记录的“信息量”不一样。4个瓦片,就得记录4个偏移量。1个瓦片则只需要记1个偏移量。

这里以一个5GB左右大小的GeoTIFF文件举例,按照128*128像素进行瓦片,那么所有的瓦片偏移值如下:

(标签ID=324,代表TileOffsets,值为8字节的整型。)

所以为了记录所有瓦片信息:65905(瓦片数) * 8(字节) = 527240,就要520KB。

如果按照256*256的瓦片保存,则可以直接减少到1/4,记录所有瓦片的偏移信息只需要520KB / 4 = 130KB。可见适当加大瓦片面积,可以缩小TIFF文件头大小。

但是瓦片又不能太大,因为这会影响取局部区域的像素效率问题。

如下图举例:

如果目标区域在一个小瓦片范围内,则瓦片大小为256*256的话,取回的文件内容,就很小。 而512*512的话,一次取回就得整个大瓦片。显然网络传输效率会降低很多。

4 瓦片大小性能分析

下面我们详细分析性能vs瓦片大小的影响,分别以:

  • gdal默认tile大小256*256。
  • rio默认tile大小 512*512。见:

gdal命令:

gdal_translate input.tiff output.tiff \
-co TILED=YES -co COPY_SRC_OVERVIEWS=YES -co COMPRESS=LZW

rio命令:

rio cogeo create input.tif output.tif

如果你仅有gdal,也可以通过以下命令:

gdal_translate input.tif output.tif \
-co TILED=YES -co COMPRESS=LZW -co COPY_SRC_OVERVIEWS=YES \
-co BLOCKXSIZE=256 -co BLOCKYSIZE=256 \
--config GDAL_TIFF_OVR_BLOCKSIZE 256

来控制瓦片大小。

gdal命令,可以通过docker直接获得:

docker pull osgeo/gdal

启动gdal容器的时候,只需要使用 -v 将主机目录,挂载到容器内就行。例如我的:

docker run -it -v /home/tsjsdbd/cog/:/tmp/cog/ osgeo/gdal /bin/bash

这样容器里面的/tmp/cog目录下,就可以看到主机/home/tsjsdbd里的tiff文件了。

下面来对2种做对比,详细操作如下:

4.1 取一个像素

512*512瓦片:

第2次通过HTTP响应取回来:105119744-105840639 = 720,895 字节

256*256瓦片:

可以看到,第2次请求的内容,小很多:139476992-139722751 = 245,759 字节

对比发现,256的瓦片,第2次HTTP响应只有1/3,延时也是优势明显。

4.2 取一块区域

512*512瓦片:

第2次通过HTTP响应取回来:32522240-33095679 = 573,439 字节

256*256瓦片:

同样的,第2次取的内容,小很多:41402368-41533439 = 131,071 字节

同样,256的瓦片,第2次HTTP响应大小只有1/3,延时也是优势明显。

4.3 512瓦片性能

官方测试报告里面(见: )

显示 512*512 的瓦片大小,性能更优,是因为,

256*256的小瓦片,导致TIFF文件头太大了。第1次16KB取不完,又取了1次导致的。

Ps:首次取的字节数,是可以通过配置控制的。

所以实际业务场景下,具体以多大的瓦片划分,要根据项目影像图片特征适当的调整。

4.4 性能小结

性能对比看,256*256的小瓦片,在做局部在线Web预览加载时,性能更优异。

但是 256*256 的瓦片,意味着瓦片数量更多,TIFF文件头更大,因此需要适当控制“首次取文件头字节”配置。

上述GDAL操作步骤可以参考:

其他GADL配置调优可参考:

5 COG的未来

分享了GeoTIFF影像文件上云后的一系列最佳实践后,我们探讨一下,未来在COG性能方面,有没有云厂商提供更加深度优化方式呢?

可以想到的有:快速的获得COG文件头大小,使得首次HTTP请求,精确取想要的数据,不浪费额外的网络报文。不过这种就需要对象存储提供一些定制能力了。

COG已经是业界普遍认可的云原生的遥感影像数据格式,未来一定可以更加的普及,并且发挥更大的价值。其他有好的想法,也欢迎探讨分享。

华为云地理遥感平台GeoGenius,经过多年的技术项目积累,采用了业界最佳的云原生的遥感影像管理实践,并且提供端到端最优的性能体验,欢迎领域同行了解使用。

详见:

 

点击关注,第一时间了解华为云新鲜技术~