2

I am using a numpy array to hold Perlin Noise values. I have been told that Perlin Noise values in a 2D array are in the range [-0.7, 0.7] respectively, but this doesn't seem to be true. At least not for Caseman's "noise" library when I adjust the parameters for octaves, persistence, and lacunarity.

I would use a different library, except I can't find any for python that will run anywhere near as fast. Also, the typical formula for normalizing a value to range [0, 1] doesn't seem to work here regardless. Even If I get the min/max values of the unmodified noise, it still doesn't give me the value range I want. I just have to guess what to use for the min/max values until the range is roughly [0, 1].

How can I normalize Perlin Noise values to range [0, 1]?

import noise
import numpy
import sys

def __noise(noise_x, noise_y):
    """
    Generates and returns a noise value normalized to (roughly) range [0, 1].

    :param noise_x: The noise value of x
    :param noise_y: The noise value of y
    :return: float
    """

    value = noise.pnoise2(noise_x, noise_y, 8, 1.7, 2)
    # Normalize to range [0, 1]
    value = numpy.float32((value + 0.6447) / (0.6697 + 0.6447))

    return value


map_arr = numpy.zeros([900, 1600], numpy.float32)

for y in range(900):

    for x in range(1600):

        noise_x = x / 1600 - 0.5
        noise_y = y / 900 - 0.5

        value = __noise(noise_x, noise_y)
        map_arr[y][x] = value

for row in map_arr:
    for num in row:
        sys.stdout.write(str(num) + " ")
    print("")
LuminousNutria
  • 1,883
  • 2
  • 18
  • 44
  • Ah, my mistake. Why doesn't `(map_arr - map_arr.min()) / (map_arr.max() - map_arr.min())` work? – gmds Mar 22 '19 at 01:24
  • @MarcusLim I would have to iterate entirely through the array to generate the relevant min/max values. Then, I would have to iterate through the entire array again to adjust all of the values therein. This seems inefficient. Also, I mentioned that it doesn't get me a range close to [0, 1] anyway. – LuminousNutria Mar 22 '19 at 01:30
  • I am afraid I do not understand. Why would you have to perform iteration, since you can apply a vectorised operation using the code in my comment? – gmds Mar 22 '19 at 01:32
  • @MarcusLim Because when map_arr is first initialized, it is full of zeros. – LuminousNutria Mar 22 '19 at 01:33
  • So you're saying that you want to perform the min/max calculation at the same time as the generation of data, by caching already seen values? That can be done easily, but would it really be such a performance boost? – gmds Mar 22 '19 at 01:34
  • @MarcusLim No, I am asking how to normalize the values to [0, 1] as stated in my question. I don't care how it's done. – LuminousNutria Mar 22 '19 at 01:35
  • Which goes back to what I asked: why would the code I provided not work? You run that *after* populating the array. – gmds Mar 22 '19 at 01:35
  • @MarcusLim Please read my question again. I mention that. It's the second sentence of the second paragraph. – LuminousNutria Mar 22 '19 at 01:36
  • Yes, so what output do you actually get? I cannot see why that wouldn't work, without an actual example to the contrary – gmds Mar 22 '19 at 01:56
  • @MarcusLim How much experience do you have with Perlin Noise? I suspect it's doing something neither of us fully understand. If you doubt me, you can modify my code and check for yourself.. – LuminousNutria Mar 22 '19 at 01:59
  • I was actually unable to reproduce your problem (I get a properly normalised array, with max 1 and min 0), which is why I asked what your output was. – gmds Mar 22 '19 at 02:06
  • @MarcusLim You want me to show a 1600x900 2D array of 32-bit floats? The minimum is about 0.1295 and the maximum is roughly 0.8898. – LuminousNutria Mar 22 '19 at 02:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/190472/discussion-between-marcus-lim-and-luminousnutria). – gmds Mar 22 '19 at 02:13

1 Answers1

3

map_arr = (map_arr - map_arr.min()) / (map_arr.max() - map_arr.min()) (taking advantage of numpy broadcasting and vectorisation) should be sufficient.

gmds
  • 19,325
  • 4
  • 32
  • 58
  • 2
    You probably don't need to use map_arr.max()/min(). In 2D the Perlin noise should be bound between -math.sqrt(2)/2 and math.sqrt(2)/2 (the "about 0.7" the OP referred in the question). – Rick77 Apr 30 '19 at 16:17