# Displacement based on image with colormap

I'm trying to displace a plane based on an image with a given known colormap, such as the examples below.

Is there a way to translate the colormap scale, and consequently the image texture color, into actual displacement?

It seems to take the Value (from HSV color space) of the color to displace, which makes sense based on typical heightmaps being greyscale (0 to 1 or max displacement). I'd be happy with only a proper way to translate from color to 0-1 greyscale image.

Examples:

• Hello, I don't understand how the color gives the information about negative values. If you're only going to use the V component of the HSV you'll only be able to use the top-right quadrant of your first image. I think we're missing something as it looks like the first picture is horizontally and vertically symetrical whereas the abscissa and ordinate tell a different story. Cheers Commented May 29 at 7:25
• @Gorgious How color gives negative values? By mapping a positive range to a negative. If you look at a map with mountains and valleys with color-coded height information, you can surely give valleys which lie below sea level (i.e. have height value below 0) a color like blue for example? If the second colormap would not go from blue over green to yellow but from black to white, the mapping would be trivial with a Map Range node: From Min = 0, From Max = 1, To Min = -4, To Max = 6 or the other way round if you wanted to converted height above/below sea level to a greyscale range. Commented May 29 at 7:49
• @GordonBrinkmann sure but how do you differentiate between a color that would put you in the lower left quadrant of the first picture and a color that would put you in the top right quadrant ? They look like they are the same color. Maybe I didn't understand the image. Commented May 29 at 10:50
• @Gorgious There is no need to differentiate between lower left and top right quadrant. As said in the question: "I'd be happy with only a proper way to translate from color to 0-1 greyscale image." When you have an image texture providing these colors and want to convert them in a heightmap, the above is simple UV mapping. You differentiate from bottom left to top right quadrant by going from bottom left of the image to the top right of the image. The problematic thing about this is, the colors are not easily converted in a heightmap. Commented May 29 at 11:14

This post is just to flesh out the commentary under Gordon's answer. It suggests a strategy that does not depend on any logical progression through the colours in the colour-key, which maps colours to heights.

The group expects 2 inputs: an image of the color-key from 0-1 across its U dimension, and and image of the map.

1. It maps the colors in the color-key to a (perhaps irregular) curve in RGB space. (The 'key-curve'.) The Factor of that curve will be a 0-1 mapping of the corresponding heights.
2. It maps the points of a grid, textured with the map, to the same RGB space, according to its texture. Most of the points will lie on the key-curve.
3. There are some points from the grid which don't have a color found in the key, especially if the map is anti-aliased against its background, round its edges. Those are effectively culled.
4. The transformed grid samples the Factor from the closest point on the key-curve
5. The grid is transformed back to its original X,Y, and Z = an appropriate mapping of the sampled Factor

The group is a little big to illustrate. It can be found in the example .blend, annotated in frames:

• I just saw this now. Amazing. It appears to do the trick. Not sure I fullt understand it completely, but I'm accepting it as an answer. Thank you very much. Commented Aug 6 at 18:22
• @ComicMatrix Basically it is doing what my answer did, only that I did not color my result... but since the question stated translating color into displacement I thought coloring was negligible since this would be trivial. Commented Aug 7 at 2:13

The problem with the colormap is that there is no constant increase (or decrease) in any of the color channels or the hue, which becomes most obvious when you look at the upper region where it goes from green already to a more yellowish color and over to reddish orange, but then back to yellow.

Here is the colormap separated in its RGB channels and the Hue:

Or if a graph makes it easier to see (the black line is the Hue):

As you can see in the greyscales, there is no continuous rise or fall from left to right. So everything based on a single one of these values would be problematic.

I've played along with the values, adding, multiplying, dividing, averaging... and the closest to a continuous gradient was "yellow", meaning I added the red and green channel together and divided by 2:

Now you could try to figure out with a color picker or a Math node set to Less Than or Greater Than what the highest and lowest values are and then map them more or less accurately to the 0 to 1 range with a Map Range node for example.

So if I would now take an image like this:

I separate the color channels, then add the red and green channel together and map it to the 0 to 1 range (I did not divide by 2, the Map Range node takes care of this) to create a heightmap:

This heightmap I can now use for Displacement:

And here a rendered view, for shading I just used a default Principled BSDF:

To get different height values than 0 to 1 like the ones shown in the question, you just have to set the To Min and To Max accordingly, so either 0.2 to 1.8 or -4 to 6. When you set the Displacement node to a Midlevel of 0 and a Scale of 1, the resulting displaced geometry should match those values.

The problem with this approach is, it is quite fiddly and it works now with this colormap, but as soon as you would replace it with a different one you have to reconsider which combination of channels might give the best result, and in case the palette is very colorful there might not even be a really good way to convert it in a 0 to 1 greyscale range. And there is nothing "automatic" about it, as long as you have not found a way to convert it. Apart from that, also the fact that image textures are gamma corrected and (when trying to determine the input range) can give varying result depending on the Color Management settings, this is far from giving perfectly accurate heightmaps.

In the given example, the yellow graph fortunately has no local minima or maxima, so could even be split in discrete sections and then I could calculate formulas to convert it to a linear gradient, but I wanted to spare everyone these mathematics when a simple addition brings an acceptable result.

• Very nice study! I wonder, would it be possible to represent the color map as a Curve in a color 3-space, and then use Geometry Proximity to points, mapped into the same space, to sample the Factor from the curve? Commented May 29 at 15:53
• @RobinBetts Probably... but as I said in the beginning, one problem is that the color map has local maxima and minima in its RGB and Hue channels, I would guess this will lead to problems there as well. But it would be interesting to check that. The other thing is, I don't even know if the given color map follows any real rule or if those are just arbitrary colors someone chose. With a Color Ramp for example I could create any color map I like. Oh, and Color Space matters as well. My solution does not work well if I set the image to Non-Color for example. Commented May 29 at 16:18
• Thank you for the detailed answer! This is indeed not trivial and heavily dependent on the colormap itself and the type of conversion that is done from 3d color space to 1d heightmap. My hope was that there could be a way in Bender that I was not aware of to translate the colormap itself to height or 1d scale. I think I'l try another approach using other software such as MatLab/Octave for this. Thanks again! Commented May 29 at 19:32