Panchromatic Sharpening
Tutorial created by **Aaron Zuspan**: GitHub | Twitter
GitHub Repo: https://github.com/davemlz/eemont
PyPI link: https://pypi.org/project/eemont/
Conda-forge: https://anaconda.org/conda-forge/eemont
Documentation: https://eemont.readthedocs.io/
More tutorials: https://github.com/davemlz/eemont/tree/master/docs/tutorials
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 |