zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    contentSize,contentOffset,contentInset整理
    UITableViewCell的移动
    怎么修改Xcode新项目或新文件最上面的Creat By XXX
    objc_setAssociatedObject 关联对象
    Python strip()方法
    Python函数中*args和**kwargs来传递变长参数的用法
    python闭包
    Grand Garden思维题
    Circles Inside a Square(几何题)
    Matrix Transformation(模拟)
  • 原文地址:https://www.cnblogs.com/shoufengwei/p/7465431.html
Copyright © 2011-2022 走看看