Skip to content

Instantly share code, notes, and snippets.

@mx-moth
Last active January 17, 2024 04:22
Show Gist options
  • Save mx-moth/40351a93b48eac37649bb43859d0a9f2 to your computer and use it in GitHub Desktop.
Save mx-moth/40351a93b48eac37649bb43859d0a9f2 to your computer and use it in GitHub Desktop.
Simulated true colour plots

Simulated true colour plots

Use reflectance data from datasets to generate simulated true colour plots. This script needs emsarray, matplotlib and scipy installed.

true_colour

import emsarray
import emsarray.plot
import matplotlib.pyplot as plt
import numpy
from scipy.interpolate import interp1d
def reflectance_to_rgb(
r_645: numpy.ndarray,
r_555: numpy.ndarray,
r_470: numpy.ndarray,
*,
bright_factor: float = 12.5,
desaturate_factor: float = 0.6,
) -> numpy.ndarray:
"""
Take an array of radiance values and transform it in to true colour.
The colours are ramped a bit, desatureated, etc.
Parameters
----------
r_645, r_555, r_470 : numpy.ndarray
Arrays representing the surface reflectance (radiance?)
in wavelengths of 645 nm, 555 nm, and 470 nm respectively.
The arrays must be the same shape,
but can have any number of axes.
bright_factor : float
A multiplier that increases the brightness of the image.
Higher numbers are brighter.
desaturate_factor : float
How much to desaturate the image.
Valid range between 0 (grey scale) to 1 (full saturation)
Returns
-------
rgb: numpy.ndarray
An array the same shape as the input arrays
except for one extra axis of length 3.
The final axis represents RGB values suitable for plotting.
The values will be between 0 and 1.
"""
# setup our rgb array using the 3 vars
rgb = numpy.stack([r_645, r_555, r_470], axis=-1)
rgb = numpy.nan_to_num(rgb, nan=1)
# Some colour ramps
in_scale = numpy.array([0, 30, 60, 120, 190, 255], dtype=numpy.float64)
out_scale = numpy.array([0, 130, 160, 210, 240, 255], dtype=numpy.float64)
# Pull the green channel down a little more than the others,
# otherwise it can look more saturated than expected.
g_scale = out_scale - 50
g_scale[0] = 0
g_scale[5] = 255
in_scale = in_scale / 255.
out_scale = out_scale / 255.
g_scale = g_scale / 255.
# apply color channel enhancement
rgb[..., 0] = interp1d(in_scale, out_scale)(rgb[..., 0])
rgb[..., 1] = interp1d(in_scale, g_scale)(rgb[..., 1])
rgb[..., 2] = interp1d(in_scale, out_scale)(rgb[..., 2])
# turn brightness back up a bit
brighter = rgb * bright_factor
# Desaturate the image a bit by blending with a greyscale copy.
# The particulars here are how Pillows ImageEnhance.Color class operates.
#
# Convert to greyscale using the ITU-R 601-2 luma transform.
greyscale_value = (
brighter[..., 0] * 299/1000
+ brighter[..., 1] * 587/1000
+ brighter[..., 2] * 114/1000
)
greyscale = numpy.stack([greyscale_value] * 3, axis=-1)
# Blend with the original to get a desaturated image
rgb = brighter * desaturate_factor + greyscale * (1 - desaturate_factor)
# Clip the values to the [0..1] interval
rgb = numpy.clip(rgb, 0, 1)
# Done!
return rgb
# Open the dataset
dataset_path = 'https://dapds00.nci.org.au/thredds/dodsC/fx3/gbr4_bgc_GBR4_H2p0_B3p1_Cfur_Dnrt/gbr4_bgc_simple_2023-10-19.nc'
dataset = emsarray.open_dataset(dataset_path)
# Arbitrarily select the first time step
dataset = dataset.isel(time=0)
# Red, green, blue channels
reflectance_data_arrays = [
dataset['R_645'],
dataset['R_555'],
dataset['R_470'],
]
# Calculate the true colours from the reflectances
rgb = reflectance_to_rgb(
# Flatten the reflectance data arrays as we pass them in
*(dataset.ems.ravel(da).values for da in reflectance_data_arrays),
bright_factor=10, desaturate_factor=0.6)
# Make a figure
figure = plt.figure(figsize=(6, 10), layout='constrained')
axes = figure.add_subplot(projection=dataset.ems.data_crs)
axes.set_aspect(aspect='equal', adjustable='datalim')
# Add the simulated true colour data
axes.add_collection(dataset.ems.make_poly_collection(
color=rgb[dataset.ems.mask], edgecolor='face'))
# Finish styling the plot
axes.set_title("True colour")
emsarray.plot.add_coast(axes, facecolor='green')
axes.autoscale()
# Save the plot then show it
plt.savefig('./true_colour.png')
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment