# Smoothing Heightmap Data

I've made a Heightmap Generator that creates island heightmaps like in this picture:

I am dividing the grayscale ( 0 - 255 ) into 4 diferent parts ( water, sand, gras and forrest ) and after coloring those layers the heightmap looks like this:

As you can see, the "coast" is pretty noisy ( there are some sand-pixels on the edges, that are not connected to the island itself )

So my question is, How to smooth that noisy coast / beach ?

Is there any quick method that detects those "lonly" pixels and turns them into water ?

can i use the smoothing function below to smooth the final output ?

( I'm working with either a float[][] or a Color[][] array )

UPDATE

here is my smoothing function that i've implemented in my heightmap generation core.

i don't know if i can use this function for this purpose.

    public static float[][] GenerateSmoothNoise( float[][] baseNoise, int octave ) {
int width = baseNoise.Length;
int height = baseNoise[ 0 ].Length;

float[][] smoothNoise = GetEmptyArray<float>( width, height );

int samplePeriod = 1 << octave; // calculates 2 ^ k
float sampleFrequency = 1.0f / samplePeriod;

for( int i = 0; i < width; i++ ) {
//calculate the horizontal sampling indices
int sample_i0 = ( i / samplePeriod ) * samplePeriod;
int sample_i1 = ( sample_i0 + samplePeriod ) % width; //wrap around
float horizontal_blend = ( i - sample_i0 ) * sampleFrequency;

for( int j = 0; j < height; j++ ) {
//calculate the vertical sampling indices
int sample_j0 = ( j / samplePeriod ) * samplePeriod;
int sample_j1 = ( sample_j0 + samplePeriod ) % height; //wrap around
float vertical_blend = ( j - sample_j0 ) * sampleFrequency;

//blend the top two corners
float top = Interpolate( baseNoise[ sample_i0 ][ sample_j0 ],
baseNoise[ sample_i1 ][ sample_j0 ], horizontal_blend );

//blend the bottom two corners
float bottom = Interpolate( baseNoise[ sample_i0 ][ sample_j1 ],
baseNoise[ sample_i1 ][ sample_j1 ], horizontal_blend );

//final blend
smoothNoise[ i ][ j ] = Interpolate( top, bottom, vertical_blend );
}
}

return smoothNoise;
}


and for those who are interested, i'm calling GenerateSmoothNoise() in this way ->

    public static float[][] GeneratePerlinNoise( float[][] baseNoise, int octaveCount ) {
int width = baseNoise.Length;
int height = baseNoise[ 0 ].Length;

float[][][] smoothNoise = new float[ octaveCount ][][]; //an array of 2D arrays containing

float persistance = 0.7f;

//generate smooth noise
for( int i = 0; i < octaveCount; i++ ) {
smoothNoise[ i ] = GenerateSmoothNoise( baseNoise, i );
}

float[][] perlinNoise = GetEmptyArray<float>( width, height ); //an array of floats initialised to 0

float amplitude = 1.0f;
float totalAmplitude = 0.0f;

//blend noise together
for( int octave = octaveCount - 1; octave >= 0; octave-- ) {
amplitude *= persistance;
totalAmplitude += amplitude;

for( int i = 0; i < width; i++ ) {
for( int j = 0; j < height; j++ ) {
perlinNoise[ i ][ j ] += smoothNoise[ octave ][ i ][ j ] * amplitude;
}
}
}

//normalisation
for( int i = 0; i < width; i++ ) {
for( int j = 0; j < height; j++ ) {
perlinNoise[ i ][ j ] /= totalAmplitude;
}
}

return perlinNoise;
}

• How about applying a gaussian, or another low-pass filter? it should remove those high-frequency noise elements. – Panda Pajama Apr 23 '13 at 7:16
• simple idea, i had it too. i thought that bluring the image will give me a not nice looking output, but i'll give it a try – Ace Apr 23 '13 at 12:21

Note: I'm gonna use the term "pixel" here to refer to a unit of land in your height map.

I'll assume your definition of noise are groups of land pixel are that smaller than certain size and you want these removed (turned into water).

In that case, a simple method may be just counting the total number of connected pixels (size) for each group of land pixels(islands) and removing ones with pixel count below a certain threshold. You can do this in O(n) time using flood fill (http://en.wikipedia.org/wiki/Flood_fill) as follows:

1. For each pixel, start a flood-fill to count number connected land pixels (don't replace any pixels yet). Store this starting pixel in a list if number pixels < threshold. You flag each pixel that you've encountered in the algorithm so that you never look at the same pixel twice.
2. For each pixel you stored in that list, flood-fill and replace land pixel with water pixel.

Pesudocode:

for each pixel at point p in map
count = floodFillCount(p, map)
if(count < threshold)