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?)
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}")