Skip to main content

I am trying to use Python to convert a directory of 4 band PlanetScope Surface Reflectance TIFF tiles to RGB JPEGs so I can upload the smaller, easy to visualize JPEG files to LabelBox for manually labeling Arctic lakes as either ice covered or ice free.

I have thrown together a script (relevant functions attached below) which reads in the bands from each of my downloaded TIFF files (I have around 100 right now) and normalizes each of them to 0-255 for conversion to JPEG. 

I have tried many different normalization algorithms, including histogram stretching, but all methods so far leave almost all my images with significant red, green or blue tint, which makes identifying which lakes are ice covered vs. ice free much more difficult (example of blue tint below.)

Is there a way to automatically process RGB files for each of my scenes which will appear without these tints, more like the rgb preview images shown on Planet Explorer?  (Or is there a way to directly download pre-processed RGB directly from Planet for a SR image?)

 

Wrongly blue tinted image
def band_scale(red,green,blue):
# Get the 95th percentile (saturation point) for each band
red_max = np.nanpercentile(red, 95.0)
green_max = np.nanpercentile(green, 95.0)
blue_max = np.nanpercentile(blue, 95.0)

# Find the lowest max value across the three bands
lowest_max = min(red_max, green_max, blue_max)

# Scale each band using the same lowest saturation value
red_scaled = np.interp(red, (0, lowest_max), (0, 255)).astype(np.uint8)
green_scaled = np.interp(green, (0, lowest_max), (0, 255)).astype(np.uint8)
blue_scaled = np.interp(blue, (0, lowest_max), (0, 255)).astype(np.uint8)

return red_scaled, green_scaled, blue_scaled

# Function to convert a 4-band TIF to a 3-band RGB JPEG using rasterio and Pillow
def convert_tif_to_jpeg(tif_path, jpeg_path):
try:
with rasterio.open(tif_path) as src:
# Read the RGB bands (1, 2, 3)
red = src.read(1) # Band 1 - Red
green = src.read(2) # Band 2 - Green
blue = src.read(3) # Band 3 - Blue

# Apply scaling to each band
red_stretched,green_stretched,blue_stretched = band_scale(red,green,blue)

# Stack the bands into a single RGB image
rgb_array = np.stack((red_stretched, green_stretched, blue_stretched), axis=-1)

# Convert to a Pillow image
rgb_jpeg = Image.fromarray(rgb_array)

# Save as JPEG
rgb_jpeg.save(jpeg_path, format='JPEG')
print(f"Saved JPEG: {jpeg_path}")
except Exception as e:
print(f"Error converting {tif_path}: {e}")

 

Hi @NSJacobs,

There is actually an option to download a true color RGB composition directly for any given image if you use the right asset type / bundle. 

  • If you are using Explorer, make sure to select the Visual asset.
  • If you are using Orders API, use the visual bundle (here)

 

This will generate a 3 band multiband GeoTIFF (RGB only), color corrected and optimised for visual analysis. 

 

You can then read that, stack the bands together and save it as a JPEG.

import rasterio
from PIL import Image
import numpy as np

# Path to the 3-band GeoTIFF image
geotiff_image_path = 'your_path'

# Read the GeoTIFF image
with rasterio.open(geotiff_image_path) as src:
red_band = src.read(1)
green_band = src.read(2)
blue_band = src.read(3)

# Create Stack
rgb = np.dstack((red_band, green_band, blue_band))

# Convert to PIL Image (needed to save later as JPEG)
rgb_image = Image.fromarray(rgb)

# Save
output_path = 'your_output_path'
rgb_image.save(output_path)

Hope it helps!

Miguel


Reply