Geotrellis系列文章链接地址http://www.cnblogs.com/shoufengwei/p/5619419.html

目录

  1. 前言
  2. 问题探索
  3. 采样说明
  4. 实现方案
  5. 总结

一、前言

       上一篇文章讲了通过Geotrellis导出自定义的Tiff文件(见geotrellis使用(十四)导出定制的GeoTiff),但是实际中有时会有BUG,就是数据值发生非常明显的变化,理论上只进行了切割、重投影操作,数据值不应该会发生特别大的变化。今天认认真真查找了下问题,发现是因为采样方式造成的。

二、问题探索

       使用QGIS打开导出的Tiff文件,形状、位置、投影等信息都正确,甚至大部分数据值都正确,唯一出现问题的地方就是边缘,边缘出现了很多不正常的值。经过试验不同的投影方式、采样方式、数据类型,发现只有在投影方式选择4326(原始数据投影方式是墨卡托-3857),采样方式选择三次卷积法内插等几种重采样方式的时候才会出现边缘的问题,那么很明显导致该问题的原因肯定是投影的时候选择的采样方式造成的,发现问题是解决问题的第一步。

三、采样说明

       什么是采样?先来看一下百度百科对重采样的定义。

就是根据一类象元的信息内插出另一类象元信息的过程。在遥感中,重采样是从高分辨率遥感影像中提取出低分辨率影像的过程。

       简单的说采样就是根据栅格图中坐标点周围的一些值重新计算该点的值。这里我们虽然没有进行降低分辨率操作但是由于改变了投影方式,各坐标点的数据肯定是要重新计算的,所以需要用到重采样。那么为什么采样会造成边缘数据值出现偏差呢?

       很简单,重采样要根据坐标点周围的几个点的值来重新计算当前点的值,在图像边缘处,只有部分临近点有数据,其他无数据的地方会用NODATA值来替代,所以计算结果当然会出问题。

       下面简单介绍一下在Geotrellis中支持的采样方式以及其几种常用的采样方式的简单原理。在Geotrellis中写好了以下几种采样方式:

编号 英文名称 中文名称
1 NearestNeighbor 最邻近内插法
2 Bilinear 双线性内插法
3 CubicConvolution 三次卷积法内插
4 CubicSpline 三次样条插值
5 Lanczos 正交相似变换
6 ... ...

       最近邻插值法是最简单的插值方法。也称作零阶插值,就是令变换后像素值等于距它最近的输入像素值。所以采用该方法边缘值计算不会出现问题。

       双线性内插法取(x,y)点周围的4邻点,在y方向(或x方向)内插两次,再在x方向(或y方向)内插一次,得到(x,y)点的值f(x,y)。

设4个邻点分别为(i,j),(i,j+1),(i+1,j),(i+1,j+1),i代表左上角为原点的行数,j代表列数。设α=x-i,β=y-j,过(x,y)作直线与x轴平行,与4邻点组成的边相交于点(i,y)和点(i+1,y)。先在y方向内插,计算交点的值f(i,y)和f(i+1,y)。f(i,y)即由f(i,j+1)与f(i,j)内插计算而来。简单的说就是选周围的四个点,然后做一条水平的线,按照线性求出水平线与四个点组成的四边形的交点的值,然后根据这两个值再计算出该点的值,理论上使用Bilinear也应该会出现边缘问题,但是实际测试并没有出现。查看其源码,发现其实现原理是根据四个点进行一个加权计算,所以边缘处有值,只是不够准确。

       三次卷积法内插法计算精度高,但计算量大,它考虑坐标点周围的16个邻点值,具体公式不在这里罗列,可以参考(http://wenku.baidu.com/link?url=mvyjK0h98UAldYFr_L0-qW-3Rj73uW_yMz0Jwo4ulbWUIfzdAI9f_qOqv_rVqhlTDmEU3xW6vLxp8JTTDtTeCsBGmcb1pmkUfhv-XlkAB6O)。

       三次样条插值是通过一系列形值点的一条光滑曲线,数学上通过求解三弯矩方程组得出曲线函数组的过程。简单说就是找插值结果是光滑的。其他采样方式不在哲理具体介绍。

       理论上插值结果越精确则需要的邻点就越多,边缘处就越容易出问题。可能Geotrellis中采样代码写的并不完善是导致边缘问题的因素之一,也许随着Geotrellis的更新,边缘问题会自动解决。但是目前来看我们必须要想一个办法来解决这个问题,下面就是本文重点要讲的——使用缓冲区分析的方式解决投影变换中边缘数据值计算的问题。

四、实现方案

1.缓冲区分析

       之前在做矢量数据栅格化的时候已经讲解过一次(见geotrellis使用(十)缓冲区分析以及多种类型要素栅格化)。这里用到缓冲区分析的思想,首先将要导出的区域做一个缓冲区分析,将范围扩大,然后根据扩大后的区域进行切割、重投影、数据类型转换等工作,待处理完毕之后再根据原始区域进行切割,这样虽然投影变换时的边缘问题依然存在,但是有问题的边界比实际需要的边界大,在用原始数据切割的时候,“有问题的边界”自然就被去掉了,就能得到一个正确的结果。下面来看具体实现。

2.扩大区域

       这一步很简单,Geotrellis中已经写好了缓冲区分析的函数,直接调用即可,代码如下:

poly.buffer(3 * cellWidth)

       其中ploy是原始区域,cellWidth是栅格数据的分辨率,这里相当于将面扩大3个像素,保证有足够的邻点。有了扩大后的区域之后,按照上文讲述的方式处理数据即可。

3.裁剪结果

       将得到的处理结果按照原始区域进行切割即可得到最终结果,但是Geotrellis中并没有提供不规则切割的方式,只能按照矩形切割。所以我们只能按照不规则区域的外接矩形进行切割,而原始区域又不一定是矩形,即使按照外接矩形切割一样会在很多地方包含扩大后的边界,得不到理想的效果。为了解决这一问题可以先将处理结果按照原始区域进行mask操作,然后切割,便会得到正确的结果。实现代码如下:

val mask = tile.mask(extent, poly)
val realTile = GeoTiff(mask, extent, crs)
.raster
.crop(poly.envelope)

       其中poly为原始区域,extent为缓冲区分析后的面的外接矩形,crs为数据投影方式,poly.envelope获取原始区域的外接矩形。这样第一行实现了mask操作,第二行先将mask的结果转为Geotiff然后进行crop(切割)操作。

五、总结

       以上就是通过使用缓冲区分析的方式解决投影变换中边缘数据值计算过程中出现偏差的问题。看似简单的原理与实现过程,其实同样可以上升到哲学的高度去思考。当我们解决一个问题的时候,如果不能有所突破何不换个角度考虑绕过这个问题,采取迂回的方式。当然该方法不止能解决重采样造成的问题,凡是涉及到边缘值计算的都可以采用该方法,下一篇文章我将讲解如何使用该方法解决瓦片计算过程中的边缘问题。最后申明这么好的方法并不是我想出来的,要归功于吴老板(具体姓名不在这里透露(●'◡'●))。

geotrellis使用(十六)使用缓冲区分析的方式解决投影变换中边缘数据值计算的问题的更多相关文章

  1. geotrellis使用(十七)使用缓冲区分析的方式解决单瓦片计算边缘值问题

    Geotrellis系列文章链接地址http://www.cnblogs.com/shoufengwei/p/5619419.html 目录 前言 需求分析 实现方案 总结 一.前言        最 ...

  2. MP实战系列(十六)之性能分析插件

    性能分析拦截器,用于输出每条 SQL 语句及其执行时间. 虽然使用阿里的Druid连接池可以完成这个目的,但是,我们一般认为,目前的组件能够达到这个目的,尽量使用目前的组件,因为修改配置和引入第三方库 ...

  3. Hive学习之路 (十六)Hive分析窗口函数(四) LAG、LEAD、FIRST_VALUE和LAST_VALUE

    数据准备 数据格式 cookie4.txt cookie1, ::,url2 cookie1, ::,url1 cookie1, ::,1url3 cookie1, ::,url6 cookie1, ...

  4. [ExtJS5学习笔记]第十六节 Extjs5使用panel新增的ViewModel属性绑定数据

    本文地址:http://blog.csdn.net/sushengmiyan/article/details/39078627 sencha官方API:http://docs.sencha.com/e ...

  5. [Python爬虫] 之十六:Selenium +phantomjs 利用 pyquery抓取一点咨询数据

    本篇主要是利用 pyquery来定位抓取数据,而不用xpath,通过和xpath比较,pyquery效率要高. 主要代码: # coding=utf-8 import os import re fro ...

  6. Android实战简易教程-第六十六枪(server端搭建和server端Json数据交互)

    学习Android有一段时间了.对server端有非常深的好奇,决定对server端的实现进行一些研究,这里实现了一个简单的小样例,用于获取server端的json数据,样例非常easy,适合刚開始学 ...

  7. SpringMVC(十六):如何使用编程方式替代/WEB-INF/web.xml中的配置信息

    在构建springmvc+mybatis项目时,更常用的方式是采用web.xml来配置,而且一般情况下会在web.xml中使用ContextLoaderListener加载applicationCon ...

  8. 设计模式学习笔记(十六)迭代器模式及其在Java 容器中的应用

    迭代器(Iterator)模式,也叫做游标(Cursor)模式.我们知道,在Java 容器中,为了提高容器遍历的方便性,把遍历逻辑从不同类型的集合类中抽取出来,避免向外部暴露集合容器的内部结构. 一. ...

  9. ElasticStack系列之十六 & ElasticSearch5.x index/create 和 update 源码分析

    开篇 在ElasticSearch 系列十四中提到的问题即 ElasticStack系列之十四 & ElasticSearch5.x bulk update 中重复 id 性能骤降,继续这个问 ...

随机推荐

  1. win32进程名查找进程PID

    1. #include <Psapi.h> #pragma comment(lib, "Psapi.lib") DWORD GetProcIDFromName(LPCT ...

  2. 高通AR和友盟SDK的AndroidManifest.xml合并

    高通AR和友盟SDK的AndroidManifest.xml合并 因为高通的AR在android中一开始就要启动,所有主Activity要设置为高通的Activity,即android:name=&q ...

  3. 内存不足时,调用ajax报的错

    在error中遍历出来的异常   很难见

  4. App测试

    (1)App独特测试点: 客户端兼容性测试:系统版本.不同深度定制的rom.屏幕分辨率.中断测试.安装.卸载.升级.对其他程序的干扰等 需要的一些工具: appnium / lr /  jmeter ...

  5. SQL Server差异备份的备份/还原原理

    SQL Server差异备份的备份/还原原理 记住一点:差异备份是基于最后一次完整备份的差异,而不是基于最后一次差异的差异   备份过程: 1-完整备份之后有无对数据库做过修改,如果有,记录数据库的最 ...

  6. 细嗅Promise

    读完这篇文章,预计会消耗你 40 分钟的时间. Ajax 出现的时候,刮来了一阵异步之风,现在 Nodejs 火爆,又一阵异步狂风刮了过来.需求是越来越苛刻,用户对性能的要求也是越来越高,随之而来的是 ...

  7. Unit Testing with NSubstitute

    These are the contents of my training session about unit testing, and also have some introductions a ...

  8. 在Visual Studio上开发Node.js程序(2)——远程调试及发布到Azure

    [题外话] 上次介绍了VS上开发Node.js的插件Node.js Tools for Visual Studio(NTVS),其提供了非常方便的开发和调试功能,当然很多情况下由于平台限制等原因需要在 ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 (17) -----第三章 查询之分页、过滤和使用DateTime中的日期部分分组

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-12 分页和过滤 问题 你想使用分页和过滤来创建查询. 解决方案 假设你有如图3 ...

  10. React 生命周期

    前言 学习React,生命周期很重要,我们了解完生命周期的各个组件,对写高性能组件会有很大的帮助. Ract生命周期 React 生命周期分为三种状态 1. 初始化 2.更新 3.销毁 初始化 1.g ...