14

Since the early days of thermal imaging, infrared cameras often use a distinctive palette that runs from black through blue, magenta, orange, yellow to bright white. This palette is often called Iron, or Ironbow.

Here is a typical false color visualization of an image taken with a forward looking infrared camera (source: Wikipedia).

"Termografia kot" by Lcamtuf - a typical false color infrared

"Termografia kot" by Lcamtuf - work by Wikipedia user Lcamtuf. Licensed under CC BY-SA 3.0 via Wikimedia Commons "Termografia kot" by Lcamtuf - work by user Lcamtuf. Licensed under CC BY-SA 3.0 via Wikimedia Commons

On a specialized infrared imagery forum I've found a post from 2005 with a discrete palette that seems to be close to what I am looking for.

A discrete FLIR palette of unknown origin

enter image description here

However as with the rainbow palette it would be nice to have a concise analytical expression that defines the palette.

To those who have used GNUPLOT this palette might look familiar as the default PM3D palette runs black-blue-magenta-orange-yellow.

GNUPLOT PM3D palette

GNUPLOT PM3D palette

This palette has a concise definition

r = Math.round(255*Math.sqrt(x)); 
g = Math.round(255*Math.pow(x,3)); 
b = Math.round(255*(Math.sin(2 * Math.PI * x)>=0?
                   Math.sin(2 * Math.PI * x) : 0 ));

However it is not quite how the other palette looks. A bit too brownish to my taste. Any additional information on the origins or an analytical expression for the palette used in FLIR cameras would help.

I have created a JSFiddle to play with different palettes.

Dima Chubarov
  • 16,199
  • 6
  • 40
  • 76
  • 2
    I hope [these graphs](https://jsfiddle.net/ycu5vv40/) help :-) There surely is a concise formula, but I haven't yet figured it out. – Bergi May 06 '15 at 03:34

6 Answers6

7

It is unlikely that you'll find a formula for the color palette. So you should use a color array.

Here is FLIR's Iron palette (from here), and its colors in an array:

enter image description here

var iron_palette = [
"#00000a","#000014","#00001e","#000025","#00002a","#00002e","#000032","#000036",
"#00003a","#00003e","#000042","#000046","#00004a","#00004f","#000052","#010055",
"#010057","#020059","#02005c","#03005e","#040061","#040063","#050065","#060067",
"#070069","#08006b","#09006e","#0a0070","#0b0073","#0c0074","#0d0075","#0d0076",
"#0e0077","#100078","#120079","#13007b","#15007c","#17007d","#19007e","#1b0080",
"#1c0081","#1e0083","#200084","#220085","#240086","#260087","#280089","#2a0089",
"#2c008a","#2e008b","#30008c","#32008d","#34008e","#36008e","#38008f","#390090",
"#3b0091","#3c0092","#3e0093","#3f0093","#410094","#420095","#440095","#450096",    
"#470096","#490096","#4a0096","#4c0097","#4e0097","#4f0097","#510097","#520098",
"#540098","#560098","#580099","#5a0099","#5c0099","#5d009a","#5f009a","#61009b",
"#63009b","#64009b","#66009b","#68009b","#6a009b","#6c009c","#6d009c","#6f009c",
"#70009c","#71009d","#73009d","#75009d","#77009d","#78009d","#7a009d","#7c009d",
"#7e009d","#7f009d","#81009d","#83009d","#84009d","#86009d","#87009d","#89009d",
"#8a009d","#8b009d","#8d009d","#8f009c","#91009c","#93009c","#95009c","#96009b",
"#98009b","#99009b","#9b009b","#9c009b","#9d009b","#9f009b","#a0009b","#a2009b",
"#a3009b","#a4009b","#a6009a","#a7009a","#a8009a","#a90099","#aa0099","#ab0099",
"#ad0099","#ae0198","#af0198","#b00198","#b00198","#b10197","#b20197","#b30196",
"#b40296","#b50295","#b60295","#b70395","#b80395","#b90495","#ba0495","#ba0494",
"#bb0593","#bc0593","#bd0593","#be0692","#bf0692","#bf0692","#c00791","#c00791",
"#c10890","#c10990","#c20a8f","#c30a8e","#c30b8e","#c40c8d","#c50c8c","#c60d8b",
"#c60e8a","#c70f89","#c81088","#c91187","#ca1286","#ca1385","#cb1385","#cb1484",
"#cc1582","#cd1681","#ce1780","#ce187e","#cf187c","#cf197b","#d01a79","#d11b78",
"#d11c76","#d21c75","#d21d74","#d31e72","#d32071","#d4216f","#d4226e","#d5236b",
"#d52469","#d62567","#d72665","#d82764","#d82862","#d92a60","#da2b5e","#da2c5c",
"#db2e5a","#db2f57","#dc2f54","#dd3051","#dd314e","#de324a","#de3347","#df3444",
"#df3541","#df363d","#e0373a","#e03837","#e03933","#e13a30","#e23b2d","#e23c2a",
"#e33d26","#e33e23","#e43f20","#e4411d","#e4421c","#e5431b","#e54419","#e54518",
"#e64616","#e74715","#e74814","#e74913","#e84a12","#e84c10","#e84c0f","#e94d0e",
"#e94d0d","#ea4e0c","#ea4f0c","#eb500b","#eb510a","#eb520a","#eb5309","#ec5409",
"#ec5608","#ec5708","#ec5808","#ed5907","#ed5a07","#ed5b06","#ee5c06","#ee5c05",
"#ee5d05","#ee5e05","#ef5f04","#ef6004","#ef6104","#ef6204","#f06303","#f06403",
"#f06503","#f16603","#f16603","#f16703","#f16803","#f16902","#f16a02","#f16b02",
"#f16b02","#f26c01","#f26d01","#f26e01","#f36f01","#f37001","#f37101","#f37201",
"#f47300","#f47400","#f47500","#f47600","#f47700","#f47800","#f47a00","#f57b00",
"#f57c00","#f57e00","#f57f00","#f68000","#f68100","#f68200","#f78300","#f78400",
"#f78500","#f78600","#f88700","#f88800","#f88800","#f88900","#f88a00","#f88b00",
"#f88c00","#f98d00","#f98d00","#f98e00","#f98f00","#f99000","#f99100","#f99200",
"#f99300","#fa9400","#fa9500","#fa9600","#fb9800","#fb9900","#fb9a00","#fb9c00",
"#fc9d00","#fc9f00","#fca000","#fca100","#fda200","#fda300","#fda400","#fda600",
"#fda700","#fda800","#fdaa00","#fdab00","#fdac00","#fdad00","#fdae00","#feaf00",
"#feb000","#feb100","#feb200","#feb300","#feb400","#feb500","#feb600","#feb800",
"#feb900","#feb900","#feba00","#febb00","#febc00","#febd00","#febe00","#fec000",
"#fec100","#fec200","#fec300","#fec400","#fec500","#fec600","#fec700","#fec800",
"#fec901","#feca01","#feca01","#fecb01","#fecc02","#fecd02","#fece03","#fecf04",
"#fecf04","#fed005","#fed106","#fed308","#fed409","#fed50a","#fed60a","#fed70b",
"#fed80c","#fed90d","#ffda0e","#ffda0e","#ffdb10","#ffdc12","#ffdc14","#ffdd16",
"#ffde19","#ffde1b","#ffdf1e","#ffe020","#ffe122","#ffe224","#ffe226","#ffe328",
"#ffe42b","#ffe42e","#ffe531","#ffe635","#ffe638","#ffe73c","#ffe83f","#ffe943",
"#ffea46","#ffeb49","#ffeb4d","#ffec50","#ffed54","#ffee57","#ffee5b","#ffee5f",
"#ffef63","#ffef67","#fff06a","#fff06e","#fff172","#fff177","#fff17b","#fff280",
"#fff285","#fff28a","#fff38e","#fff492","#fff496","#fff49a","#fff59e","#fff5a2",
"#fff5a6","#fff6aa","#fff6af","#fff7b3","#fff7b6","#fff8ba","#fff8bd","#fff8c1",
"#fff8c4","#fff9c7","#fff9ca","#fff9cd","#fffad1","#fffad4","#fffbd8","#fffcdb",
"#fffcdf","#fffde2","#fffde5","#fffde8","#fffeeb","#fffeee","#fffef1","#fffef4",
"#fffff6"];
Roland
  • 4,619
  • 7
  • 49
  • 81
minipif
  • 4,756
  • 3
  • 30
  • 39
  • 433 colors in an array? We surely can do better than that. – Bergi May 06 '15 at 01:58
  • If it is too much, you can reduce the array size. If it is not enough, you can interpolate the missing values. If you have a better solution, I'd love to read it. – minipif May 06 '15 at 02:03
  • Still searching :-) So far, I only found an indexed list of 120 shades [here](http://www.infraredtraining.com/community/boards/thread/3019/) – Bergi May 06 '15 at 02:19
  • I've generated the list myself, using the image showed in the question. I'll post my script if you want. You can set the number of shades you want by resizing the image first (letting your image processing software take care of the interpolation for you), and then run the script on that image. – minipif May 06 '15 at 02:22
5

These palettes are arbitrary and is mainly used to improve contrast depending of type of image you're having. The values can therefor be pure custom set.

As IR does not capture any colors (as it is outside the color range) the returned luminance value is simply mapped to what creates best contrast, in particular in regards to edges and shapes.

The iron palette has 5-7 key colors which are then interpolated (red can be made fine-tuning the mixing between yellow and magenta). The exact values and positions can be set any way you like, here is an example:

var ctx = document.querySelector("canvas").getContext("2d");
var gr = ctx.createLinearGradient(0, 0, 600, 0);
var keys = ["white", "gold", "#c07", "#20008c", "black"];

// add color stops to gradient:
for(var i = 0, key; key = keys[i]; i++) {
  gr.addColorStop(i / (keys.length-1), key);
}

ctx.fillStyle = gr;
ctx.fillRect(0, 0, 600, 20);
<canvas width=600></canvas>
1

Here is better polynomial approximation made from RGB: https://jsfiddle.net/ozkh6bp1 I also tried HSL but it didn't produce simpler equations.

var x = 433 * idx / iron.length;
var R = 4.18485e-6*x*x*x - 0.00532377*x*x + 2.19321*x - 39.1125;
var G = 1.28826e-10*x*x*x*x*x-1.64251e-7*x*x*x*x+6.73208e-5*x*x*x-0.00808127*x*x+0.280643*x-1.61706;
var B = 9.48804e-12*x*x*x*x*x-1.05015e-8*x*x*x*x+4.19544e-5*x*x*x-0.0232532*x*x+3.24907*x+30.466;
    var rgb = {r: Math.floor(Math.max(0, R)), 
               g: Math.floor(Math.max(0, G)), 
               b: Math.floor(Math.max(0, B))}

enter image description here

asdjfiasd
  • 1,572
  • 15
  • 28
0

Here is a nice article explaining various thermal color palettes and their usage. These are also showing the color scales, where you can pick the color values using e.g. GIMP. Note that some palettes only use grey scale values. The main point is that there is no single "best" palette. From that also follows that there is no magic formula, and that most palettes are just a set of selected color values, to be implemented as an array of values. Except perhaps that greyscale palettes could easily be implemented with a simple formula.

If you use a limited IR sensor like the 50 dollar one for the raspberry pi with 32 x 24 pixel resolution, you could probably do with a palette of just 10 values.

flir.com about picking a thermal color palette

NB: this seems a commercial site, and it does not feel good to copy its contents here, so just use the link.

Roland
  • 4,619
  • 7
  • 49
  • 81
0

This allows you to create your own color gradient using a few checkpoints:

var imageCanvas = document.createElement("canvas")

const white = [255,255,255]
const yellow = [255,255,0]
const red = [139,0,0]
const blue = [0,0,139]
const black = [0,0,0]
const colors = [black,blue,red,yellow,white]

function colorFromNormal(normalizedHeat) {
    if (normalizedHeat >= 1) {return colors[colors.length-1]}
    if (normalizedHeat <= 0) {return colors[0]}
    const belowIndex = Math.floor(normalizedHeat*(colors.length-1))
    const stepBelow = colors[belowIndex]
    const stepAbove = colors[belowIndex+1]
    var rDiff = stepAbove[0]-stepBelow[0]
    var gDiff = stepAbove[1]-stepBelow[1]
    var bDiff = stepAbove[2]-stepBelow[2]
    const distanceFromBelow = (normalizedHeat-(belowIndex/(colors.length-1)))*(colors.length-1)
    const rFinal = stepBelow[0] + rDiff*distanceFromBelow
    const gFinal = stepBelow[1] + gDiff*distanceFromBelow
    const bFinal = stepBelow[2] + bDiff*distanceFromBelow
    return [rFinal,gFinal,bFinal]
}

function setColor(image,imageCanvas) {// manipulate some pixel elements
    const maximumTemp = foo
    const minimumTemp = bar
    var imageCtx = imageCanvas.getContext("2d");
    var imgData = imageCtx.getImageData(0, 0, width, height);
    var data = imgData.data;
    var ratio = .5 // just a placeholder value
    for (var i = 0; i < data.length; i += 4) {
        
        ratio = (temps[i/4]-minimumTemp) / (maximumTemp - minimumTemp)
        colorVals = colorFromNormal(ratio)
        data[i] = colorVals[0];
        data[i + 1] = colorVals[1];
        data[i + 2] = colorVals[2];
        data[i + 3] = 255; // make this pixel opaque
    }
    // put the modified pixels back on the canvas
    imageCtx.putImageData(imgData, 0, 0);

    // set the img.src to the canvas data url
    image.src = imageCanvas.toDataURL();
}
document.body.appendChild(image);
DavidSM
  • 163
  • 2
  • 7
0

From a simple evenly spaced sample from the original palette, we can get a very similar palette with only 5 colors.

const ironPalette = ['00000A', '91009C', 'E64616', 'FEB400', 'FFFFF6']
David Cavazos
  • 196
  • 1
  • 3