使用GDAL实现DEM的地貌晕渲图(二)
1. 问题
之前我在《使用GDAL实现DEM的地貌晕渲图(一)》这篇文章里面讲述了DEM晕渲图的生成原理与实现,大体上来讲是通过计算DEM格网点的法向量与日照方向的的夹角,来确定该格网点的晕渲强度值。但其实关于这一点我不是很理解,这样做随着坡面与光源方向的夹角不同,确实产生了不同色调明暗效果;但晕渲图同时又有“阴坡面越陡越暗,阳坡面越陡越亮”的特性的,而阴阳坡面的划分又是跟坡度和坡向相关,之前的生成方法能体现出这种特性吗?
经过查阅资料,却在ArcGIS的帮助文档《山体阴影工具的工作原理》(在线版本可查看这篇文章《ArcGIS教程:山体阴影工作原理》)中查阅到了晕渲图的另外一种生成算法。利用直接利用坡度和坡向的关系,算出每个点的山体阴影值:
并且,在该文档中,还附带了一个具体的计算示例:
具体的算法过程说的很清楚了,可惜的就是不太明白具体的原理是什么,在帮助中指向了一本1998的英文文献[Burrough, P. A. and McDonell, R. A., 1998. Principles of Geographical Information Systems (Oxford University Press, New York), 190 pp]也实在是没法深入查阅深究。而在查阅中文论文的时候,关于这一段的描述也是互相抄袭,摘录如下:
这一段的论述反正我是没看明白的,也就不多做论述了,希望看懂这个算法的大神能指点我一下。
2. 实现
虽然更深入的原理没弄明白,不过作为应用者却足够能够实现其算法了。我这里通过GDAL实现了晕渲图的生成:
#include <iostream>
#include <algorithm>
#include <gdal_priv.h>
#include <osg/Vec3d>
#include <fstream>
using namespace std;
using namespace osg;
// a b c
// d e f
// g h i
double CalHillshade(float *tmpBuf, double Zenith_rad, double Azimuth_rad, double dx, double dy, double z_factor)
{
double dzdx = ((tmpBuf[2] + 2 * tmpBuf[5] + tmpBuf[8]) - (tmpBuf[0] + 2 * tmpBuf[3] + tmpBuf[6])) / (8 * dx);
double dzdy = ((tmpBuf[6] + 2 * tmpBuf[7] + tmpBuf[8]) - (tmpBuf[0] + 2 * tmpBuf[1] + tmpBuf[2])) / (8 * dy);
double Slope_rad = atan(z_factor * sqrt(dzdx*dzdx + dzdy*dzdy));
double Aspect_rad = 0;
if (abs(dzdx) > 1e-9)
{
Aspect_rad = atan2(dzdy, -dzdx);
if (Aspect_rad < 0)
{
Aspect_rad = 2 * PI + Aspect_rad;
}
}
else
{
if (dzdy > 0)
{
Aspect_rad = PI / 2;
}
else if (dzdy < 0)
{
Aspect_rad = 2 * PI - PI / 2;
}
else
{
Aspect_rad = Aspect_rad;
}
}
double Hillshade = 255.0 * ((cos(Zenith_rad) * cos(Slope_rad)) + (sin(Zenith_rad) * sin(Slope_rad) * cos(Azimuth_rad - Aspect_rad)));
return Hillshade;
}
int main()
{
GDALAllRegister(); //GDAL所有操作都需要先注册格式
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); //支持中文路径
const char* demPath = "D:/CloudSpace/我的技术文章/素材/DEM的渲染/dst.tif";
//const char* demPath = "D:/Data/imgDemo/K51E001022/k51e001022dem/w001001.adf";
GDALDataset* img = (GDALDataset *)GDALOpen(demPath, GA_ReadOnly);
if (!img)
{
cout << "Can't Open Image!" << endl;
return 1;
}
int imgWidth = img->GetRasterXSize(); //图像宽度
int imgHeight = img->GetRasterYSize(); //图像高度
int bandNum = img->GetRasterCount(); //波段数
int depth = GDALGetDataTypeSize(img->GetRasterBand(1)->GetRasterDataType()) / 8; //图像深度
GDALDriver *pDriver = GetGDALDriverManager()->GetDriverByName("GTIFF"); //图像驱动
char** ppszOptions = NULL;
ppszOptions = CSLSetNameValue(ppszOptions, "BIGTIFF", "IF_NEEDED"); //配置图像信息
const char* dstPath = "D:\\dst.tif";
int bufWidth = imgWidth;
int bufHeight = imgHeight;
int dstBand = 1;
int dstDepth = 1;
GDALDataset* dst = pDriver->Create(dstPath, bufWidth, bufHeight, dstBand, GDT_Byte, ppszOptions);
if (!dst)
{
printf("Can't Write Image!");
return false;
}
dst->SetProjection(img->GetProjectionRef());
double padfTransform[6] = { 0 };
if (CE_None == img->GetGeoTransform(padfTransform))
{
dst->SetGeoTransform(padfTransform);
}
//申请buf
depth = 4;
size_t imgBufNum = (size_t)bufWidth * bufHeight * bandNum;
float *imgBuf = new float[imgBufNum];
//读取
img->RasterIO(GF_Read, 0, 0, bufWidth, bufHeight, imgBuf, bufWidth, bufHeight,
GDT_Float32, bandNum, nullptr, bandNum*depth, bufWidth*bandNum*depth, depth);
if (bandNum != 1)
{
return 1;
}
//
double startX = padfTransform[0]; //左上角点坐标X
double dx = padfTransform[1]; //X方向的分辨率
double startY = padfTransform[3]; //左上角点坐标Y
double dy = padfTransform[5]; //Y方向的分辨率
//申请buf
size_t dstBufNum = (size_t)bufWidth * bufHeight * dstBand * dstDepth;
GByte *dstBuf = new GByte[dstBufNum];
memset(dstBuf, 0, dstBufNum*sizeof(GByte));
//设置方向:平行光
double solarAltitude = 45.0;
double solarAzimuth = 315.0;
//
double Zenith_rad = osg::DegreesToRadians(90 - solarAltitude);
double Azimuth_math = 360.0 - solarAzimuth + 90;
if (Azimuth_math >= 360.0)
{
Azimuth_math = Azimuth_math - 360.0;
}
double Azimuth_rad = osg::DegreesToRadians(Azimuth_math);
//a b c
//d e f
//g h i
double z_factor = 1;
for (int yi = 1; yi < bufHeight-1; yi++)
{
for (int xi = 1; xi < bufWidth-1; xi++)
{
size_t e = (size_t)bufWidth * yi + xi;
size_t f = e + 1;
size_t d = e - 1;
size_t b = e - bufWidth;
size_t c = b + 1;
size_t a = b - 1;
size_t h = e + bufWidth;
size_t i = h + 1;
size_t g = h - 1;
float tmpBuf[9] = { imgBuf[a], imgBuf[b], imgBuf[c], imgBuf[d], imgBuf[e], imgBuf[f], imgBuf[g],imgBuf[h], imgBuf[i] };
double Hillshade = CalHillshade(tmpBuf, Zenith_rad, Azimuth_rad, dx, -dy, z_factor);
dstBuf[e] = (GByte)(std::min(std::max(Hillshade, 0.0),255.0));
}
}
//写入
dst->RasterIO(GF_Write, 0, 0, bufWidth, bufHeight, dstBuf, bufWidth, bufHeight,
GDT_Byte, dstBand, nullptr, dstBand*dstDepth, bufWidth*dstBand*dstDepth, dstDepth);
//释放
delete[] imgBuf;
imgBuf = nullptr;
//释放
delete[] dstBuf;
dstBuf = nullptr;
//
GDALClose(dst);
dst = nullptr;
GDALClose(img);
img = nullptr;
return 0;
}
最终得到的晕渲结果和ArcMap的晕渲结果比较,几乎是一模一样的:
后续会正式在这个基础之上实现彩色的晕渲图。
3. 参考
[1]. ArcGIS帮助:山体阴影工具的工作原理。
[2]. 基于视觉表象的彩色晕渲地图色彩设计.郭礼珍等.2004
使用GDAL实现DEM的地貌晕渲图(二)的更多相关文章
- 使用GDAL实现DEM的地貌晕渲图(三)
目录 1. 原理 1) ArcMap生成彩色晕渲图 2) 彩色色带赋值 3) 颜色叠加 2. 实现 3. 结语 4. 参考 1. 原理 之前在<使用GDAL实现DEM的地貌晕渲图(一)>和 ...
- 使用GDAL实现DEM的地貌晕渲图(一)
目录 1. 原理 1) 点法向量 2) 日照方向 (1) 太阳高度角和太阳方位角 (2) 计算过程 3) 晕渲强度 2. 实现 3. 参考 @ 1. 原理 以前一直以为对DEM的渲染就是简单的根据DE ...
- 全球数字高程数据(DEM)详解,还有地形晕渲、等高线等干货
1 基本概念 DEM是数字高程模型的英文简称(Digital Elevation Model),是研究分析地形.流域.地物识别的重要原始资料.由于DEM 数据能够反映一定分辨率的局部地形特征,因此通过 ...
- 到手的DEM不会用?教你6个常用强大功能
一.概述 DEM是数字高程模型(Digital Elevation Model)的简称,接触GIS,规划,设计类的多多少少会接触到DEM,可是这个直接查看黑溜溜一片DEM到底可以用来做什么呢? 二.背 ...
- SuperMap空间数据处理与制图操作短视频汇总
转自:http://blog.csdn.net/supermapsupport/article/details/70227669 空间数据处理与制图是GIS系统建设最基础的部分,这里利用超图桌面软件- ...
- ArcGIS 栅格数据教程
ArcGIS 栅格数据教程 全部8个教程,带详细操作步骤和原始数据. 技术咨询:谢老师,135_4855_4328,xiexiaokui#139.com ArcGIS 10.5 此教程中的练习将使用样 ...
- 山顶点提取(ArcPy实现)
一.背景 山顶点指哪些在特定邻域分析范围内,该点都比周围点高的区域.山顶点是地形的重要特征点,它的分布与密度反映了地貌的发育特征,同时也制约着地貌发育.因此,如何基于DEM数据正确有效的提取山顶点,在 ...
- 地形鞍部的提取(ArcPy实现)
1.背景 相邻两山头之间呈马鞍形的低凹部分称为鞍部.鞍部点是重要的地形控制点,它和山顶点.山谷点及山脊线.山谷线等构成地形特征点线,对地形具有很强的控制作用.因此,因此,对这些地形特征点.线的分析研究 ...
- ArcGIS空间分析工具
1. 3D分析 1.1. 3D Features toolset 工具 工具 描述 3D Features toolset (3D 要素工具集) Add Z Information 添加 Z 信息 添 ...
随机推荐
- RedHat 7.3+ORACLE 12c RAC 使用udev绑定磁盘
在RedHat 7中,很多命令发生了改变,其中使用udev对磁盘绑定的命令也发生了变更,不再使用start_udev,而是改为了udevadm,下面具体介绍如何使用udev对磁盘进行绑定,这里对6和7 ...
- 解决 ThinkPHP Undefined class constant 'MYSQL_ATTR_INIT_COM
这是 php.ini 配置所导致: 放开php配置文件中被注释掉的.dll引用即可. extension=php_mysql.dllextension=php_mysqli.dllextension= ...
- ArrayList(1.8)
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...
- LINQ学习笔记(三)
下面对各子句解释 from子句:查询表达式的开始子句,查询表达式必须以from子句开头. 格式:from u in source 其中u表示范围变量,它表示源序列中的每个后续元素,source为数据源 ...
- Windows RabbitMQ 安装
操作系统 Win10 企业版 目标: 在win10上安装RabbitMQ 安装步骤 1.安装RabbitMQ需要先安装Erlang语言开发包,下载地址:http://www.erlang.org/d ...
- PHP 的异步并行 C 扩展 Swoole
PHP的异步.并行.高性能网络通信引擎,使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,异步Redis,数据库连接池,AsyncTask,消息队列, ...
- Tomcat请求过程
Tomcat请求过程 1.用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得. 2.Connector把该请求交给它所在的Servic ...
- 如何从一张图片中裁剪一部分距形图片另存为文件(使用Canvas.CopyRect)
如何从一张图片中裁剪一部分距形图片另存为文件? Delphi / Windows SDK/APIhttp://www.delphi2007.net/DelphiMultimedia/html/delp ...
- 网络包抓取开发包 Npcap
Npcap 是 Nmap 项目的网络包抓取库在 Windows 下的版本. Npcap 是致力于采用 Microsoft Light-Weight Filter (NDIS 6 LWF) 技术和 Wi ...
- Python-基本数据类型(list,tuple)
一. 列列表 1.1 列列表的介绍 列表是python的基础数据类型之⼀一,其他编程语言也有类似的数据类型. 比如JS中的数 组, java中的数组等等. 它是以[ ]括起来, 每个元素用' , ...