colab Open in SageMaker Studio Lab Open in Planetary Computer

Panchromatic Sharpening

Tutorial created by **Aaron Zuspan**: GitHub | Twitter

Let’s start!

If required, please uncomment:

[1]:
# !pip install eemont
# !pip install geemap

Import the required packages.

[2]:
import ee, eemont, geemap

Authenticate and Initialize Earth Engine and geemap.

[3]:
Map = geemap.Map()

Some image platforms capture high resolution panchromatic data that can be used to increase the resolution of multispectral bands. Using eemont, supported ee.Image and ee.ImageCollection platforms can be sharpened using the panSharpen() method.

NOTE: Supported platforms are TOA and raw reflectance products from Landsat 7 and Landsat 8. Unfortunately, surface reflectance products do not contain panchromatic bands and cannot be sharpened.

Sharpening a Landsat Image

Let’s sharpen a single Landsat 8 image. First, we’ll look at the original image at 30m resolution.

[4]:
img = ee.Image("LANDSAT/LC08/C01/T1_TOA/LC08_047027_20160819")
Map.addLayer(img, dict(min=0, max=0.35, bands=["B4", "B3", "B2"]), "Landsat 8 - Original")

pt = ee.Geometry.Point([-122.4100625, 47.2686875])
Map.centerObject(pt, zoom=15)
Map

Now we’ll use the panSharpen() method to increase the resolution of all sharpenable bands, creating a 15m resolution image. By toggling the sharpened image on and off, you can see how detail is added by pan-sharpening.

[5]:
sharp = img.panSharpen()
Map.addLayer(sharp, dict(min=0, max=0.35, bands=["B4", "B3", "B2"]), "Landsat 8 - Sharp")
Map

NOTE: eemont automatically filters out bands that don’t support sharpening such as thermal, bitmasks, and the panchromatic band itself. The panSharpen method leaves only the sharpenable bands in the visible, NIR, and SWIR spectrums.

Sharpening Methods

There are many different algorithms that can be used to pan-sharpen imagery. SFIM (Smoothing Filter-based Intensity Modulation) is the default algorithm in eemont because it produces high quality output images, runs efficiently in GEE, and is tolerant of different band combinations, but users can experiment with other methods—HPFA (high-pass filter addition), SM (simple mean), and PCS (principal component substitution)—by setting the method argument.

HPFA

HPFA is similarly efficient to SFIM but generally produces less realistic sharpening. Try comparing the previous sharpened images (created with SFIM) to images sharpened with HFPA below.

[6]:
sharp = img.panSharpen(method="HPFA")
Map.addLayer(sharp, dict(min=0, max=0.35, bands=["B4", "B3", "B2"]), "Landsat 8 - Sharp HPFA")
Map

SM

SM is very fast, but it generally produces more spectral distortion than SFIM or HPFA due to its simplicity.

[7]:
sharp = img.panSharpen(method="SM")
Map.addLayer(sharp, dict(min=0, max=0.35, bands=["B4", "B3", "B2"]), "Landsat 8 - Sharp SM")
Map

PCS

PCS (sometimes referred to as PCA) is slower than other methods and may produce poor results depending on the image and band combinations. PCS requires calculating image statistics using the ee.Image.reduceRegion method, so additional keyword arguments can be passed through panSharpen. In this case, we’ll pass a maxPixels argument to ensure statistics can be computed throughout the entire image, but we could also pass arguments like geometry, scale, bestEffort, etc.

[8]:
sharp = img.panSharpen(method="PCS", maxPixels=1e13)
Map.addLayer(sharp, dict(min=0, max=0.35, bands=["B4", "B3", "B2"]), "Landsat 8 - Sharp PCS")
Map

Sharpening Image Collections

Sharpening Image Collections is the same as sharpening Images. For example, let’s sharpen a subset of the Landsat 8 collection.

Create a fresh map.

[9]:
Map = geemap.Map()

Add the first image of the unsharpened collection.

[10]:
img_collection = ee.ImageCollection("LANDSAT/LC08/C01/T1_TOA").filterBounds(pt).filterDate("2016", "2017")
Map.addLayer(img_collection.first(), dict(min=0, max=0.35, bands=["B4", "B3", "B2"]), "Landsat 8 Collection - Original")

pt = ee.Geometry.Point([-122.4100625, 47.2686875])
Map.centerObject(pt, zoom=15)
Map

Now we’ll sharpen the whole collection and visualize the first sharpened image.

[11]:
sharp_collection = img_collection.panSharpen()
Map.addLayer(sharp_collection.first(), dict(min=0, max=0.35, bands=["B4", "B3", "B2"]), "Landsat 8 Collection - Sharp")
Map

Quality Assessments

Image quality assessments (QA) measure the amount of spectral distortion caused by pan-sharpening and can help to select the best sharpening method. There are a wide variety of QA metrics for different applications. In eemont, QA metrics are calculated within the panSharpen method by passing a list of names to the qa argument. Results are added as properties to the sharpened image.

Below, we’ll re-sharpen the original image and calculate a variety of QA metrics at the same time. QA metrics calculate image statistics, so additional arguments may be needed that will be passed to ee.Image.reduceRegion. In the example below, we’ll specify maxPixels.

NOTE: By default, QA metrics are calculated throughout the entire image. To speed up calculation or avoid memory issues you can specify a geometry parameter to calculate image statistics within.

[12]:
metrics = ["RASE", "UIQI"]

img = ee.Image("LANDSAT/LC08/C01/T1_TOA/LC08_047027_20160819")
sharp = img.panSharpen(qa=metrics, maxPixels=1e13)

Calculated QA metrics can be retrieved from the sharpened image like any property. The property names always follow the format “eemont:{QA name}”. Below, we see the RASE (Relative Average Spectral Error) value for the image sharpened with the default SFIM method. The ideal value for RASE is 0.

[13]:
sharp.get("eemont:RASE").getInfo()
[13]:
15.153220110202467

Let’s see how RASE compares when using SM sharpening.

[14]:
sharp_sm = img.panSharpen(method="SM", qa=metrics, maxPixels=1e13)
sharp_sm.get("eemont:RASE").getInfo()
[14]:
49.04100968167302

The higher RASE value in the SM image suggests more spectral distortion, so SFIM performed better.

Image-wise and Band-wise QA

RASE is an image-wise QA metric because it returns one value calculated for all bands together. Other QA metrics are band-wise and return one number for each band. Below, we’ll see that the Universal Image Quality Index (UIQI) returns a quality value for each band. The ideal value for UIQI is 1.

[15]:
sharp.get("eemont:UIQI").getInfo()
[15]:
{'B2': 0.9257909067747834,
 'B3': 0.946138969196525,
 'B4': 0.9603165087419183,
 'B5': 0.9835284121260173,
 'B6': 0.978635120940636,
 'B7': 0.9760713865055599}

Let’s see how UIQI compares when using SM sharpening.

[16]:
sharp_sm.get("eemont:UIQI").getInfo()
[16]:
{'B2': 0.9241026160115009,
 'B3': 0.9634693861440802,
 'B4': 0.9608864222114036,
 'B5': 0.7370347291993338,
 'B6': 0.8380615966696616,
 'B7': 0.8808608544580628}

Notice how SM performs similarly to SFIM in the visible spectrum (B2, B3, and B4), but performs much worse in the infrared spectrum (B5, B6, and B7)

Metrics

The list below describes all QA metrics available through eemont.

Name

Full Name

Ideal Value

Axis

MSE

Mean Square Error

0

Band

RMSE

Root-Mean Square Error

0

Band

RASE

Relative Average Spectral Error

0

Image

ERGAS

Dimensionless Global Relative Error of Synthesis

0

Image

DIV

Difference in Variance

0

Band

bias

Bias

0

Band

CC

Correlation Coefficient

1

Band

CML

Change in Mean Luminance

1

Band

CMC

Change in Mean Contrast

1

Band

UIQI

Universal Image Quality Index

1

Band