GIS知识学习进击之路

后面要从事相关的GIS开发工作,之前并没有系统接触过测绘相关的专业知识,是一个新的领域了,有好多新的概念及专业名词。把工作中遇见和学习的知识,按照项目分类进行下记录,一方面加深新知识的记忆,另一方面方便后面遇见相关问题再次查阅和学习。

一.gdal之gdal2tiles.py转化工作

刚着手开发了一段时间GIS的文件切片工作,主要是对现成的python源码gdal2tiles.py进行一个c++的转化。gdal2tiles.py是GDAL库中用于生成TMS瓦片的python代码,支持谷歌墨卡托EPSG:3857与经纬度EPSG:4326两种瓦片,输出png格式图像。

1.知识链接

哈哈,先放几个大佬的链接,知识太深奥了,先拿着后面慢慢学习。

(1)瓦片及坐标系的一些概念:地图瓦片坐标系定义及计算原理_高德地图瓦片坐标-CSDN博客

 (2)别人家的一个类似的源码处理标注,主要是一些注释和文字解释写的容易明白,主要是源码里的英文注释,个人太水了看不懂,唔.......How it works(14) GDAL2Tiles源码阅读-CSDN博客

 2.gdal2tiles源码输出目录引出的坐标系和瓦片概念

代码转化完了,把输出的结果给了前端使用,前端问文件结果是按照什么逻辑分的目录结构,中间又提到了瓦片、金字塔之类的名词,好吧问到我了,我哪知道,然后就开始百度了,生成的目录结构如下(这里是基于大地坐标系切出的瓦片结构):

 最外层的0-13:切分出了13级瓦片结构。

 上面是瓦片的层级图(也称为地图金字塔)。瓦片层级的下一层文件夹(如6805、13611、13612等)名称代表切出瓦片的唯一x坐标编号,最内层的图片名称(6185.png等)代表切出瓦片的唯一y坐标编号,这里的唯一我理解的是:整个瓦片切分结构是已经确定的了,不会变化,地球上的每个经纬度都能在每个瓦片层级上找到其所在的瓦片位置(以瓦片x、y来定位),就是存在一个映射关系。

3.GetGeoTransform函数引出的仿射矩阵

这个到很好搜出来相关的资料,是文件像素点与实际地理信息建立的一个映射关系,根据仿射矩阵的6个参数,输入像素点计算实际的地理经纬度,或者反推。

我这里做个这么个事,也不是太确定对不对,有大佬懂的话,欢迎指点。手头有俩文件,一个影像文件、一个高程文件,配套的,其中影像文件没有仿射矩阵,无法计算其经纬度信息,然后就依据高程文件给影像文件手动设立了仿射矩阵,也到能对的上,做了如下处理:

(a)左上角经纬度、旋转系数,这4个参数没动,直接拿着给赋值了。

(b)空间分辨率俩个值,按照反比处理了,把两个文件的栅格长宽之比的反比作为常数乘以空间分辨率,就得到了新的分辨率:dstReso = srcReso * srcLen / dstLen.

4.影像文件与高程文件以及图片通道

这个是在处理输入数据时了解的,输入的两个tif文件,

影像文件是一个3通道的(关于图片的通道,就是三原色嘛,红绿蓝,三个通道控制三原色的亮度不同,就叠加形成了五颜六色图像。有意思的还有一个相关的概念-灰度图,就是当三个通道每个像素颜色的值即亮度都相同,图像就没有颜色了,显示灰色吧好像),这里通过gdal读数据的时候术语叫“波段”,波段的每个像素点的值就是该像素的亮度;

高程文件是一个1通道的,其波段的像素点值不代表颜色亮弱,而代表该像素点高度,可以和影像文件配合使用,获取某点的地理信息。

二.openCV库的的使用

1.cv::imread使用的坑

(1)imread读取失败

使用该函数读取一张图片时,老是读取失败,一直提示下面错误:

[ WARN:0@3.003] global loadsave.cpp:248 cv::findDecoder imread_('

解决办法:需要根据自己的调试环境,将附加依赖感项的opencv库改成相应的debug或release版本,我这里用的debug模式,但两种模式的库都添加了,去掉release库,就能够读取成功了。

(2)16位深度图片读取异常

在处理高程文件的时候,需要生成相应的png图片供前端使用,由于精度的需要,将高程文件转化位了16位深度的png图片。下图是生成的16位、8位图片对比效果:

 左边是16位深度图片,右侧为8位深度图片。

在使用8位图片时,8位图片范围在0-255,处理方式为每个像素点的代表高度=像素点值/100*基准高程值,数据相对正确,但是每差一个像素点,高度差10m左右,精度不够;

在使用16位图片时,16位图片范围在0-65535,处理方式为 每个像素点的代表高度=像素点值/10000*基准高程值。差异就在这里体现了,比如某一点,gdal解析出来该像素点值=9278;但使用各种图片软件查看其值=36,而且使用cv::imread()函数进行像素点数据值读取也是36.

出现了不可避免的问题,就把以前的问题也带出来了:

自己调用gdal库生成png图片时,只生成了一个波段,而且再次使用gdal打开该文件调用函数查看是一个波段,为什么各种软件查看包括cv::imread()函数调用查看时,都是有rgb三种波段?

首先,我怀疑gdal中的波段概念跟rgb通道概念不是一码事,网上找资料看了几个,但的确是一个东西;后面,怀疑gdal、opencv生成图片的方式有差异,于是我更改了图片生成方式,用gdal生成像素矩阵,然后调用cv::Mat根据该像素矩阵生成图片,结果明明使用的CV_16UC1(16位无符号整型一通道图片)格式生成的图片,但再次读取格式就变成了8位无符号整型3通道图片。至此基本上确定了是cv::imread()函数的问题了,函数原型为imread( const String& filename, int flags = IMREAD_COLOR ),其参数2代表图像读取方式,默认方式IMREAD_COLOR (代表总是按照3通道数据处理),将参数改为IMREAD_UNCHANGED(按照原格式进行数据处理),果然数据格式跟写入时一样了(16位无符号整型一通道图片),读像素点值也正确了。

排查罪魁祸首(还是自己菜,不理解、没用好函数,哈哈)cv::imread()最终结果再加上查找的资料,其实也可以解释为啥看图软件总是把1波段图像读成3波段了,显示器渲染的问题吧,目前市场主流的硬件屏幕都是8位深度的渲染,然后中间可能就有个默认处理的算法了,然后就看不出来16位深度图片的真实值了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巨菜的阿豪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值