目录
一、前言
前面几篇文章讲解了如何使用Geotrellis
进行数据处理、瓦片生成等,今天主要表一下如何使用Geotrellis
进行栅格渲染。
昨日完成了两种数据叠加生成瓦片的工作,然而在进行瓦片渲染的时候始终得不到想要的漂亮的颜色效果,由于这块代码是从之前Geotrellis
官方DEMO
中拷贝过来的,从未进行深究,所以折腾半天也没能实现,无奈那么就看源代码吧,在源代码中找到了这样一篇文档(rendering.md),里面详细讲述了在系统中如何直接使用Geotrellis
进行渲染。本文在对其翻译的基础上,添加自己的部分心得。
二、图像渲染
在上一篇文章中讲述了如何进行矢量数据栅格化操作,以及geotrellis使用(三)geotrellis数据处理过程分析中讲解了如何将geotiff数据导入Accumulo中进行调用,这里不再讲述这些,直接讲解如何对Tile
进行渲染,说白了就是如何使用renderPng
方法,当然你也可以使用renderJpg
,二者基本相同。
最简单的渲染方式
最简单的方式就是直接使用下述代码:
tile.renderPng
其中
tile
表示一个瓦片实例,下文相同。
看似简单的代码,其实也不是那么简单,这里需要注意的就是tile
的数据值必须为颜色值才能得到正确的颜色显示,这里就简单讲解一下Geotrellis
中的颜色值。
Geotrellis
中包含两个颜色类,RGBA
和RGB
,其中RGB表示普通的颜色、RGBA
表示附加了透明度的颜色值。二者均用int
类型进行表示,例如0xFF0000FF
,前两位表示R
值,紧接着两位表示G
值,再后面两位表示B
值,如果是RGBA
模式,则还有两位表示A
值。所以上述瓦片的数据类型必须为int32
,然后为不同的点赋不同的颜色值,即可渲染成一个漂亮的瓦片。
使用ColorMap
类
直接使用上述方式看似简单,其实比较麻烦,不易操作,因为要将瓦片数据值转成不同的颜色值,Geotrellis
完全考虑到了这一点,为我们定义了一个ColorMap
类,能够帮助我们实现瓦片值与颜色值之间的映射。使用方法如下:
val colorMap = ColorMap(...)
tile.renderPng(colorMap)
那么如何定义一个ColorMap
实例呢?其实也很简单,只需要传入一个数据值和颜色值对应的Map
对象即可。代码如下:
val colorMap =
ColorMap(
Map(
3.5 -> RGB(0,255,0),
7.5 -> RGB(63,255,51),
11.5 -> RGB(102,255,102),
15.5 -> RGB(178,255,102),
19.5 -> RGB(255,255,0),
23.5 -> RGB(255,255,51),
26.5 -> RGB(255,153,51),
31.5 -> RGB(255,128,0),
35.0 -> RGB(255,51,51),
40.0 -> RGB(255,0,0)
)
)
上述就可以得到一个ColorMap
对象,其中数据在[-∞, 3.5]
之内的都将对应成RGB(0,255,0)
的颜色,(3.5, 7.5]
之内的都将对应成RGB(63,255,51)
的颜色,以此类推。然后将此对象传递给renderPng
函数,即可得到想要的瓦片图像。
当然ColorMap
类中还定义了一个子类Options
,用于定义ColorMap
的一些选项。
case class Options(
classBoundaryType: ClassBoundaryType = LessThanOrEqualTo,
/** Rgba value for NODATA */
noDataColor: Int = 0x00000000,
/** Rgba value for data that doesn't fit the map */
fallbackColor: Int = 0x00000000,
/** Set to true to throw exception on unmappable variables */
strict: Boolean = false
)
classBoundaryType
表示瓦片值与颜色值的对应方向,如刚刚的[-∞, 3.5]
表示小于等于3.5
,此处可以定义成GreaterThan
,GreaterThanOrEqualTo
,LessThan
,LessThanOrEqualTo
,Exact
,意思非常清楚,不在这里赘述。
noDataColor
表示瓦片的值为noData
的时候显示的颜色。
fallbackColor
表示不在映射范围内的值显示的颜色。
strict
表示如果瓦片数据值不在定义之内,是报错还是使用fallbackColor
进行渲染。
当然定义上述对应关系未免显得繁琐,Geotrellis
为我们定义了一个ColorRamp
类,实现了简单的自定义颜色对应关系的方法。
val colorRamp =
ColorRamp(0xFF0000FF, 0x0000FFFF)
.stops(100)
.setAlphaGradient(0xFF, 0xAA)
表示定义一个从
0xFF0000FF
到0x0000FFFF
有100个渐变点的颜色对应,并且A
值也从0xFF
变至0xAA
。
当然Geotrellis
还为我们定义了一个ColorRamps
类,里面封装了部分常用的颜色变化值,具体可以查看其源码。
final def BlueToOrange =
ColorRamp(
0x2586ABFF, 0x4EA3C8FF, 0x7FB8D4FF, 0xADD8EAFF,
0xC8E1E7FF, 0xEDECEAFF, 0xF0E7BBFF, 0xF5CF7DFF,
0xF9B737FF, 0xE68F2DFF, 0xD76B27FF
)
final def ...
根据瓦片自动生成ColorMap
如果为瓦片直接定义ColorMap
可以得到渲染的瓦片,但是存在颜色值固定无法动态调整以及非专业人员不能得到很好的颜色对应关系的问题。Geotrellis
在ColorMap
中定义了一个方法可以根据瓦片自动生成ColorMap
,方法如下:
val colorMap = ColorMap.fromQuantileBreaks(tile.histogram, ColorRamp(0xFF0000FF, 0x0000FFFF).stops(10))
实现了将瓦片的值均匀对应到
[0xFF0000FF, 0x0000FFFF]
并分成10个等级,其中tile.histogram
表示瓦片的值分布,从这我们不难看出,其完成的是根据瓦片的值统计分布,动态生成了一个ColorMap
实例。
三、总结
以上讲述了如何渲染瓦片,具体效果大家可以自行实验,不在这里展示。虽然实现方法有易有难,但是也都代表了不同的需求,大家可以根据自己的需求选择合适的方法进行渲染。
本次实验再次证实了源码的重要性,还是要细致扎实的研读Geotrellis
源代码方能更好的使用Geotrellis
得到自己想要的结果。
四、参考链接
一、geotrellis使用初探
二、geotrellis使用(二)geotrellis-chatta-demo以及geotrellis框架数据读取方式初探
三、geotrellis使用(三)geotrellis数据处理过程分析
四、geotrellis使用(四)geotrellis数据处理部分细节
五、geotrellis使用(五)使用scala操作Accumulo
六、geotrellis使用(六)Scala并发(并行)编程
七、geotrellis使用(七)记录一次惨痛的bug调试经历以及求DEM坡度实践
八、geotrellis使用(八)矢量数据栅格化
九、geotrellis使用(九)使用geotrellis进行栅格渲染