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.

Speckle Statistics

This notebook will provide an empirical demonstration of speckle - how it originates, how it visually and statistically looks like, and some of the most common approaches to filter it.

Speckle is defined as a kind of noise that affects all radar images. Given the multiple scattering contributions originating from the various elementary objects present within a resolution cell, the resulting backscatter signal can be described as a random constructive and destructive interference of wavelets. As a consequence, speckle is the reason why a granular pattern normally affects SAR images, making it more challenging to interpret and analyze them.

Credits: ESRI

WARNING:param.Parameterized: Use method 'warning' via param namespace 
WARNING:param.main: pandas could not register all extension types imports failed with the following error: cannot import name 'ABCIndexClass' from 'pandas.core.dtypes.generic' (/home/runner/micromamba/envs/eo-datascience-cookbook/lib/python3.13/site-packages/pandas/core/dtypes/generic.py)
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
WARNING:param.Dimension: Use method 'get_param_values' via param namespace 
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
Cell In[1], line 4
      1 import json
      2 from functools import partial
      3 
----> 4 import holoviews as hv
      5 import intake
      6 import matplotlib.pyplot as plt
      7 import numpy as np

File ~/micromamba/envs/eo-datascience-cookbook/lib/python3.13/site-packages/holoviews/__init__.py:12
      6 import param
      9 __version__ = str(param.version.Version(fpath=__file__, archive_commit="$Format:%h$",
     10                                         reponame="holoviews"))
---> 12 from . import util # noqa (API import)
     13 from .core import archive, config                        # noqa (API import)
     14 from .core.boundingregion import BoundingBox             # noqa (API import)

File ~/micromamba/envs/eo-datascience-cookbook/lib/python3.13/site-packages/holoviews/util/__init__.py:14
     11 import param
     12 from pyviz_comms import extension as _pyviz_extension
---> 14 from ..core import DynamicMap, HoloMap, Dimensioned, ViewableElement, StoreOptions, Store
     15 from ..core.options import options_policy, Keywords, Options
     16 from ..core.operation import Operation

File ~/micromamba/envs/eo-datascience-cookbook/lib/python3.13/site-packages/holoviews/core/__init__.py:4
      1 from datetime import date, datetime
      3 from .boundingregion import *  # noqa (API import)
----> 4 from .data import *            # noqa (API import)
      5 from .dimension import *       # noqa (API import)
      6 from .element import *         # noqa (API import)

File ~/micromamba/envs/eo-datascience-cookbook/lib/python3.13/site-packages/holoviews/core/data/__init__.py:20
     18 from .array import ArrayInterface
     19 from .dictionary import DictInterface
---> 20 from .grid import GridInterface
     21 from .multipath import MultiInterface         # noqa (API import)
     22 from .image import ImageInterface             # noqa (API import)

File ~/micromamba/envs/eo-datascience-cookbook/lib/python3.13/site-packages/holoviews/core/data/grid.py:5
      3 import sys
      4 import datetime as dt
----> 5 from collections import OrderedDict, defaultdict, Iterable
      7 try:
      8     import itertools.izip as zip

ImportError: cannot import name 'Iterable' from 'collections' (/home/runner/micromamba/envs/eo-datascience-cookbook/lib/python3.13/collections/__init__.py)

Let’s make an example of a cornfield (with a typical backscattering value of about -10 dB). According to the following equation:

σ0=1area∑n∈areaσn\sigma^0 = \frac{1}{\text{area}} \sum_{n \in \text{area}} \sigma_n

We should ideally have a uniform discrete sigma naught σ0\sigma^0 value, given that the cornfield pixel is the only individual contributor.

However, since we already learned from the previous notebooks that a pixel’s ground size can be in the order of tens of meters (i.e., 10 meters for Sentinel-1), we can imagine that different distributed targets in the scene contribute to the global backscattered information.

Let´s replicate this behavior with an ideal uniform area constituted by 100 pixels and then by adding 30% of speckle.

Figure 1: Synthetic data that emulates speckles in microwave backscattering

We can imagine that the second plot represents a real SAR acquisition over a cornfield, while the first plot represents an ideal uniform SAR image over a cornfield land (no speckle). The introduction of a simulated 30% speckle noise could be related to the presence of distributed scatterers of any sort present in the scene, which would cause a pixel-to-pixel variation in terms of intensity.

All the random contributions (such as the wind) would result in a different speckle pattern each time a SAR scene is acquired over the same area. Many subpixel contributors build up a complex scattered pattern in any SAR image, making it erroneous to rely on a single pixel intensity for making reliable image analysis. In order to enhance the degree of usability of a SAR image, several techniques have been put in place to mitigate speckle. We will now show two of the most common approaches: the temporal and the spatial filter.

Lake Neusiedl data

We load a dataset that contains the CORINE land cover and Sentinel-1 σE0\sigma^0_E at a 20 meter resolution. This is the same data presented in notebook 6.

We also create the same dashboard for backscatter of different landcover types over time. In order to make this code reusable and adaptable we will define the following function plot_variability, which allows the injection of a spatial and/or temporal filter. It is not important to understand all the code of the following cell!

Now, lets work on the real-life dataset to see how speckle actually looks like.

Figure 2: Lake Neusiedl σE0\sigma^0_E without any filter.

The speckle noise typically appears as a “salt-and-pepper” pattern. Also, please note the distribution of backscatter for each land cover. Even though speckle is known for following non-normal distributions (i.e., Rayleigh distribution for amplitude in the linear domain, and the Gumple for intensity in the log domain), we can assume that due to the Central Limit Theorem, the overall backscatter means (dB) tend to follow a Gaussian distribution.

We can mitigate speckle (it is impossible to remove it completely) by following approaches such as:

  • spatial filtering - taking mean backscatter value over the same land cover, or

  • temporal filtering - taking the average backscatter value over some time period.

Either way, one pixel is never representative of ground truth! Therefore we need to look at samples and distributions.

Spatial filtering

We first introduce a common spatial filter. The Lee filter is an adaptive speckle filter. The filter works using a kernel window with a configurable size, which refers to the dimensions of the neighborhood over which the filter operates. The kernel slides across the data, applying the smoothing operation at each pixel position of the image. It follows three assumptions:

  1. SAR speckle is modeled as a multiplicative noise - the brighter the area the noisier the data.

  2. The noise and the signal are statistically independent of each other.

  3. The sample mean and sample variance of a pixel is equal to its local mean and local variance.

This approach comes with some limitations: it reduces the spatial resolution of the SAR image.

Let’s build up a function for applying a Lee filter with a kernel window size of 7 (do not forget to switch back to linear units before doing this computation and to dB after it):

Figure 3: Lake Neusiedl σE0\sigma^0_E with a Lee filter applied.

Temporal filtering

Temporal filtering would involve taking the average of all previous (past) observations for each pixel. This approach comes with some limitations: it takes out the content-rich information tied to the temporal variability of backscatter.

Figure 4: Lake Neusiedl σE0\sigma^0_E with a temporal filter applied.

Let´s observe the histograms of the two plots. Especially in the region around the lake, it is clear that the distribution is now less dispersed and more centered around a central value.