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详细格式,可参考:https://www.jianshu.com/p/ff32eb09ed3d
1.4 GeoTIFF格式
正是因为TIFF这种标签化的格式,非常的好扩展,为图片添加地理信息也很方便。 所以GeoTIFF就在TIFF的标签规范里面,增加一系列(地理信息相关的)扩展标签,用来记录一幅影像的地理坐标信息。
可以看到,一个GeoTIFF,也是正常的TIFF文件。所以它的内容,也是分散分块在文件内保存的。只是多了一系列的地理信息标签。
所有标签解释,见:https://www.loc.gov/preservation/digital/formats/content/tiff_tags.shtml
1.5 TIFF格式灵活
由于TIFF文件内部都是链表的形式,所以文件标准中并没有要求各Block块之间彼此的顺序。
有时候它是这样的:
更常见的则是这样的:
少数还有可能是这样的:
无论哪种组织形式,都是符合标准的TIFF文件。
1.6 TIFF文件调试
由于我个人的编程语言是GO语言,所以这里我选用了https://github.com/google/tiff
这个包(谷歌开源的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级。随着卫星传感器精度增加,单个影像文件越来越大。
大,带来的问题就是不容易保存,本地数据中心存不下,就得上云。但是大量的遥感数据上云后,面临不少挑战:
- 大量的既有软件,无法远程读取云上的(特别是对象存储,如S3)影像文件。必须先Download到本地,然后才能打开分析。
- 即使为软件增加S3驱动。远程分析一个文件,也不得不全量读取文件内容(因为它是链表式的文件)。注意这个是通过网络进行的,所以很影响效率。
- 单独取影像文件中的部分区域(瓦片,或者缩略图),也不得不全量下载or访问整个文件。即使瓦片仅占全影像的1/N。
所以,能不能在访问云上的遥感影像数据的时候,只访问部分(尽可能小的)内容呢?
2.1 GeoTIFF适合云的优化
要达成这个目的,需要有以下能力:
- 云存储协议上支持以 Range方式读取云上的文件。
- 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)标准。规范可以参考:https://www.cogeo.org/
介绍文章可以参考:https://medium.com/planet-stories/cloud-native-geospatial-part-2-the-cloud-optimized-geotiff-6b3f15c696ed
目前该标准得到了业界很多公司的认可:
重要的是,一个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。见:https://github.com/cogeotiff/rio-cogeo
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瓦片性能
官方测试报告里面(见:https://trac.osgeo.org/gdal/wiki/CloudOptimizedGeoTIFF )
显示 512*512 的瓦片大小,性能更优,是因为,
256*256的小瓦片,导致TIFF文件头太大了。第1次16KB取不完,又取了1次导致的。
Ps:首次取的字节数,是可以通过配置控制的。
所以实际业务场景下,具体以多大的瓦片划分,要根据项目影像图片特征适当的调整。
4.4 性能小结
性能对比看,256*256的小瓦片,在做局部在线Web预览加载时,性能更优异。
但是 256*256 的瓦片,意味着瓦片数量更多,TIFF文件头更大,因此需要适当控制“首次取文件头字节”配置。
上述GDAL操作步骤可以参考:https://trac.osgeo.org/gdal/wiki/CloudOptimizedGeoTIFF
其他GADL配置调优可参考:https://developmentseed.org/titiler/advanced/performance_tuning/
5 COG的未来
分享了GeoTIFF影像文件上云后的一系列最佳实践后,我们探讨一下,未来在COG性能方面,有没有云厂商提供更加深度优化方式呢?
可以想到的有:快速的获得COG文件头大小,使得首次HTTP请求,精确取想要的数据,不浪费额外的网络报文。不过这种就需要对象存储提供一些定制能力了。
COG已经是业界普遍认可的云原生的遥感影像数据格式,未来一定可以更加的普及,并且发挥更大的价值。其他有好的想法,也欢迎探讨分享。
华为云地理遥感平台GeoGenius,经过多年的技术项目积累,采用了业界最佳的云原生的遥感影像管理实践,并且提供端到端最优的性能体验,欢迎领域同行了解使用。
详见:https://www.huaweicloud.com/product/geogenius.html