Skip to content

Commit

Permalink
Add FLIR visualisation for Landsat-8 (#329)
Browse files Browse the repository at this point in the history
* Add EOB script for FLIR vis

* Raw thermal band in celsius

* Add link in Landsat page

* Add readme

* Add visualisation script

* Add example image
  • Loading branch information
maximlamare authored Oct 24, 2024
1 parent d733222 commit 999afca
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 0 deletions.
1 change: 1 addition & 0 deletions landsat-8/landsat-8.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ The Landsat program is the longest running enterprise for acquisition of satelli
- [Clouds Segmentation](/landsat-8/clouds_segmentation)
- [Pansharpened true color](/landsat-8/true-color-pansharpened)
- [Thermal visualization](/landsat-8/thermal)
- [Thermal FLIR visualization](/landsat-8/thermal-iron)
- [Band quality assessment band visualization](/landsat-8/bqa)
46 changes: 46 additions & 0 deletions landsat-8/thermal-iron/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: FLIR visualisation of the thermal IR band
parent: Landsat-8
grand_parent: Landsat
layout: script
permalink: /landsat-8/thermal-iron/
nav_exclude: true
scripts:
- - Visualization
- script.js
- - EO Browser
- eob.js
- - Raw Values
- raw.js
examples:
- zoom: '11'
lat: '35.18167'
lng: '-5.4657'
datasetId: AWS_LOTL2
fromTime: '2024-07-15T00:00:00.000Z'
toTime: '2024-07-15T23:59:59.999Z'
platform:
- EOB
evalscripturl: https://custom-scripts.sentinel-hub.com/custom-scripts/landsat-8/thermal-iron/eob.js
---
## General description

Since the inception of thermal imaging, infrared cameras have commonly employed a distinctive color palette, ranging from black to blue, magenta, orange, yellow, and culminating in bright white. This palette is frequently referred to as “Iron” or “Ironbow.”

This script allows the visualisation of the thermal IR band of Landsat 8 (Band 10, centered on 10.895 µm) in a FLIR-like palette that was inspired by a StackOverflow post [1]. The script allows the adjustment of 3 parameters:

- **minValue**: The minimum value of the thermal band mapped to the black color.
- **maxValue**: The maximum value of the thermal band mapped to the white color.
- **numSteps**: The number of increments in the color palette.

The script returns the thermal band values in degrees Celsius, converted from Kelvin, for an easier interpretation. Furthermore, the script masks out clouds and cloud shadows using the QA band (BQA).

## Description of representative images

Thermal data over Morocco. Acquired on 15.07.2024.

![Morocco thermal image](fig/fig1.png)


## References
[1] StackOverflow, [Thermal imaging palette](https://stackoverflow.com/questions/28495390/thermal-imaging-palette). Accessed on 19th September 2024.
71 changes: 71 additions & 0 deletions landsat-8/thermal-iron/eob.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//VERSION=3

// Set Min and Max values for display and number of steps in the palette
const minValue = 10
const maxValue = 45
const numSteps = 200

// Setup palette
const palette_colours = palette(numSteps, minValue, maxValue)
const viz = new ColorRampVisualizer(palette_colours);


function setup() {
return {
input: ["B10", "BQA", "dataMask"],
output: [
{ id: "default", bands: 4 },
{ id: "eobrowserStats", bands: 2 },
{ id: "dataMask", bands: 1 },
],
};
}

function evaluatePixel(samples) {
let val = samples.B10 - 273;
let clouds = isCloud(samples)

return {
default: [...viz.process(val), (samples.dataMask * (clouds ? 0 : 1))],
eobrowserStats: [val, clouds ? 0 : 1],
dataMask: [samples.dataMask],
};
}

function isCloud(sample) {
const BQA = decodeL8C2Qa(sample.BQA);
let cloudPresence = false
if (BQA.cloud == 1 || BQA.cloudShadow == 1 || BQA.cirrus == 1 || BQA.dilatedCloud == 1) {
cloudPresence = true
}
return cloudPresence
}

function componentToHex(c) {
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}

function rgbToHex(r, g, b) {
return "0x" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}

function palette(colour_length, min_value, max_value){
let colourPairs = []
let values = Array.from({length: colour_length}, (_, i) => min_value + (max_value - min_value) * i / (colour_length - 1));
for (var idx = 0; idx < colour_length; idx++){
var x = idx * 1.0/colour_length;

// Convert RGB to hex
let coulours = rgbToHex(Math.round(255*Math.sqrt(x)),
Math.round(255*Math.pow(x,3)),
Math.round(255*(Math.sin(2 * Math.PI * x)>=0?
Math.sin(2 * Math.PI * x) :
0 )))

//Make pairs of colours
colourPairs.push([values[idx], coulours.toString()])

}
return colourPairs
}
Binary file added landsat-8/thermal-iron/fig/fig1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions landsat-8/thermal-iron/raw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//VERSION=3

function setup() {
return {
input: ["B10"],
output: {
bands: 1,
sampleType: "FLOAT32"
}
};
}

function evaluatePixel(samples) {
// Convert to Celsius
return [samples.B10 - 273];
}
65 changes: 65 additions & 0 deletions landsat-8/thermal-iron/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//VERSION=3

// Set Min and Max values for display and number of steps in the palette
const minValue = 10
const maxValue = 45
const numSteps = 200

// Setup palette
const palette_colours = palette(numSteps, minValue, maxValue)
const viz = new ColorRampVisualizer(palette_colours);


function setup() {
return {
input: ["B10", "BQA", "dataMask"],
output: {
bands: 4
}
}
}

function evaluatePixel(samples) {
let val = samples.B10 - 273;
let clouds = isCloud(samples)

return [...viz.process(val), (samples.dataMask * (clouds ? 0 : 1))];
}

function isCloud(sample) {
const BQA = decodeL8C2Qa(sample.BQA);
let cloudPresence = false
if (BQA.cloud == 1 || BQA.cloudShadow == 1 || BQA.cirrus == 1 || BQA.dilatedCloud == 1) {
cloudPresence = true
}
return cloudPresence
}

function componentToHex(c) {
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}

function rgbToHex(r, g, b) {
return "0x" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}

function palette(colour_length, min_value, max_value){
let colourPairs = []
let values = Array.from({length: colour_length}, (_, i) => min_value + (max_value - min_value) * i / (colour_length - 1));
for (var idx = 0; idx < colour_length; idx++){
var x = idx * 1.0/colour_length;

// Convert RGB to hex
let coulours = rgbToHex(Math.round(255*Math.sqrt(x)),
Math.round(255*Math.pow(x,3)),
Math.round(255*(Math.sin(2 * Math.PI * x)>=0?
Math.sin(2 * Math.PI * x) :
0 )))

//Make pairs of colours
colourPairs.push([values[idx], coulours.toString()])

}
return colourPairs
}

0 comments on commit 999afca

Please sign in to comment.