美文网首页技术与生活@IT·互联网开源GIS+空间数据应用
geotrellis使用(三十一)使用geotrellis直接将

geotrellis使用(三十一)使用geotrellis直接将

作者: 魏守峰 | 来源:发表于2017-09-01 23:31 被阅读254次

    前言

    传统上我们需要先将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

    相关文章

      网友评论

      • 35ff82cc64b0:在最新Geotrellis代码中,已经跑不通了
      • 35ff82cc64b0:假设有一个超过1TB大小的GeoTIFF,能否发布服务?不经过预处理吗?
        实验最大数据是多大?:smile:
        魏守峰:@35ff82cc64b0 那要看你的集群的内存是多大,我这里只提供方法,不是做科学研究。代码也仅以当时的为准,更新之后请自行修改。
      • shanyukang:你好,问一下geotrellis 能切图吗?效率咋样?
        魏守峰: @shanyukang 可以的,分布式切图,效率应该比较高

      本文标题:geotrellis使用(三十一)使用geotrellis直接将

      本文链接:https://www.haomeiwen.com/subject/tkkljxtx.html