geotrellis使用(三十一)使用geotrellis直接將GeoTiff發布為TMS服務


前言

傳統上我們需要先將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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM