基于DEM规则格网自动生成等高线

遥感院数字摄影测量课程设计题目:基于DEM规则格网自动生成等高线。我在网上查找相关资料,发现并没有什么切实相关的内容,没有人对这一块内容进行一个完整的原理讲解与总结,所以我自己对照武汉大学出版社的《摄影测量学》中讲解的算法原理,结合老师上课所讲内容,理解并完成了这一算法的代码实现。

一、原理介绍

1.1实现流程图

1.2DEM无效值处理

        我们拿到DEM数据之后,一般的组织形式都是:

        第一行为「左下角格网坐标 旋转量 采样间隔 行列数」;第二行开始记录格网点的高程信息

        通过记事本打开DEM数据,观察数据我们可以发现,其中存储的高程数据有大量的值为“-99999”的无效值,这将影响后续DEM状态矩阵计算。

        所以我们要对这些无效值进行处理,处理方法是:最邻近元法。首先找到无效值的位置,然后先沿行,再沿列逐个搜索,找到的第一个有效值数据赋值给该无效值,完成无效值处理。

1.3计算状态矩阵

        创建两个与DEM格网边大小相同的表示状态的矩阵Vk和Hk。

        对整个DEM格网的横边、竖边进行状态判断,判断其是否与给定高度的等高线有相交,即是否有等高线穿过,若有相交则将状态矩阵中的对应值设置为1,否则为0.

        判断相交的准则如下公式所示,其中k表示等高线高程序号,Zk表示待求等高线高程。其中i、j表示格网行列号,Zij表示DEM格网中对应序号点的高程,hij表示对应格网边的状态。

        表示了DEM与等高线水平边(Hk)和竖直边(Vk)的相交状态。若Hk(i,j)=1,说明ij对应的格网与DEM的水平边有交点,既有等高线通过。示例如下图所示:

1.4起始点搜索

        计算完状态矩阵后,对于给定的高程,我们就知道了等高线与DEM格网的相交状态了,下面将进行等高线跟踪查找,在此之前,需要先找到等高线搜索的起点。

        等高线有两种,分别是开曲线与闭曲线,两者的区别在于起始点是否会再次被访问,故需要使用不同的方法查找。

        (1)开曲线查找:

       开曲线是起始点和终止点在DEM边缘的等高线,所以在边缘处查找即可,使用Vk计算起始于第一行和最后一行的等高线,使用HK计算起始于第一列和最后一列的等高线。将找到的格网作为等高线起点。

        将状态矩阵中对应的“1”更改为“0”,以免再次查找。

        (2)闭曲线查找:

        闭曲线是在DEM内部格网中,首尾相连的等高线,所以在内部进行遍历查找,可以使用先搜索行再搜索列的方法遍历查找,第一个有等高线穿过的格网边计作闭曲线的起始边。

        由于起点格网边会作为终点格网边被再次访问,所以在找到起始点后,不将其状态矩阵更改为“0”,再次作为终止点访问时,再设置为“0”,否则闭曲线无法闭合。

1.5等高线跟踪

        找到起点后,就可以对该条等高线进行跟踪,首先将格网进行编号,因为从不同的等高线边进入格网,搜索离去边的代码是不同的。

        

        记录上一步找到的起始边的编号,作为起始格网的进入边,并内插其等高线点坐标,然后再在格网中按照顺(逆)时针的顺序判断另外三条边是否为离去边,若对应状态矩阵为1,则说明是离去边,将该条边

        对应的状态矩阵设置为0,内插等高线点坐标,保存该点的序号与XYZ值,将该离去边作为下一个格网的进入边,再次进行上述的“顺时针查找-内插坐标-记录等高线点-记录离去边(下一格网进入边)”的顺序进行查找。

        比如当前等高线起点从4号边进入,则按照下式顺时针搜索等高线走向:

        找到离去边后,内插该等高线点坐标值,Z为该等高线高程值

        若从3号边出,即下一格网从1号边进入:

        如此循环往复,开曲线查找直到找不到下一离去边/离去边为边缘线,闭曲线查找到起始点位置后找不到下一个离去边为止。

        所有状态矩阵全部为0,该高程对应的等高线搜索完毕,更换下一高程,完成以上2、3、4步算法。直到所有高程的所有等高线全部搜索完毕。

1.6可视化

        使用OSG(OpenSceneGraph)引擎进行可视化,设置参考坐标系的坐标、网格大小等,设置背景颜色、等高线线条粗细、颜色,选择OSG场景漫游方式。

        将等高线模型加入到场景结点中,进行可视化即可。

二、程序框架设计

结构体设计:

struct PtLoc {
	double X;
	double Y;
	double Z;
	int in;
	int col;
	int row;
	int HK;
};

struct CLine {
	std::vector<PtLoc> pt;
	int shape = 0;
};

自定义函数设计:

std::vector<std::vector<double>> GetNearestHeight();
std::vector<std::vector<double>> StateMatHk(int t);
std::vector<std::vector<double>> StateMatVk(int t);

void GetlinePt(std::vector<std::vector<double>>& Hk, std::vector<std::vector<double>>& Vk, double Z, int ni, int nj, CLine& line);
void getline(std::vector<std::vector<double>> Hk, std::vector<std::vector<double>>  Vk, double Z, std::vector<CLine>& Line);
void savelines(std::string dir, std::vector<CLine> Line, int k);
void nlines(std::string dir, double dz);

        GetNearestHeight()用于处理无效值

        StateMatHk()与StateMatVk()用于计算状态矩阵

        GetlinePt()用于给定起点与状态矩阵,跟踪等高线中的点

        getline()用于查找起点,在函数中调用GetlinePt()函数,利用查找到的起点,去跟踪该条等高线中的余下点,并连接成线,同时完成剔除工作。

        nlines()用于按照不同的高程值生成所有等高线。

        savelines()用于保存不同高程的若干等高线到文件中。

三、成果展示

俯视角度:

侧视角度:

局部细节:

四、结果分析

        整体效果良好、理想,能够通过等高线清晰了解地形地貌特征,坡度坡向等信息,且等高线绘制基本正确,边缘处都为开曲线,内部没有意外短接的闭曲线线条疏密合理,高程步距合适,且可以通过osg引擎实现模型的缩放平移,方便观察。

        但是在俯视图中可以看出,右侧有一部分等高线出现了异常,可能是无效值处理的时候导致的问题。

五、反思与展望

        在代码编写的过程中,对于状态矩阵组织、使用方面研究了很久,理解起来容易,实际编写过程中却不知道如何组织数据。

        对于不同的进入边,应该使用不同的查找遍历逻辑,在这里由于自己逻辑混乱,编写错误很多次,不断的梳理修改后终于得出正确结果。

        由于在之前的虚拟现实技术课程中学习过OSG与OpenGL引擎,故这里选择使用OSG引擎去进行等高线的三维可视化,这样可以方便的旋转缩放模型。

该代码中仍有一些部分可以优化:

        1)可以设计等高线跟踪可视化代码,展示等高线跟踪的过程,更清晰的理解等高线跟踪算法原理与过程

        2)输出的等高线是由直线连接等高线点得到的, 因此其一阶导数不连续,可以使用二次曲线拟合方法,将等高线平滑输出。

六、代码

        还没有上传到GitHub上,大家可以参考GitHub - Charrrrrlie/PracticalCourse: 遥感院实习课代码集(数据结构,数字图像处理,遥感原理,解析摄影测量,近景摄影测量,数字摄影测量)中数字摄影测量部分

  • 28
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现格网DEM和TIN内插等高线的过程可以使用Python中的gdal库和qgis库。下面是一个简单的实现过程: 1. 安装gdal库和qgis库 ```python !pip install gdal !pip install qgis ``` 2. 生成随机格网DEM ```python import numpy as np from osgeo import gdal, osr # 定义格网DEM的宽度和高度 width = 100 height = 100 # 定义格网DEM的分辨率 resolution = 10 # 创建一个随机的二维数组作为DEM数据 data = np.random.rand(height, width) # 定义DEM的左上角坐标和投影信息 x_min, y_max = (0, 0) x_max, y_min = (x_min + width * resolution, y_max - height * resolution) srs = osr.SpatialReference() srs.ImportFromEPSG(4326) # 将DEM写入GeoTIFF文件 driver = gdal.GetDriverByName('GTiff') dataset = driver.Create('dem.tif', width, height, 1, gdal.GDT_Float32) dataset.SetGeoTransform((x_min, resolution, 0, y_max, 0, -resolution)) dataset.SetProjection(srs.ExportToWkt()) dataset.GetRasterBand(1).WriteArray(data) dataset.FlushCache() ``` 3. 将DEM转换为TIN ```python import qgis.core # 加载DEM文件 dem_path = 'dem.tif' dem_layer = qgis.core.QgsRasterLayer(dem_path, 'dem') # 定义TIN文件路径 tin_path = 'tin.shp' # 创建TIN params = { 'INPUT': dem_layer, 'FIELD_NAME': 'elevation', 'OUTPUT': tin_path } processing.run('qgis:tin', params) ``` 4. 生成等高线 ```python # 定义等高线间隔 interval = 10 # 定义等高线文件路径 contour_path = 'contour.shp' # 生成等高线 params = { 'INPUT': tin_path, 'INTERVAL': interval, 'FIELD_NAME': 'elevation', 'OUTPUT': contour_path } processing.run('qgis:contour', params) ``` 通过以上步骤,我们就可以实现格网DEM和TIN内插等高线的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值