Skip to main content
gamedev.net
🔒 Locked

Heightmap filter

Started by kapru 6 replies 850+ views
Original Post
kapru
kapru
Hey all im trying to downsample the resolution of chunks of my height map for a LOD algorithm im writing but it seam to be showing up with some artifacts that i cant get rid of Here the input heightmap 513x513 Here the output heightmap 257x257 and here the code im using to downsample it <code> void FilterHeightmap(char *hmap,short dim) { //this function filters down a given height map to half its size short newdim = (dim/2)+1; char *newhmap; int i,j,i2,j2; //create a new temp hmap half the size newhmap = new char[newdim*newdim]; int count; SaveRaw(hmap,"input.raw",dim); for(i=0;i<newdim;i++) for(j=0;j<newdim;j++) { i2=i*2; j2=j*2; count = hmap[(j2*dim)+i2]+ hmap[(j2*dim)+i2+1]+ hmap[((j2+1)*dim)+i2]+ hmap[((j2+1)*dim)+i2+1]; count = count/4; newhmap[(j*newdim)+i] = (char)(count); } //test save output SaveRaw(newhmap,"output.raw",newdim); } </code>
DBX
DBX
Shouldn't that be unsigned char, not char? Otherwise you get -ve values interpreted in the range 128-255
kapru
kapru
i thought char was automatically unsigned
kapru
kapru
changing to unsigned does nothing
d000hg
d000hg
Why not downsize it using a paint program - even MSPaint can do that easily with tolerable results?
darookie
darookie
Quote:
Original post by kapru
i thought char was automatically unsigned

Nope - it isn't. You need to change the input and output to unsigned char pointers. I'd also suggest using a weighted filtering like so:

void FilterHeightmap(const unsigned char *hmap, const int dim){   //this function filters down a given height map to half its size  int newdim = (dim / 2) + 1;  //create a new temp hmap half the size  unsigned char *newhmap = new unsigned char[newdim*newdim];  SaveRaw(hmap, "input.raw", dim);  // clear the new map  memset(newhmap, 0, newdim*newdim);  // using C++: declare variables as you need them.    // run over original dimensions instead of newdim and filter  // line-by-line  int n = dim - 1;  for(int i = 1; i < n; ++i) {     for(int j = 1; j < n; ++j) {        // neighbouring pixel values.        int center, north, south, east, west;                // center pixels gets most attention ( x 4)        center = hmap[(i * dim) + j] * 4;        // neighbouring pixels influence the new value by (1/4)        north  = hmap[((i - 1) * dim)) + j];        south  = hmap[((i + 1) * dim) + j];        east   = hmap[(i * dim) + j + 1];        west   = hmap[(i * dim) + j - 1];         // combine the pixels and scale down        int pixel = (center + north + south + east + west) / 8;        newhmap[((i / 2) * newdim) + (j / 2)] = pixel;     }   }   //test save output   SaveRaw(newhmap, "output.raw", newdim);   // remember to cleanup!   delete [] newhmap;}


Try this, it should work.

Good luck,
Pat.
kapru
kapru
I tried that code but it still came up with crap on the new image
darookie
darookie
Quote:
Original post by kapru
I tried that code but it still came up with crap on the new image

Strange. I've tried the code with your image and it runs fine.
I suppose your Read/Load code is flawed.
Here's my test framework - it loads and saves PGM (portable graymap images):

// Filter test framework by Patrick Levin// This code is Public Domain.// No warranty of any kind is provided.#include <cstdio>#include <cstdlib>#include <cstring>#include <ctype.h>// loads a PGM image; 8 bit only.unsigned char *LoadGraymap(const char *fileName, int &width, int &height) {    FILE *f = fopen(fileName, "rb");    unsigned char *result = 0;    if (f != 0) {       char buf[256];       int i = 0;       for (;;) {          if (fgetc(f) != 'P') break;          if (fgetc(f) != '5') break;          buf[0] = fgetc(f);          // skip WS          while (isspace(buf[0])) buf[0] = fgetc(f);          if (buf[0] == EOF) break;          // skip comment          if (buf[0] == '#') {             while (buf[0] != '\n' && buf[0] != EOF) buf[0] = fgetc(f);             if (buf[0] == EOF) break;          }          // skip WS          while (isspace(buf[0])) buf[0] = fgetc(f);          if (buf[0] == EOF) break;          // read width          i = 0;          while (!isspace(buf) && buf != EOF) buf[++i] = fgetc(f);          if (buf == EOF) break;          buf = 0;          width = atoi(buf);          // skip WS          while (isspace(buf[0])) buf[0] = fgetc(f);          if (buf[0] == EOF) break;          // read height          i = 0;          while (!isspace(buf) && buf != EOF) buf[++i] = fgetc(f);          if (buf == EOF) break;          buf = 0;          height = atoi(buf+1);           // skip WS          while (isspace(buf[0])) buf[0] = fgetc(f);          if (buf[0] == EOF) break;          // read max gray          i = 0;          while (!isspace(buf) && buf != EOF) buf[++i] = fgetc(f);          if (buf == EOF) break;          buf = 0;          i = atoi(buf+1);          // only support 8 bit images          if (i < 256) result = new unsigned char [width * height];          break;       }       if (result) {          if (fread(result, 1, width * height, f) != width * height) {             // read error             delete [] result;             result = 0;          }       }       fclose(f);    }    return result;}// Save a PGM image.bool SaveGraymap(const char *fileName, const unsigned char *img, const int w, const int h) {    bool result = false;    FILE *f = fopen(fileName, "wb");    if (f) {       if (0 < fprintf(f, "P5\n# Written by sample.exe\n%i %i\n255\n", w, h)) {          result = fwrite(img, 1, w * h, f) == w * h;       }       fclose(f);    }        return result;}// Filter n x n image to (n/2) x (n/2)unsigned char* FilterImage(const unsigned char *hmap, const int dim, int &newdim) {  // this function filters down a given height map to half its size (improved version)  newdim = (dim / 2) + 1;  //create a new temp hmap half the size  unsigned char *newhmap = new unsigned char[newdim*newdim];  // clear the new map - FIXED: not necessary//  memset(newhmap, 0, newdim*newdim);  // using C++: declare variables as you need them.    // run over original dimensions instead of newdim and filter  // line-by-line  int n = dim - 1;  for(int i = 1; i < n; ++i) {     for(int j = 1; j < n; ++j) {        // neighbouring pixel values.        int center, north, south, east, west;                // center pixels gets most attention ( x 4)        center = hmap[(i * dim) + j] * 4;        // neighbouring pixels influence the new value by (1/4)        north  = hmap[((i - 1) * dim) + j];        south  = hmap[((i + 1) * dim) + j];        east   = hmap[(i * dim) + j + 1];        west   = hmap[(i * dim) + j - 1];         // combine the pixels and scale down        int pixel = (center + north + south + east + west) / 8;        newhmap[((i / 2) * newdim) + (j / 2)] = pixel;     }     // FIX: duplicate the last odd pixel     newhmap[((i / 2) * newdim) + newdim-1] = newhmap[((i / 2) * newdim) + newdim-2];   }   // FIX: duplicate the last odd line   int ofs = newdim * (newdim-1);   for (int k = 0; k < newdim; ++k) newhmap[ofs + k] = newhmap[ofs - newdim + k];   return newhmap;}// sample program driverint main(int argc, char **argv) {    int w, h, newDim, result = 0;    // load input image    unsigned char *hmap = LoadGraymap("input.pgm", w, h);    unsigned char *filtered = 0;    if (!hmap) {       printf("Failed to load input.pgm.\n");       result = 1;    } else if (w != h) {       printf("Image size %ix%i is not squared.\n", w, h);       result = 2;    } else {       printf("Filtering %ix%i image.\n", w, h);       filtered = FilterImage(hmap, w, newDim);       printf("Filtered image is %ix%i.\n", newDim, newDim);       if (!SaveGraymap("output.pgm", filtered, newDim, newDim)) {          printf("Failed to save output.pgm.\n");       }    }    delete [] hmap;    delete [] filtered;    return result;}

I used PSP to save your image as "input.pgm", which the above program expects as input. Here's the resulting "output.pgm":


Review your code,
Pat.

[edit]Slightly improved filtering. Note that no optimisation has been applied - this is left as an exercise for you [wink].[/edit]

[Edited by - darookie on November 17, 2004 8:49:45 AM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.