目录
一、前言
今天我们来研究一下这个看似简单的问题,在地理信息系统中颜色渲染应当是最基本的操作和功能,比如我们将一幅Landsat数据拖拽到Arcgis或者QGis等软件中,软件会自动为我们呈现出漂亮的图案,一切看似来的那么容易,但是在分布式海量空间数据的情况下实现色彩渲染操作实在也是要了命的。今天我们就接着上一篇文章中的数据处理(权且将色彩渲染归结到数据处理中)来介绍一下如何在Geotrellis中为栅格数据渲染漂亮的色彩。
二、复杂原因及思路分析
普通地理信息系统处理的对象都是单幅图像,当我们打开单幅图像的时候程序很容易获取到关于此数据的数据,包括元数据信息、波段信息、值域范围等等,我理解的色彩渲染就是读出图像的值域范围将其分段对应到相应的色彩即可。而当我们采用分布式处理框架之后,面对的不再是单幅图像,而是一层或一种(Geotrellis中将存储在Accumulo中的数据按照导入名称进行分层管理),而其读取数据的时候也不再是读取整个数据,而是单一瓦片或者部分数据,面对这种方式我们就无法再简单的根据当前请求的数据值域来进行简单的对应。
这个问题上升到哲学就是局部与整体的关系,我们如何根据局部的信息来显示出整体一致的效果。比如我们请求了一个瓦片,我们不可能根据此瓦片的值域做颜色映射,此瓦片作为很小的局部必然不可能包含我们研究范围(整体)的所有信息,但只要我们将其类比到传统地理信息系统就为此问题找到了解决方案。
首先像传统地理信息系统读取整幅图像那样获取我们研究区域的信息,然后将请求的单一瓦片根据整体的信息做色彩映射,这样我们就能得到整体一致的色彩效果。
写到这里我突然有个思路,目前遥感影像匀光匀色是一个很复杂的过程,需要耗费大量的人力和时间也未必能得到理想的效果,我觉得此处可以借鉴上述整体与局部的关系,当我们研究清楚了整体(如全球)遥感影像数据的情况之后,将单幅影像作为局部向整体映射,这样应该就能得到整体一致的匀光匀色效果,此思路有待验证。
三、实现过程
实现过程只需要将上述思路转换成代码即可,首先读取整体(研究区域)信息,此研究区域我们以一个面状区域为例。
3.1 整体信息
简单的说就是将研究区域与数据整体做空间判断,取出研究范围内的数据,然后统计此范围内数据信息。实现代码如下:
val raster = reader.query[SpatialKey, Tile, TileLayerMetadata[SpatialKey]](layerId).where(Intersects(polygon)).result
raster.minMax
很简单的两行代码,其中reader是Accumulo层的读取对象,layerId表示请求层,polygon表示研究的范围,这样就能得到研究区域内值域的分布情况。
3.2 瓦片映射到整体
根据整体信息将值域内的数据值映射到颜色范围内,然后读取单一瓦片根据每个像素点的值选取对应的颜色即可,代码如下:
val cr = ColorRamp(startColor, endColor).stops(stops)
val cm = cr.toColorMap((startValue to endValue).toArray)
tile.renderPng(cm)
其中startColor表示起始颜色值,一般为白色,endColor表示终止颜色值,一般为黑色,stops表示要将此颜色区域分成多少区间,是为了让出来的色彩效果更加平滑,startValue和endValue就是上一步获取到整体的值域范围,tile为请求的瓦片,最终将获取到一幅渲染好的png,将其发送到前台显示即可。
四、总结
本文简单为大家介绍了如何实现栅格数据的色彩渲染,复杂的问题经过分析之后貌似也不是那么复杂,但是这些都要经过一步步探索、反复思索才能找到方案,所以作为一个程序员也不能仅仅关注代码,更应该多理理自己的思路,找到好的解决问题的方案。真的是一入地理信息系统深似海,一入大数据地理信息深似无底洞,牵涉到的东西以及需要学习的东西实在太多。无它法,唯有低着头,朝着目标步履维艰的前进。
Geotrellis系列文章链接地址http://www.cnblogs.com/shoufengwei/p/5619419.html