前言
傳統上我們需要先將Tiff中存儲的影像等數據先切割成瓦片,而后再對外提供服務。這樣的好處是服務器響應快,典型的用空間來換時間的操作。然而這樣造成的問題是空間的巨大浪費,一般情況下均需要存儲1-18級左右的瓦片數據。我一直在思考有沒有辦法不存儲瓦片而直接發布TMS服務,當然這樣響應速度肯定是要受一點影響,但是基於Geotrellis的分布式計算對這一點提供了巨大幫助,大大縮短了瓦片臨時切割(存儲於內存中)所用的時間。而且這樣不僅僅是節省了存儲空間的問題,何況我們有時可能只是為了查看數據情況(大量的Tiff文件,無法或者不方便逐一打開),這時不需要事先切割,就能查看大量Tiff文件的數據情況,並且可以逐級縮放。本文介紹如何基於Geotrellis直接將Geotiff發布為TMS服務。
一、效果預覽
閑話不多說,先來看一下效果。我從Google地圖上下載了北京首都國際機場部分影像圖,並將其拼接成了Tiff文件(不是多此一舉,只是為了演示效果)。而后通過Geotrellis成功將其加載到了Leaftlet地圖中。效果如下圖:
二、實現方案
其實總體說起來也很簡單。主要是讀取Tiff文件,並將其根據瓦片編號切割成256*256的小塊並附帶key(row,col)信息,這樣我們就能根據前台發送的key值信息查找后返回相應的瓦片。
2.1 讀取Geotiff文件
使用Spark讀取Geotiff文件,並將其轉成RDD。代碼如下:
val path = new org.apache.hadoop.fs.Path(filePath)
val rdd = HadoopGeoTiffRDD.spatialMultiband(path)
其中filePath表示tiff文件的存放位置,最好是將tiff文件存儲於HDFS中,第二行便得到了需要的rdd,其類型為RDD[(ProjectedExtent, MultibandTile)],其實此處已經完成了Geotiff的讀取和瓦片的切割兩步功能。
2.2 為RDD賦key編碼
這一步較復雜。首先獲取rdd的屬性信息並生成TileLayerMetadata,然后為rdd賦此metadata信息並完成查找。在此簡單敘述之,代碼如下:
- 第一步獲取KeyBounds、空間范圍、數據類型、數據精度等信息。
val sms = rdd
.map { case (key, grid) =>
val ProjectedExtent(extent, crs) = key.getComponent[ProjectedExtent]
// Bounds are return to set the non-spatial dimensions of the KeyBounds;
// the spatial KeyBounds are set outside this call.
val boundsKey = key.translate(SpatialKey(0,0))
val cellSize = CellSize(extent, grid.cols, grid.rows)
HashMap(crs -> RasterCollection(crs, grid.cellType, cellSize, extent, KeyBounds(boundsKey, boundsKey), 1))
}
.reduce { (m1, m2) => m1.merged(m2){ case ((k,v1), (_,v2)) => (k,v1 combine v2) } }
.values.toSeq
- 獲取當前請求層級的瓦片布局信息
val layoutScheme = ZoomedLayoutScheme(WebMercator, tileSize = 256)
val layout = layoutScheme.levelForZoom(zoom)
此處表示的是采用通用的TMS編號信息,投影才用墨卡托,瓦片大小為256。
- 為rdd賦key屬性信息
val sm = sms.head
val metadata = TileLayerMetadata[SpatialKey](
sm.cellType,
layout.layout,
sm.extent,
sm.crs,
sm.bounds.setSpatialBounds(layout.layout.mapTransform(sm.extent))
)
val layoutRdd = rdd.tileToLayout(metadata, resampleMethod)
val contextRDD = new ContextRDD(layoutRdd, metadata)
resampleMethod為采樣方式。
- 根據瓦片編號進行查找
val tile = contextRDD.lookup(SpatialKey(col, row))
找到該瓦片后即可才用前面博客中講述過的方式將其發送到前台,油leftlet進行渲染。
三、總結
本文簡單講述了如何使用Geotrellis直接將Geotiff發布為TMS服務,操作較為繁瑣,對Geotrellis的綜合性知識要求較高。
Geotrellis系列文章鏈接地址http://www.cnblogs.com/shoufengwei/p/5619419.html