geotrellis使用(十四)导出定制的GeoTiff
Geotrellis系列文章链接地址http://www.cnblogs.com/shoufengwei/p/5619419.html
目录
一、前言
最近一段时间比较忙,没能继续推进Geotrellis项目开发,周末和这两天抽空又实现了一个功能——导出自定义的Tiff文件。又恰巧碰上今天这么重要的日子,当然要写点东西来纪念一下,所以就有了这篇文章,闲话莫说,进入正题。
二、需求说明
很多时候我们需要从一块(或者很多块)大的Tiff中根据需要截取一部分数据,并且需要采用某种采样方式转成特定的投影,并转成需要的数据类型。当然有人会说这个很容易,用GDAL的gdaltransform等可以很容易的实现此功能,GDAL是很强大,但是前提是你的数据不能太大并且只能处理单块栅格数据。正因为有这些问题,所以我实现了使用Geotrellis来实现该功能,下面我就为大家分析实现方法。
之前讲了很多数据处理方式,其中。
三、实现方案
1.前台界面
前台就是一个简单的地图控件,外加几个选择器。地图控件主要为了浏览区域以及手工选取想要导出的Tiff的范围,选择器主要选择目标投影方式、数据类型以及采样方式。根据用户的选择将请求采用ajax的方式发送到后台进行处理。这块不是本文的重点,不在这里具体介绍。
2.数据导入
要想处理大数据或者处理多块栅格数据就不能直接处理栅格数据,可以先将栅格数据导入到Accumulo中,当然导入之后是一块块的瓦片,这部分在geotrellis使用(三)geotrellis数据处理过程分析一文中已经进行了详细介绍,这里还是要说明的是参数layoutScheme一定要选择floating,这样在Accumulo中保存的就是原始只是切割而未经过其他处理的数据。
3.读取数据
Accumulo中已经存储了需要的数据,并且后台接收到了前台用户选择的区域范围以及投影方式、数据类型、采样方式,这样我们就可以开始实现读取需要的数据,简单的说就是从Accumulo中取出与用户选定区域有交集的数据(瓦片),实现代码如下:
val raster = reader.read[SpatialKey, Tile, TileLayerMetadata[SpatialKey]](layerId)
val masked = raster.mask(polygon)
是不是很容易,就这两句话,其中reader是AccumuloLayerReader实例,layerId表示读取的层,polygon是用户选取的范围。首先从Accumulo中读出该层数据,然后与polygon做一个mask,得到的结果就是用户想要导出的数据。
4.数据转换
4.1 得到结果瓦片数据
首先将上述得到的瓦片集做一个拼接,这样就会得到一个大的瓦片,代码也很简单,如下:
val stitch = masked.stitch
val tile = stitch.tile
4.2 得到最终结果
之后要做的就是根据采样类型、投影方式以及数据类型将上述tile进行转换,代码如下:
val rep = tile.reproject(extent, srcCRS, dstCRS, method).tile
val res = rep.convert(cellType)
其中extent是瓦片的范围,可以用上述拼接对象stitch的stitch.extent得到,srcCRS是原始数据的投影类型,可以通过上述raster对象的raster.metadata.crs得到,dstCRS表示目标投影方式,即用户想要的投影方式,同样method表示采样方法,cellType表示数据类型,这三个的获取方式我会重点介绍。
4.3 获取dstCRS、resampleMethod、cellType
首先可以肯定的是前端传来的这三个参数都是字符串型的,这就要求后台将字符串转成相应的类型。
投影方式我这里投了个懒,传递的是EPSG CODE,EPSG是投影方式的一种数字编码,具体请见:http://www.epsg.org/。总之每一个EPSG编码对应了一种投影方式,像常见的经纬度投影的编码是4326,WebMercator的编码是3857。有了这个编码之后就可以很容易的得到投影方式,代码如下:
try{
CRS.fromEpsgCode(epsg)
}
catch {
case _ => CRS.fromEpsgCode(3857)
}
采样方式和数据类型就稍显麻烦,我这里采用了反射的方式获取对应实例,我将反射的代码进行了封装,代码如下L:
def getClassName(name: String, hasEndWith$: Boolean) = {
var className = name
if (hasEndWith$) {
if (!className.endsWith("$"))
className += "$"
}
else {
if (className.endsWith("$"))
className = className.substring(0, className.length - 1)
}
className
}
def getClassFor[T: ClassTag](name: String, hasEndWith$: Boolean) = {
val className = getClassName(name, hasEndWith$)
Try[Class[_ <: T]]({
val c = Class.forName(className, false, getClass.getClassLoader).asInstanceOf[Class[_ <: T]]
val t = implicitly[ClassTag[T]].runtimeClass
if (t.isAssignableFrom(c)) c else throw new ClassCastException(t + " is not assignable from " + c)
})
}
def getInstanceByReflact[T: ClassTag](name: String) = {
val classTry = getClassFor[T](name, true) recoverWith { case _ => getClassFor[T](name, false) }
classTry flatMap{
c =>
Try{
val module = c.getDeclaredField("MODULE$") //通过获得变量"MODULE$"来初始化
module.setAccessible(true)
val t = implicitly[ClassTag[T]].runtimeClass
module.get(null) match {
case null => throw new NullPointerException
case x if !t.isInstance(x) => throw new ClassCastException(name + " is not a subtype of " + t)
case x: T => x
}
} recover{ case i: InvocationTargetException if i.getTargetException ne null => throw i.getTargetException }
}
这段代码看上去很复杂,其实是做了很多判断加强程序稳定性用的的,主要功能就是一个类的全名(包含包名)创建其实例。
有了上述代码之后就可以将前台传来的字符串直接转换为相应的实例,获取采样方式的代码如下:
val resample = s"geotrellis.raster.resample.${resampleStr}"
val method = getInstanceByReflact[ResampleMethod](resample)
if(method.isSuccess) {
println(method.get.toString)
method.get
}
else {
Bilinear
}
前台只需传入采样方式名称即可,如Bilinear,这样就会自动获取其实例。
获取数据类型同理,代码如下:
val className = getCellTypeClassName(dataTypeStr)
val cellType = getInstanceByReflact[CellType](className)
if(cellType.isSuccess) {
cellType.get
}
else {
ByteConstantNoDataCellType
}
这样就可实现获取用户想要的投影方式、采样方法以及数据类型。
四、总结
以上就是使用Geotrellis实现导出定制的GeoTiff的方法,由于时间紧,可能还有很多没有注意的细节,会在后续中进一步研究,并更新该文或者另设新篇。在这里我也呼吁大家都来撰写技术博客,一来提高自己,进行技术总结;二来真的是可以帮助别人。最近在工作中碰到很多莫名其妙的BUG,但是基本都在一番搜索之后在别人的博客中找到了解决方案,所以在此也感谢那些愿意写博客的人,希望大家都能加入进来。
geotrellis使用(十四)导出定制的GeoTiff的更多相关文章
- SpringBoot入门教程(十四)导出Excel
用JavaPOI导出Excel时,我们会考虑到Excel版本及数据量的问题.针对不同的Excel版本,要采用不同的工具类.HSSFWorkbook:是操作Excel2003以前(包括2003)的版本, ...
- geotrellis使用(四)geotrellis数据处理部分细节
前面写了几篇博客介绍了Geotrellis的简单使用,具体链接在文后,今天我主要介绍一下Geotrellis在数据处理的过程中需要注意的细节,或者一些简单的经验技巧以供参考. 一.直接操作本地Geot ...
- WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇)
原文:WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话)]]在.NE ...
- spring boot 常见三十四问
Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家. 问题一 Spring Boot.Spring MVC 和 Spring 有什么区别 ...
- 我的MYSQL学习心得(十四) 备份和恢复
我的MYSQL学习心得(十四) 备份和恢复 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) ...
- SNF开发平台WinForm之十四-站内发送系统信息-SNF快速开发平台3.3-Spring.Net.Framework
1运行效果: 2开发实现: .组装站内信息发送实体对象. SNFService SNFService = new SNFService(); if (this.ucUser.SelectedIds ! ...
- 《sed的流艺术之四》-linux命令五分钟系列之二十四
本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket. 为了防止某些网站的恶性转载,特在每篇文章前加入此信息,还望读者体谅. ...
- 从零开始学习PYTHON3讲义(十四)写一个mp3播放器
<从零开始PYTHON3>第十四讲 通常来说,Python解释执行,运行速度慢,并不适合完整的开发游戏.随着电脑速度的快速提高,这种情况有所好转,但开发游戏仍然不是Python的重点工作. ...
- 实验十四 第九组 张燕~杨蓉庆~杨玲 Swing图形界面组件
实验十四 Swing图形界面组件 8-11-29 理论知识 Swing和MVC设计模式 (1)设计模式(Design pattern)是设计者一种流行的 思考设计问题的方法,是一套被反复使用,多数人 ...
随机推荐
- Devexpress
1.隐藏最上面的GroupPanel gridView1.OptionsView.ShowGroupPanel=false; 2.得到当前选定记录某字段的值 sValue=Table.Rows[gri ...
- Servlet解决参数乱码问题
为什么会产生乱码? 之所以会产生乱码,是由于服务器端和客户端的编码方式不一致造成的.客户端与服务器端的交互过程中,存在着两次数据交换:第一次,客户端向服务器端发起请求,第二次数据交换,服务器端响应客户 ...
- Cocos2d 利用继承Draw方法制作可显示三维数据(宠物三维等)的三角形显示面板
很久没有写博客了,这段时间比较忙,又是搬家又是做自己的项目,还有太多琐碎的事情缠身,好不容易抽出时间把最近自己做的一些简单例子记录一下. 在我的项目中,我需要一个显示面板来显示游戏中的一个三维数据,例 ...
- 异常处理_Maven之web项目java.lang.LinkageError
浏览器运行项目异常如下: HTTP Status 500 - type Exception report message description The server encountered an i ...
- *HDU 1709 母函数
The Balance Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- 封装自己的DB类(PHP)
封装一个DB类,用来专门操作数据库,以后凡是对数据库的操作,都由DB类的对象来实现.这样有了自己的DB类,写项目时简单的sql语句就不用每次写了,直接调用就行,很方便! 1.封装一个DB类.一个类文件 ...
- poj2718-Smallest Difference(枚举全排列)
一,题意: 给出最多10个数字,将它们划分为两个整数,求差值最小的值(除非只有一位数,否则不允许出现先导0) 很显然如果总共有n个数,必然有一个整数长n/2,另一个长n-n/2.二,思路: 利用nex ...
- linux内核分析作业8:理解进程调度时机跟踪分析进程调度与进程切换的过程
1. 实验目的 选择一个系统调用(13号系统调用time除外),系统调用列表,使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 分析汇编代码调用系统调用的工作过程,特别是参数的传递的方 ...
- 关于object和embed
最近发现很久之前写的demo 在FF上有兼容问题, 主要发生在如下: 由于时间太久,自己都有点搞不清怎么写的,尤其是object标签,今天查了很多资料,总结一下object标签 在网页中正常显示fla ...
- 魅族M8时期写过几个app,纪念一下曾经的自己
找工作的过程中也看了不少资料和文章,也学着别人弄弄博客,但发现自己临时的行为有点那啥吧..曾经我也写过不少东西,有过自己的一个技术论坛,为当时的魅族M8手机写过一个系列的技术帖子,但因为论坛被我关了, ...