Dima Chubarov
Dima Chubarov

Reputation: 17179

Thermal imaging palette

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.

Upvotes: 14

Views: 18538

Answers (6)

David Cavazos
David Cavazos

Reputation: 336

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']

Upvotes: 0

asdjfiasd
asdjfiasd

Reputation: 1730

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

Upvotes: 2

DavidSM
DavidSM

Reputation: 163

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);

Upvotes: 0

minipif
minipif

Reputation: 4876

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"];

Upvotes: 9

Roland
Roland

Reputation: 5232

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.

Upvotes: 0

user1693593
user1693593

Reputation:

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>

Upvotes: 5

Related Questions