构建数字高程模型(DEM),同时控制山脉数量及其邻近度

时间:2017-08-17 20:39:10

标签: python arrays pandas numpy scipy

我的目标是获得一个2d阵列(即矩阵)的浮点数,可以将其视为数字高程模型(即等高线图),其中平滑轮廓如下图所示,只要我能够控制每次运行脚本时产生的白山数量和彼此之间的距离

白色山脉代表CSV文件中包含大于0.9的值的单元格群,如色标所示。在图中,我们看到两个山脉被值小于0.9的区域划分。 contours 这是我的完整代码,其中包含详细注释,其中我使用卷积滤镜来创建这样的图像:

import numpy as np
import pandas as pd
from scipy import signal
import plotly
import plotly.graph_objs as go


def rndmtx():
    """Generate random 2d-array as a digital elevation model."""

    nx = 100
    ny = 100
    dem1 = np.random.rand(nx, ny)
    # Save array to csv file befor Gaussian filter.
    # Comment the next two lines if reading from the csv file.
    dafr = pd.DataFrame(dem1)
    dafr.to_csv('G_dem1.csv', header=False, index=False)

    # Uncomment the next two lines to read from csv file.
    # dafr = pd.read_csv('G_dem1.csv', header=None)
    # dem1 = dafr.values

    # Apply the first Gaussian filter.
    sizex = 5  # The less sizex and sizey the more highlands.
    sizey = 5  # The more sizex and sizey the more water.
    x, y = np.mgrid[-sizex:sizex+1, -sizey:sizey+1]
    scale = 0.33  # The more scale the bigger the difference in elevation.
    g = np.exp(-scale*(x**2/sizex+y**2/sizey))
    filter1 = g/g.sum()  # Normalise the Gaussian function.

    dem_smooth = signal.convolve(dem1, filter1, mode='valid')
    # Rescale so it lies between 0 and 1.
    dem_smooth = ((dem_smooth - dem_smooth.min())
                  / (dem_smooth.max() - dem_smooth.min()))

    # Apply the second Gaussian filter to make the boundaries smoother.
    sizex = 5
    sizey = 5
    x, y = np.mgrid[-sizex:sizex+1, -sizey:sizey+1]
    g = np.exp(-0.33*(x**2/sizex+y**2/sizey))
    filter2 = g/g.sum()

    dem_smooth1 = signal.convolve(dem_smooth, filter2, mode='valid')
    dem_smooth1 = ((dem_smooth1 - dem_smooth1.min())
                   / (dem_smooth1.max() - dem_smooth1.min()))

    return dem_smooth1

# Get the raw random array of the digital elevation model
#   and assign it to the variable.
contour_xy = rndmtx()

# Save the array into CSV file in the working directory.
df = pd.DataFrame(contour_xy)
df.to_csv('last_data.csv', header=False, index=False)

data = [
    go.Contour(
        z=contour_xy,
        colorscale=[
            [0, 'rgb(0, 161, 233)'], [0.28, 'rgb(0, 161, 233)'],
            [0.28, 'rgb(29, 210, 108)'], [0.50, 'rgb(29, 210, 108)'],
            [0.50, 'rgb(141, 232, 130)'], [0.65, 'rgb(141, 232, 130)'],
            [0.65, 'rgb(254, 254, 152)'], [0.75, 'rgb(254, 254, 152)'],
            [0.75, 'rgb(192, 182, 122)'], [0.82, 'rgb(192, 182, 122)'],
            [0.82, 'rgb(142, 110, 92)'], [0.88, 'rgb(142, 110, 92)'],
            [0.88, 'rgb(171, 147, 142)'], [0.93, 'rgb(171, 147, 142)'],
            [0.93, 'rgb(227, 219, 217)'], [0.97, 'rgb(227, 219, 217)'],
            [0.97, 'rgb(255, 255, 255)'], [1, 'rgb(255, 255, 255)']
        ],
    ),
]

layout = go.Layout(
    yaxis=dict(
        autorange='reversed'
    )
)

figure = go.Figure(data=data, layout=layout)
plotly.offline.plot(figure, filename='dem.html')

每次运行脚本时,我都会得到一个独特的随机数组。

如何控制要生成的白山的数量和距离?

例如,现在我想在地块上放置10座白山,然后我只想要2座山,依此类推。

目前,我使用的是暴力算法,最终使用所需数量的山脉建立绘图,但我无法设置山脉的特定坐标来控制它们之间的距离。

慷慨解答并指出正确的方向非常受欢迎。喜欢玩代码!

1 个答案:

答案 0 :(得分:0)

其中一个笨重的解决方案是在高斯滤波器之前将CSV文件中的某些单元簇填充高于0.9的值,例如全部,如下图所示。

这只是在Excel中打开的CSV文件,具有应用的色阶功能。左边是随机矩阵。在右侧,您可以看到我尝试设置四个相同大小的6x4单元格的山脉,所有单元格都包含值" 1"。 matrices 应用卷积滤镜后,我得到以下结果: contour-try 这不好,因为我只有两座山和两座棕色高地。另外,还有很多水。我希望尽可能少用水。

如果您能指出其他技巧,我不介意从头开始重写脚本。

<强>更新

感谢社区,我终于找到了一个稳定的解决方案: 构建散点图,然后将其转换为轮廓。

请参阅问题Convert Scatter to Contour, every dot turns into a highland