Creating Contour Maps
Creating 3d contour maps using heightmaps in processing.


2011
For some of our past projects we were in the need of creating 3d contour maps in Processing. A contour, or topographic map, uses contour lines which join points of equal elevation above a given level to show valleys and hills. You can think of these lines as intersection of a 3-dimensional surface and several horizontal planes. The following tutorial will cover two main questions. How to generate these contour maps in processing. And how to get the greyscale heightmaps that are needed for the map creation.
Creating a contour map

We started working on different approaches creating the contour maps but realized most of them were either too slow, the results were not really satisfying, or it wasn’t possible to transform them to 3d as they were pixel based. During one of the discussions on the Processing forum, Toxi suggested to use one of the blob detection libraries which definitely ended up being the right way to go.

So after testing different libraries, we decided to use v3gas Blob Detection library which seemed to be the best for our purpose. The whole secret is actually to create several instances of the BlobDetection class with different thresholds at the same time. The following code example will show you how to do that. Your testing you can download one of our heightmaps here: heightmap.gif or follow the instructions in the second part of this tutorial to create your own heightmaps. In order to run the code you will also need the peasy cam library installed, which makes it easy to zoom and rotate the resulting elevation model in 3d space.

processing code

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import blobDetection.*;
import peasy.*;
PeasyCam cam;

PImage img;

float levels = 35; // number of contours
float factor = 1; // scale factor
float elevation = 55; // total height of the 3d model

float colorStart = 0; // Starting degree of color range in HSB Mode (0-360)
float colorRange = 100; // color range / can also be negative

// Array of BlobDetection Instances
BlobDetection[] theBlobDetection = new BlobDetection[int(levels)];

void setup() {
size(1000,800,P3D);
img = loadImage("3.gif"); // heightmap (about 250×250px)
cam = new PeasyCam(this,200);
colorMode(HSB,360,100,100);

//Computing Blobs with different thresholds
for (int i=0 ; i<levels ; i++) {
theBlobDetection[i] = new BlobDetection(img.width, img.height);
theBlobDetection[i].setThreshold(i/levels);
theBlobDetection[i].computeBlobs(img.pixels);
}
}

void draw() {
background(0);
translate(-img.width*factor/2,-img.height*factor/2);

for (int i=0 ; i<levels ; i++) {
translate(0,0,elevation/levels);
drawContours(i);
}
}

By now we have created all the different instances of the blobDetection class and already computed the blobs. It’s important to do that in setup as it will slow down your sketch dramatically if you don’t.

There is not much in the draw loop beside translating our model back to the center and drawing the different contours at different elevation levels. The drawContours function is the last thing to add. That’s where we call the different Blobs of every instance and draw them to the screen. It’s also the part where we apply the coloring for the different contours in relation to their height. See the colorRange and ColorStart Variable that were added at the beginning for changing the color style.

processing code

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
void drawContours(int i) {
Blob b;
EdgeVertex eA,eB;

for (int n=0 ; n<theBlobDetection[i].getBlobNb() ; n++) {
b=theBlobDetection[i].getBlob(n);
if (b!=null) {
stroke((i/levels*colorRange)+colorStart,100,100); // coloring the contours

for (int m=0;m<b.getEdgeNb();m++) {
eA = b.getEdgeVertexA(m);
eB = b.getEdgeVertexB(m);
if (eA !=null && eB !=null)
line(
eA.x*img.width*factor, eA.y*img.height*factor,
eB.x*img.width*factor, eB.y*img.height*factor
);
}
}
}
}

As you can see this is a pretty easy way to create contour maps using a blob detection library. The most important lesson learned with this example is how useful it might be to use things differently than they were intended to achieve your goal. Feel free to use the above code for your projects as well as the heightmaps and let us know about what you have done.
We uploaded a collection of different contour maps and experiments on Flickr.

Contour Map Flickr Set
Creating heightmaps

After creating the contour map sketch we were looking for some good heightmaps. Heightmaps are an easy and common way in 3D computer graphics to store height information using a black/white image, or more specifically a grayscale image, with black representing minimum height and white representing maximum height. You can easily create your own heightmaps using perlin noise to create some pretty good imaginary landscapes. But if you want some real data it’s getting a bit more complicated.
There are different ways to get the height information from different places around the world using services like google maps. But none of them is able to export some kind of heightmap. What we need instead are some DEM (Digital Elevation Model) Files. If you are interested in how these files were collected I recommend the SRTM Wiki Page (NASA Shuttle Radar Topographic Mission ). As there is no real standard in DEM files and a lot of formats are available we will focus on GeoTIFF files. GeoTIFF is a special version of TIFF images which includes additional information like coordinates, projection method, datums and more which are stored in the tiff metadata.
There are several ways for downloading SRTM DEM files. Probably the easiest and fastest is to download them using the CGIAR Download Interface. Pick one of the servers. CGIAR-CSI (USA) seems to be the slowest so pick one of the other ones. Data selection method actually doesn’t matter as it always downloads the whole quadrant file for your chosen area. Make sure you have selected GeoTiff as File Format. You can also click on the map to highlight different quadrants and download them after clicking the yellow “Click here to begin Search” Button. There is also an ftp mirror on the website of the “Joint Research Centre” where you can download the files directly. The third and probably most convenient way to browse and download the SRTM Dataset is a Google Earth overlay provided by the King’s College London. If you have Google Earth already installed, you can easily open it directly using the following link.

Google Earth SRTM Overlay
No matter which one of the above ways you use you will end up with the same or at least similar DEM files.
What we need to do next is convert these files into greyscale heightmaps. To do so download a tool called 3DEM.

Download 3DEM (Windows only)
Install and start the 3DEM tool. You will be asked for the filetype you want to open. Chose GeoTiff here and browse to the location you extracted the downloaded zip archives.
Once you opened the file you will see a colored map with 3d shading. To removing the shading go to Color Scale > Shaded Relief and change the Shade Depth to 0%. Next step is to change the color range to greyscale. Go to the menu and select Color Scale > Modify Scale. There you can define new colors for different heights. You can do that by hand or just download the grayscale.dat and load it using “Load File”. After you loaded the greyscale.dat make sure you press “Reset” to reset the altitude range. I also recommend changing the ocean color to black as well. Before exporting your heightmap you can also remove the grid by selecting Geo Coordinates > Lat-Lon Grid Off. If you want the best possible resolution also choose Operation > Resize Overhead View and change the Mapscale to 1 before finally exporting it by choosing File > Save Map Image.
Download the greyscale.dat to easily change the predefined colorRange to greyscale.

greyscale.dat for 3DEM
There it is, your greyscale heightmap you can use to create the contour map using the processing sketch from above. I recommend loading the heightmap into an image editor like Photoshop and crop or downscale the part you need. You might get into memory problems if your image is to large. Most of the time, an image size around 250×250px is already enough for good results. Also changing the contrast and applying some Gaussian blur might result in better or less noisy contour maps.

We also created a Flickr set with a collection of different large scale heightmaps.

Heightmap Flickr Set