Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Image Translation

Introduction

Learning Objectives

Foundations of Image Translation

What Is Image-to-Image Translation?

Super-Resolution for Remote Sensing

Latent Diffusion Models for Super-Resolution

Import Libraries

import geoai
import numpy as np
import rasterio as rio
from matplotlib import pyplot as plt

Download Sample Data

url = "https://data.source.coop/opengeos/geoai/S2C-MSIL2A-20250920T162001-Knoxville.tif"
s2_path = geoai.download_file(url)

Inspecting the Input Data

with rio.open(s2_path) as src:
    print(f"Bands: {src.count}")
    print(f"Size: {src.width} x {src.height}")
    print(f"CRS: {src.crs}")
    print(f"Resolution: {src.res[0]:.2f} m")
    print(f"Dtype: {src.dtypes[0]}")

Visualize the Input RGB Composite

with rio.open(s2_path) as src:
    rgb = src.read([1, 2, 3]).astype(np.float32)

for i in range(3):
    band = rgb[i]
    p2, p98 = np.percentile(band, (2, 98))
    rgb[i] = (band - p2) / (p98 - p2)
rgb = np.clip(rgb, 0, 1)

fig, ax = plt.subplots(figsize=(12, 7))
ax.imshow(rgb.transpose(1, 2, 0))
ax.set_title("Sentinel-2 RGB Composite (10 m)")
ax.set_axis_off()
plt.tight_layout()
plt.show()

Single-Patch Super-Resolution

sr_output = "sr_output.tif"
sr_image, _ = geoai.super_resolution(
    input_lr_path=s2_path,
    output_sr_path=sr_output,
    rgb_nir_bands=[1, 2, 3, 4],
    window=(700, 1300, 128, 128),
    sampling_steps=100,
)
print(f"Input shape:  (4, 128, 128) at 10 m")
print(f"Output shape: {sr_image.shape} at 2.5 m")

Comparing Low-Resolution and Super-Resolution

geoai.plot_sr_comparison(s2_path, sr_output, bands=[1, 2, 3])
plt.show()
with rio.open(sr_output) as src:
    print(f"SR Bands: {src.count}")
    print(f"SR Size: {src.width} x {src.height}")
    print(f"SR CRS: {src.crs}")
    print(f"SR Resolution: {src.res[0]:.2f} m")

Uncertainty Estimation

sr_unc_output = "sr_with_uncertainty.tif"
unc_output = "uncertainty.tif"
sr_image2, uncertainty = geoai.super_resolution(
    input_lr_path=s2_path,
    output_sr_path=sr_unc_output,
    output_uncertainty_path=unc_output,
    rgb_nir_bands=[1, 2, 3, 4],
    window=(700, 1300, 128, 128),
    compute_uncertainty=True,
    n_variations=5,
    sampling_steps=100,
)

Visualizing the Uncertainty Map

geoai.plot_sr_uncertainty(unc_output)
plt.show()

Tiled Inference for Larger Regions

sr_large = "sr_large.tif"
sr_large_img, _ = geoai.super_resolution(
    input_lr_path=s2_path,
    output_sr_path=sr_large,
    rgb_nir_bands=[1, 2, 3, 4],
    window=(700, 1300, 256, 256),
    patch_size=128,
    overlap=16,
    sampling_steps=100,
)
print(f"Input shape:  (4, 256, 256) at 10 m")
print(f"Output shape: {sr_large_img.shape} at 2.5 m")

Comparing Results for the Larger Region

geoai.plot_sr_comparison(s2_path, sr_large, bands=[1, 2, 3])
plt.show()

Interactive Split Map Comparison

geoai.create_split_map(
    left_layer=sr_large, right_layer="Esri.WorldImagery", left_args={"vmax": 0.3}
)

Limitations and Cautions

Key Takeaways

Exercises

Exercise 1: Sampling Steps and Output Quality

Exercise 2: Uncertainty Across Land Cover Types

Exercise 3: Overlap Parameter and Stitching Quality

Exercise 4: Super-Resolution Across Landscape Types

Exercise 5: Validation Against High-Resolution Imagery