geotrellis使用(四)geotrellis數據處理部分細節


       前面寫了幾篇博客介紹了Geotrellis的簡單使用,具體鏈接在文后,今天我主要介紹一下Geotrellis在數據處理的過程中需要注意的細節,或者一些簡單的經驗技巧以供參考。

一、直接操作本地Geotiff

   如果不想將tiff數據切割成瓦片存放到集群中,也可以直接使用Geotrellis操作本地geotiff文件,可以直接使用SinglebandGeoTiff讀取單波段的tiff,使用MultibandGeoTiff讀取多波段tiff。
val geotiff = SinglebandGeoTiff("data/test.tif")
   然后使用geotiff.tile就可以像處理普通瓦片那樣處理整幅tiff圖像。

二、Geotiff數據處理需要注意的細節

       如果需要將geotiff數據切割並上傳到集群首先需要處理的是geotiff的數據類型、無數據值等元數據信息,即前期處理數據的時候需要將tiff文件處理到合適的情況以方便在程序中使用。

       與數據類型和無數據值相關的屬性是Tile類的CellType,Geotrellis中定義了與各種類型相對應的CellType類型,具體在geotrellis.raster.CellType類中,當然程序中可以使用tile.convert(ShortConstantNoDataCellType)將瓦片的類型轉換為其他形式。

三、獲取瓦片編號或者瓦片的范圍(Extent)

  將數據上傳到集群后,一般可以使用LayerReader將整層的瓦片信息全部讀出,
val r = reader.read[SpatialKey, Tile, TileLayerMetadata[SpatialKey]](layerId)
   其中reader為LayerRander的實例,可以是AccumuloLayerReader等,具體看用戶將瓦片數據存放到什么位置,layerId是存放信息的實例,包含存放的layer名稱以及第幾層,然后就可以使用r.metadata.mapTransform函數獲取
瓦片的范圍或者瓦片的編號,如果該函數的參數是一個key(瓦片編號實例),結果就是瓦片的Extent,如果參數是一個point,算出來的就是包含該點的瓦片的key。

四、數據的重投影

       程序中如果需要對tile進行點、線、面的相交取值等處理就必須使用與tile相同的投影方式,否則處理過程中會出現錯誤,可以使用ReProject首先對點、線、面進行重投影。

Reproject(geo, LatLng, WebMercator)

      其中geo表示需要進行重投影的點、線、面,LatLng是原始投影方式,WebMercator是需要轉換到的投影方式。Geotrellis中定義了一個CRS類用於記錄投影信息。LatLng和WebMercator繼承了CRS類,是定義好的4326和3857投影方式,其他投影類型可以使用CRS類中提供的fromEpsgCode等方法進行設置。

五、獲取某個坐標點對應的值

      如果我們想要獲取某個坐標點所對應的數據的值,有兩種方式,第一種是使用LayerReader先讀取整層瓦片信息,然后根據偏移得到改點的值,具體方法如下:

    val r = reader.read[SpatialKey, Tile, TileLayerMetadata[SpatialKey]](layerId)
    val mapTransform = r.metadata.mapTransform
    val key = r.metadata.mapTransform(point)
    val dataValues: Seq[Double] = r.asRasters().lookup(key).map(_.getDoubleValueAtPoint(point))
    val value = if(dataValues == null || dataValues.length <= 0) 0 else dataValues.head

     其中reader和layerId的意義與上文相同,同樣key就是根據坐標點的偏移算出的瓦片坐標,然后在所有瓦片中查找此key並且獲取該坐標點的值,若多個瓦片均包含該坐標點會獲取多個值,取出第一個。

     第二種方式是使用ValueReader直接找到包含改點的瓦片,然后根據偏移得到此點的數據,具體代碼如下:

    val key = attributeStore.readMetadata[TileLayerMetadata[SpatialKey]](layerId).mapTransform(point)
    val (col, row) = attributeStore.readMetadata[TileLayerMetadata[SpatialKey]](layerId).toRasterExtent().mapToGrid(point)
    val tile: Tile =  tileReader.reader[SpatialKey, Tile](layerId).read(key)
    val tileCol = col - key.col * tile.cols
    val tileRow = row - key.row * tile.rows
    println(s"tileCol=${tileCol}   tileRow = ${tileRow}")
    tile.get(tileCol, tileRow)

     其中attributeStore是元數據信息,與用戶數據上傳的位置有關,key是從元數據中根據坐標點偏移算出的瓦片編號,tilReader是ValueReader實例,col、row是根據偏移算出的坐標點在整個數據集中的像素偏移值,然后通過減去編號乘以瓦片像素個數來獲取相對當前瓦片的偏移,從而實現獲取當前坐標點的數據值。

     兩種方式均能得到坐標點對應的值,但是其效率卻相差幾十倍,在我自己的測試中,使用ValueReader取到數據值大概需要20ms,而使用layerReader則大概需要6000ms,我猜測應當是使用LayerReader的方式會在所有瓦片中lookup,而ValueReader則直接獲取單個瓦片,所以效率存在差別。

六、結束語

   本文簡單記錄了近期使用Geotrellis過程中遇到的一些問題,及其解決方案,目前項目只用到了柵格數據,所以只是針對Raster模塊,后續會探索其他模塊功能,並隨時將心得發布到博客園中,歡迎大家共同探討。

七、參考文獻

一、geotrellis使用初探
二、geotrellis使用(二)geotrellis-chatta-demo以及geotrellis框架數據讀取方式初探
三、geotrellis使用(三)geotrellis數據處理過程分析
四、geotrellis使用(四)geotrellis數據處理部分細節


免責聲明!

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



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