使用Perlin噪声生成Python随机地图

21

最近,我一直试图克服编程中的一个主要弱点——随机生成。我认为这应该是一件容易的事情,但缺乏简单的信息让我感到非常困扰。我不想听起来很蠢,但对我来说,像这样的地方提供的大部分信息似乎是为已经上过理论数学课程并且获得了学位的数学家撰写的。我不明白我应该如何将这些信息应用到像Python这样的编程语言中。

我已经努力工作了几天,盯着方程式尝试了无数次,但是即使经过了这么多天,再次反复检查我的代码之后,整个时间里唯一正常运行的就是这个噪声生成器,用于生成基本噪声:

import random
import math

random.seed(0)

def generateWhiteNoise(width,height):
    noise = [[r for r in range(width)] for i in range(height)]

    for i in range(0,height):
        for j in range(0,width):
            noise[i][j] = random.randint(0,1)

    return noise

noise = generateWhiteNoise(50,12)

for i in noise:
    print()
    for o in i:
        if(o == 0):
            print('-',end='')
        else:
            print('#',end='')

这段代码会产生以下结果:

##-######--#--#-#--##-###-###---#-##-#-----#--##-#
#-#-##-##-#----##------##--#####-#-##---#--#-##---
-------#-#------#---#-#---###--#--#-###-----##-#--
######--#-#-#--####-###---#---###-##--#-#-##--####
-#----###--------##--##--##-#-#--#----###-####--##
---####-#--#--###-#-#--#--#####--####-#-##-##--#--
----#--####-#-#-#-#-#---#--###------###--#-######-
--###--#-###-------#-##--###---#-####----###-#####
#----##--##-#--##-###--#----#-#-##--##-#-##---###-
##---##----##--##--#--#--###-###-#--#-##---#------
-##----#-###---######---#-#---#---###---#---###-##
#--##-##-###-###---#--##-##--##-##-#-#-##--#-#-##-

我希望最终它能够产生类似于这样的东西:

--------------------------------------------------
------------------####----------------------------
-----------------#####----------------------------
----------------#####-----------------------------
---------------#####--------------###-------------
---------------#####--------------###-------------
---------------------------------####-------------
---######------------------------####-------------
---######------------###--------------------------
----########---------###--------------------------
-----#######---------###--------------------------
------###-----------------------------------------

如何将我产生的白噪声变得平滑,并将其转化为岛屿?有人能以非常简单的方式解释一下吗?

也许我对这些都想错了。


1
我会采纳user1483482的建议。如果你想了解更多内部工作原理,请查看这里:http://devmag.org.za/2009/04/25/perlin-noise/我用Python复制了他的代码,它可以运行,但是速度非常慢,即使使用numpy也是如此。 - seth
3个回答

10

对于你的问题,直接回答是“不行,你无法做到你所想要的”,而第二个答案是“是的,你的思路完全错误”。

原因在于你生成的是完全随机的噪声。而你所需要的是一种有条理的噪声。它们是两种完全不同的类型,你无法从随机噪声中获得有条理的噪声。因此我的答案是这样的。

为了解释为什么,你必须理解这个简单的陈述,我从出色的libnoise文档中重复:


有条理的噪声

一种平滑的伪随机噪声。

有条理的噪声是由一个有条理的噪声函数生成的,它具有三个重要属性:

  • 输入相同的值将总是返回相同的输出值。
  • 输入值的微小变化将产生输出值的微小变化。
  • 输入值的大变化将产生输出值的随机变化。

随机噪声没有这些属性,因此完全不适合你想要实现的目标。

我建议学习Ken Perlin最新的(改进过的)参考实现以及他的SIGGRAPH 2002笔记。

如果你无法理解或实现这些内容,那么只需使用像libnoise这样的库,它是一款出色的LGPL库,最初是用C++编写的,并已移植到许多其他语言中。


2
“你不能从随机噪声中得到连贯的噪声” - 你可以用多种方法做到这一点。最原始的方法是对附近的值进行平均。Perlin噪声是从随机噪声中获取连贯噪声的著名方法。 - reducing activity
你不能从随机噪声中得到连贯的噪声。当然可以。 - endolith
不,相干噪声来自伪随机噪声。随机噪声没有输入属性,在提供时不会始终提供相同的输出。随机噪声根本没有输入属性。请检查您的来源。 - Ian Macintosh

5
这是一个有趣的小问题,可以用以下算法解决:
  1. 生成少量均匀噪声
  2. 将其重新采样成更高分辨率(得到平滑的噪声图像)
  3. 应用阈值以获取False/True数组
  4. 将False/True映射到“-”/“#”
稍微进行一些打印格式化就可以很好地工作。 演示:
import numpy as np
import sys
np.set_printoptions(threshold=sys.maxsize)
from scipy.ndimage.interpolation import zoom
arr = np.random.uniform(size=(4,4))
arr = zoom(arr, 8)
arr = arr > 0.5
arr = np.where(arr, '-', '#')
arr = np.array_str(arr, max_line_width=500)
print(arr)

输出:

[['-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-']
 ['-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-']
 ['-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-']
 ['-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-']
 ['-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-']
 ['-' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#']
 ['-' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#']
 ['-' '-' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#']
 ['-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#']
 ['-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#']
 ['-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#']
 ['-' '-' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#']
 ['-' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#']
 ['-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#']
 ['-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#' '#']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#' '#']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#' '#']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#' '#']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#' '#' '#']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '#' '#' '#']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['#' '#' '#' '#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['#' '#' '#' '#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['#' '#' '#' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']
 ['-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-']]

当然,像其他回答者所指出的那样,使用Perlin或Simplex噪声会给人一种稍微更好的视觉效果。如果你想尝试这个,可以用Perlin/Simplex或任何其他你能获取到的噪声来替换步骤1和2,然后再试一次。


引发 ValueError("阈值必须为非 NAN"),删除此行可以使程序不崩溃,但只显示数组的部分。 - reducing activity
@reducingactivity 不太确定我理解了,你是什么意思? - Overdrivr
np.set_printoptions(threshold=np.nan) crashes with raise ValueError("threshold must be non-NAN ... - reducing activity
看起来他们已经改变了签名,你可以尝试使用 np.set_printoptions(threshold=sys.maxsize) 吗? - Overdrivr
https://numpy.org/doc/stable/reference/generated/numpy.set_printoptions.html - Overdrivr
NameError: name 'sys' is not defined - 在顶部添加 import sys 可以解决此问题!它还可以修复截断的行。 - reducing activity

3
最好使用元胞自动机。您可以在这里找到的算法创建了类似于您想看到的图案。
. . . . . . . . . . . . . . .
. . . . . # # . . . . . # . .
. . . . # # # # . . . # # # .
. . . . . # # # # . . # # # .
. . . . . . # # # # # # # . .
. . . . . . # # # # # # # . .
. . . . # # # # # # # # # . .
. . . # # # # # # # # # # . .
. . # # # # # # . # . # # . .
. . # # # # # . . # . . . . .
. . . # # # # . . . # # # . .
. . . # # # # . . . # # # # .
. . # # # # . . . . . # # # .
. . # # # # . . . . . # # . .
. . . . . . . . . . . . . . .

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接