Image Analysis of Multi-Spectral and Polarimetric SAR Imagery
with Open Source Tools

Mort Canty (mort.canty@gmail.com)

ZFL Bonn, April 2016

Course Outline

  1. Quick tour of the IPython Notebook

  2. Mutlispectral visual/infrared images

    1. Probability distributions

    2. Principal components

    3. Clustering

  3. SAR and polarimetric SAR images

    1. Data acquisition and multilooking

    2. Probability distributions

    3. Speckle filtering

  4. Multispecral change detection and radiometric normalization

  5. Polarimetric SAR change detection

Software and Notebook Installation on Windows

  1. Install the Docker Engine from https://docs.docker.com/

    1. Ensure that hardware virtualization is enabled.

    2. Download DockerToobox from https://www.docker.com/docker-toolboxand
      and install with all defaults. Be sure to accept all Oracle drivers.

  2. In the Docker Quickstart terminal, run the commands
    docker pull mort/zfldocker
    docker pull mort/datadocker
    docker run -d -v /imagery --name=data mort/datadocker
    docker run -d -p 463:8888 --name=zfl --volumes-from=/data mort/zfldocker

  3. Run the command
    docker-machine ip default
    to get the IP address of your virtual machine.

  4. Point your browser to
    http://ip-address:463

  5. Click on the course notebook /home/imagery/ZFL-Course.ipynb,
    or open a new notebook with New/Python 2.

1. IPython Notebook

We are in a Linux environment

OS commands are prefixed with ! (the bang).

The /home directory contains the programs:

In [1]:
!ls -l /home
total 236
-rw-rw-r--  1 root root 16462 Apr  8 17:48 dispms.py
-rw-rw-r--  1 root root 12230 Oct 18  2015 em.py
-rw-rw-r--  1 root root  7749 Oct 18  2015 enlml.py
-rw-rw-r--  1 root root  9370 Mar 24 14:49 gamma_filter.py
-rw-rw-r--  1 root root  8893 Oct 18  2015 imad.py
drwxr-xr-x 10 root root  4096 Apr 20 08:31 imagery
-rw-rw-r--  1 root root  4408 Oct 18  2015 ingest.py
-rw-r--r--  1 root root    91 Apr 20 06:57 jupyter_notebook_config.json
-rwxr-xr-x  1 root root  8072 Jan 29 11:46 libprov_means.so
-rw-r--r--  1 root root  1049 Apr 20 08:23 mapready.cfg
-rw-r--r--  1 root root 38402 Apr 20 08:26 mapready.log
-rwxrw-r--  1 root root  2930 Dec 10 13:44 mapready.sh
-rw-rw-r--  1 root root  9887 Jan 27 14:03 omnibus.py
-rwxrw-r--  1 root root  1188 Dec 10 13:36 omnibus.sh
-rw-rw-r--  1 root root  4164 Dec 20 13:51 pca.py
-rw-rw-r--  1 root root   693 Oct 18  2015 prov_means.c
-rw-rw-r--  1 root root   842 Dec 10 13:47 radarsat2quadpol.template
-rw-rw-r--  1 root root  7499 Oct 18  2015 radcal.py
-rw-rw-r--  1 root root  8680 Nov 20 13:16 register.py
-rw-rw-r--  1 root root  9976 Mar  1 10:19 sar_seq.py
-rwxrw-r--  1 root root  1319 Feb 27 11:42 sar_seq.sh
-rw-rw-r--  1 root root  3584 Feb 21 10:37 subset.py
-rw-rw-r--  1 root root   829 Dec 10 13:48 terrasarxdualpol.template
-rw-rw-r--  1 root root    50 Oct 18  2015 utm.prj
-rw-rw-r--  1 root root 10531 Nov 25 14:53 wishart.py
-rwxrw-r--  1 root root   815 Dec 10 13:36 wishart.sh

The /home/imagery directory contains the image data and this notebook:

In [2]:
!ls -l /home/imagery
total 18804
-rw-rw-r-- 1 root root 6000000 Jul 28  2006 20010525
-rw-rw-r-- 1 root root     870 Jul 28  2006 20010525.hdr
-rw-rw-r-- 1 root root 6000000 Jul 28  2006 20010626
-rw-rw-r-- 1 root root     856 Jul 28  2006 20010626.hdr
-rw-rw-r-- 1 root root 6000000 Jul 28  2006 20010829
-rw-rw-r-- 1 root root     867 Jul 28  2006 20010829.hdr
drwx------ 5 root root    4096 Apr 12 09:57 RS2_OK5491_PK71074_DK68879_FQ21_20100426_172459_HH_VV_HV_VH_SLC
drwxr-xr-x 3 root root    4096 Apr 20 08:17 RS2_OK5491_PK71074_DK68879_FQ21_20100426_172459_HH_VV_HV_VH_SLC_MapReady
-rw-r--r-- 1 root root  364496 Apr 20 08:17 RS2_OK5491_PK71074_DK68879_FQ21_20100426_172459_HH_VV_HV_VH_SLC_MapReady.meta
drwx------ 4 root root    4096 Dec 15 11:21 RS2_OK5491_PK71074_DK68879_FQ21_20100520_172458_HH_VV_HV_VH_SLC
drwxr-xr-x 3 root root    4096 Apr 20 08:22 RS2_OK5491_PK71074_DK68879_FQ21_20100520_172458_HH_VV_HV_VH_SLC_MapReady
-rw-r--r-- 1 root root  364496 Apr 20 08:22 RS2_OK5491_PK71074_DK68879_FQ21_20100520_172458_HH_VV_HV_VH_SLC_MapReady.meta
drwx------ 5 root root    4096 Feb 13 09:24 RS2_OK5491_PK71074_DK68879_FQ21_20100707_172459_HH_VV_HV_VH_SLC
drwxr-xr-x 3 root root    4096 Apr 20 08:25 RS2_OK5491_PK71074_DK68879_FQ21_20100707_172459_HH_VV_HV_VH_SLC_MapReady
-rw-r--r-- 1 root root  364496 Apr 20 08:25 RS2_OK5491_PK71074_DK68879_FQ21_20100707_172459_HH_VV_HV_VH_SLC_MapReady.meta
-rw-rw-r-- 1 root root   29802 Apr 20 07:45 ZFL-Course-Part1.ipynb
-rw-rw-r-- 1 root root   25757 Apr 20 07:26 ZFL-Course-Part2.ipynb
-rw-rw-r-- 1 root root   19354 Apr 18 08:14 ZFL-Course-Part3.ipynb
-rw-rw-r-- 1 root root   30757 Apr 20 08:31 ZFL-Course-Part4.ipynb
drwxr-xr-x 2 root root    4096 Apr 18 08:15 figures
-rw-rw-r-- 1 root root    4058 Apr  1 08:56 pca.ipynb

The /home/imagery/figures directory contains some figures:

In [3]:
!ls -l /home/imagery/figures
total 3908
-rwxrw-r-- 1 root root  604286 Jan  9 13:13 aster3n.png
-rwxrw-r-- 1 root root   31104 Jan  9 13:19 aster3nhist.png
-rwxrw-r-- 1 root root  582991 Jan 10 10:23 histograms.png
-rwxrw-r-- 1 root root  854405 Apr 18 06:38 mad1.png
-rwxrw-r-- 1 root root   77147 Apr 18 06:40 mad2.png
-rwxrw-r-- 1 root root   73599 Feb  4 09:22 sar.png
-rwxrw-r-- 1 root root   76931 Jan  7 16:25 sar_imaging.png
-rwxrw-r-- 1 root root   63464 Feb  4 09:27 sarresolution.png
-rwxrw-r-- 1 root root   42845 Apr 18 07:49 scatterplot1.png
-rwxrw-r-- 1 root root 1446275 Apr 18 07:43 scatterplot2.png
-rwxrw-r-- 1 root root   59777 Feb  4 09:07 slant-range.png
-rwxr--r-- 1 root root   62332 Feb 16 09:08 templates.jpg
-rwx------ 1 root root     236 Jan 12 13:36 windows_install

which can be displayed within a markdown cell:

SAR imaging geometry

We can talk directly to the Python kernel:

In [4]:
import numpy as np
np.random.rand(5,5)
Out[4]:
array([[ 0.22859796,  0.4008518 ,  0.94084169,  0.98984888,  0.61236519],
       [ 0.93994762,  0.28884856,  0.97372978,  0.62104763,  0.99464325],
       [ 0.45968101,  0.1931793 ,  0.73082828,  0.70684095,  0.69412776],
       [ 0.14996059,  0.24817038,  0.36017549,  0.30857059,  0.19340509],
       [ 0.13922626,  0.68844617,  0.132289  ,  0.9980853 ,  0.59696563]])

To enable graphics output, we run an IPython "magic"

In [5]:
%matplotlib inline
In [6]:
import matplotlib.pyplot as plt
x = np.linspace(0,10,100)
plt.plot(x,np.sin(x))
plt.show()

Python programs (scripts) are called with the run command:

In [7]:
run /home/dispms.py -h
Usage: python /home/dispms.py [-h] [-k] [-c classes] [-C Classes] 

            [-l] [-L] [-o alpha] 

            [-e enhancementf] [-E enhancementF]

            [-p posf] [P posF [-d dimsf] [-D dimsF]

            [-f filename1] [-F filename2] 

                                        
            if -f is not specified it will be queried

            use -c classes and/or -C Classes for classification image
 
            use -k to generate a JPEG of filename1 and associated KLM file to overlay on Google Earth
            use -o alpha to overlay right onto left image with transparency alpha
            RGB bandPositions and spatialDimensions are lists, e.g., -p [1,4,3] -d [0,0,400,400] 

            enhancements: 1=linear255 2=linear 3=linear2pc 4=equalization 5=logarithmic

2. Multispectral Visual/Infrared Images

2.1 Scalar (one-band) images

The statistical distributions of optical and SAR measurements are fundamentally different: SAR intensity observations are exponentially distributed, optical/infrared observations are normally distributed.

The normal or Gaussian density function of a random variable $Z$ representing an image pixel is

$$ p(z) = {1\over \sqrt{2\pi}\sigma}\exp\left(-{1\over 2\sigma^2}(z-\mu)^2\right),\quad $$

where $-\infty<\mu<\infty$ and $\sigma^2>0$. The mean value and variance are given by

$$ \langle Z\rangle = \int_{-\infty}^\infty z\cdot p(z) dz = \mu,\quad $$$$ {\rm var}(Z) = \langle(Z-\langle Z\rangle)^2\rangle = \int_{-\infty}^\infty (z-\langle Z\rangle)^2 p(z) dz = \sigma^2.\quad $$

This is commonly abbreviated by writing

$$ Z \sim \mathcal{N}(\mu,\sigma^2).\quad $$

Here is a plot of the normal distribution for $\mu=0$ and $\sigma=1$ (the standard normal distribution)

In [8]:
import scipy.stats as st

z = np.linspace(-5,5,2000)
plt.plot(z,st.norm.pdf(z))
plt.show()

Parameter estimation

Consider a single-band image and a specific land cover category within it. We might choose $m$ pixels $Z_i$, $i=1\dots m$, belonging to that category and use them to estimate the moments of the underlying distribution. That distribution will be determined not only by measurement noise, atmospheric disturbances, etc., but also by the spread in reflectances characterizing the land cover category itself.

We can estimate the mean and variance of the distribution with two sample functions: The sample mean

$$ \bar{Z} = {1\over m}\sum_{i=1}^m Z_i\quad $$

with realizations for actual measurements $z_i$

$$ \bar{z} = {1\over m}\sum_{i=1}^m z_i\quad $$

and the sample variance

$$ S = {1\over m-1}\sum_{i=1}^m(Z_i - \bar Z )^2.\quad $$

with realizations

$$ s = {1\over m-1}\sum_{i=1}^m(z_i - \bar z )^2.\quad $$

These two sample functions are also called unbiased estimators because their average values are equal to the corresponding moments of the distribution, that is,

$$ \langle\bar Z\rangle = \langle Z\rangle\quad ( = \mu ) $$

and

$$ \langle S \rangle = {\rm var}(Z)\quad ( = \sigma^2). $$

Distributions of the sample mean and variance

The sample mean $\bar Z$ is normally distributed with mean $\mu$ and variance $\sigma^2/m$.

$$ p(z) = {1\over \sqrt{2\pi\over m}\sigma}\exp\left(-{1\over 2(\sigma^2/m)}(z-\mu)^2\right),\quad $$

For the sample variance $S$ then

$$ (m-1)S/\sigma^2 \quad $$

is independent of $\bar Z$ and has the chi-square distribution with $m-1$ degrees of freedom.

The gamma distribution and its relatives

A random variable $Z$ is said to have a gamma distribution if its probability density function is given by

$$ p_\gamma(z) = {1\over \beta^\alpha\Gamma(\alpha)}z^{\alpha-1}e^{-z/\beta}, \quad z>0, $$

where $\alpha>0$ and $\beta>0$ and where the gamma function $\Gamma(\alpha)$ is given by

$$ \Gamma(\alpha) = \int_0^\infty z^{\alpha-1} e^{-z}dz,\quad \alpha>0. \quad $$

The gamma function has the recursive property

$$ \Gamma(\alpha) = (\alpha-1)\Gamma(\alpha-1),\quad \alpha>1, \quad $$

and generalizes the notion of a factorial:

$$ \Gamma(n) = (n-1)!\ . $$

The gamma distribution has mean and variance

$$ \langle Z\rangle = \alpha\beta, \quad {\rm var}(Z) = \alpha\beta^2. \quad $$

A special case of the gamma distribution arises for $\alpha = 1$. Since $\Gamma(1) = \int_0^\infty e^{-z}dz = 1$, we obtain the exponential distribution with density function

$$ p_e(z) = \cases{{1\over \beta}e^{-z/\beta} & for $z>0$\cr \quad 0 & elsewhere,} $$

where $\beta >0$. The exponential distribution has mean $\beta$ and variance $\beta^2$. In addition If random variables $Z_1,Z_2\dots Z_m$ are independent and exponentially distributed, then

$$ Z = \sum_{i=1}^m Z_i \quad $$

is gamma distributed with $\alpha = m$.

The chi-square distribution with $m$ degrees of freedom is another special case of the gamma distribution. We get its density function with $\beta = 2$ and $\alpha = m/2$, i.e.,

$$ p_{\chi^2;m}(z)=\cases{{1 \over 2^{m/2}\Gamma(m/2)} z^{(m-2)/2} e^{-z/2} & for $z>0$\cr 0 & otherwise.} \quad $$

It follows that the chi-square distribution has mean $\mu = m$ and variance $\sigma^2 = 2m$.

Here are plots of the chi-square distribution for different degrees of freedom:

In [9]:
z = np.linspace(1,40,200)
for m in [1,2,3,4,5,10,20]:
    plt.plot(z,st.chi2.pdf(z,m))
plt.show()

The gamma and exponential distributions will be essential for the characterization of SAR speckle noise in SAR imagery. The chi-square distribution plays a central role in the iterative change detection algorithm IR-MAD that we will be looking at later:

If the random variables $Z_i$, $i=1\dots m$, are independent and standard normally distributed (i.e., with mean $0$ and variance $1$), then the random variable $Z=\sum_{i=1}^m Z_i^2$ is chi-square distributed with $m$ degrees of freedom.

2.2 Vector (multispectral or polarimetric) images

In [10]:
# vector and matrix multiplication
a = np.mat([[1],[2]])
print 'column vector\n %s' %str(a)
print 'row vector\n %s'    %str(a.T)
print 'inner product\n %s' %str(a.T*a)
print 'outer product\n %s' %str(a*a.T)
b = np.mat([[1,2],[3,4]])
print 'matrix\n %s'              %str(b)
print 'matrix times vector\n %s' %str(b*a)
print 'matrix times matrix\n %s' %str(b*b)
print 'matrix inverse\n %s'      %str(b.I)
print 'identity matrix\n %s'     %str(b*b.I)
print 'singular matrix\n %s'     %str((a*a.T).I)
column vector
 [[1]
 [2]]
row vector
 [[1 2]]
inner product
 [[5]]
outer product
 [[1 2]
 [2 4]]
matrix
 [[1 2]
 [3 4]]
matrix times vector
 [[ 5]
 [11]]
matrix times matrix
 [[ 7 10]
 [15 22]]
matrix inverse
 [[-2.   1. ]
 [ 1.5 -0.5]]
identity matrix
 [[  1.00000000e+00   0.00000000e+00]
 [  8.88178420e-16   1.00000000e+00]]
---------------------------------------------------------------------------
LinAlgError                               Traceback (most recent call last)
<ipython-input-10-8ec3cbc4979e> in <module>()
     11 print 'matrix inverse\n %s'      %str(b.I)
     12 print 'identity matrix\n %s'     %str(b*b.I)
---> 13 print 'singular matrix\n %s'     %str((a*a.T).I)

/usr/lib/python2.7/dist-packages/numpy/matrixlib/defmatrix.pyc in getI(self)
    868         else:
    869             from numpy.dual import pinv as func
--> 870         return asmatrix(func(self))
    871 
    872     def getA(self):

/usr/lib/python2.7/dist-packages/scipy/linalg/basic.pyc in inv(a, overwrite_a, check_finite)
    381         inv_a, info = getri(lu, piv, lwork=lwork, overwrite_lu=1)
    382     if info > 0:
--> 383         raise LinAlgError("singular matrix")
    384     if info < 0:
    385         raise ValueError('illegal value in %d-th argument of internal '

LinAlgError: singular matrix

A measured pixel or observation in an N-band multispectral image corresponds to a random vector

$$ Z = \pmatrix{Z_1\cr \vdots \cr Z_N} \quad $$

i.e., a vector the components of which are random variables.

The covariance of two random variables $Z_1$ and $Z_2$ is a measure of how their realizations are dependent upon each other and is defined as

$$ {\rm cov}(Z_1,Z_2) = \left\langle\ (Z_1-\langle Z_1\rangle)(Z_2-\langle Z_2\rangle)\ \right\rangle.\quad $$

Useful relations

$$ {\rm cov}(Z_1,Z_1) = {\rm var}(Z_1)\\ {\rm cov}(Z_1,Z_2) = \langle Z_1 Z_2\rangle - \langle Z_1\rangle\langle Z_2\rangle $$

The covariance matrix is a convenient way of representing the variances and covariances of the components of a random vector. Let $a = (a_1,a_2)^\top$ be any constant vector. Then the variance of the random variable $ a^\top Z = a_1Z_1+a_2Z_2$ is

$$ {\rm var}(a^\top Z) = {\rm cov}(a_1Z_1+a_2Z_2,a_1Z_1+a_2Z_2) \\ =a_1^2{\rm var}(Z_1)+a_1a_2{\rm cov}(Z_1,Z_2)+a_1a_2{\rm cov}(Z_2,Z_1)+a_2^2{\rm var}(Z_2)\\ =(a_1,a_2) \pmatrix{{\rm var}(Z_1)&{\rm cov}(Z_1,Z_2)\cr{\rm cov}(Z_2,Z_1)&{\rm var}(Z_2)} \pmatrix{a_1\cr a_2} \\ = a^\top\Sigma a. $$

Thus:

$$ {\rm var}(a^\top Z) = a^\top\Sigma a. $$

The random vector $Z$ has a multivariate normal density function when

$$ p(z) = {1\over (2\pi)^{N/2}\sqrt{|\Sigma|}} \exp\left(-{1\over 2}(z-\mu)^\top \Sigma^{-1} (z-\mu)\right), \quad $$

The mean vector is

$$ \langle Z\rangle = \mu \quad $$

and $\Sigma$ is the covariance matrix. This is indicated by writing

$$ Z \sim \mathcal{N}(\mu,\Sigma).\quad $$

Parameter estimation

The vector sample mean is given by

$$ \bar{Z} = {1\over m}\sum_{\nu=1}^m Z(\nu) $$

and the sample covariance matrix by

$$ S = {1\over m-1}\sum_{\nu=1}^m( Z(\nu) - \bar Z ) (Z(\nu) - \bar Z)^\top. $$

If we can arrange that the mean values are zero, then

$$ S = {1\over m-1}\sum_{\nu=1}^m Z(\nu) Z(\nu)^\top. $$

In the limit for large $m$,

$$ \Sigma = \langle Z Z^\top\rangle. $$

Principal components

The principal components transformation, also called principal components analysis (PCA), generates linear combinations of multi-spectral pixel intensities which are mutually uncorrelated and which have maximum variance.

pca.ipynb

Consider a multispectral image represented by the random vector $Z$ ($Z=$ vector of gray-scale values) and assume that $\langle Z\rangle=0$, so that the covariance matrix is given by

$$ \Sigma=\langle Z Z^\top\rangle. $$

Let us seek a linear combination

$$ Y = w^\top Z $$

whose variance

$$ {\rm var}(Y) = w^\top \Sigma w $$

is maximum. This quantity can trivially be made as large as we like by choosing $w$ sufficiently large, so that the maximization only makes sense if we restrict $w$ in some way. A convenient constraint is

$$ w^\top w=1. $$

We can solve this problem by maximizing the Lagrange function

$$ L = w^\top \Sigma w - \lambda(w^\top w - 1). $$

This leads directly to the eigenvalue problem

$$ \Sigma w = \lambda w. $$

This procedure is coded in the python script pca.py.

In [11]:
ls -l /home/imagery
total 18836
-rw-rw-r-- 1 root root 6000000 Jul 28  2006 20010525
-rw-rw-r-- 1 root root     870 Jul 28  2006 20010525.hdr
-rw-rw-r-- 1 root root 6000000 Jul 28  2006 20010626
-rw-rw-r-- 1 root root     856 Jul 28  2006 20010626.hdr
-rw-rw-r-- 1 root root 6000000 Jul 28  2006 20010829
-rw-rw-r-- 1 root root     867 Jul 28  2006 20010829.hdr
drwx------ 5 root root    4096 Apr 12 09:57 RS2_OK5491_PK71074_DK68879_FQ21_20100426_172459_HH_VV_HV_VH_SLC/
drwxr-xr-x 3 root root    4096 Apr 20 08:17 RS2_OK5491_PK71074_DK68879_FQ21_20100426_172459_HH_VV_HV_VH_SLC_MapReady/
-rw-r--r-- 1 root root  364496 Apr 20 08:17 RS2_OK5491_PK71074_DK68879_FQ21_20100426_172459_HH_VV_HV_VH_SLC_MapReady.meta
drwx------ 4 root root    4096 Dec 15 11:21 RS2_OK5491_PK71074_DK68879_FQ21_20100520_172458_HH_VV_HV_VH_SLC/
drwxr-xr-x 3 root root    4096 Apr 20 08:22 RS2_OK5491_PK71074_DK68879_FQ21_20100520_172458_HH_VV_HV_VH_SLC_MapReady/
-rw-r--r-- 1 root root  364496 Apr 20 08:22 RS2_OK5491_PK71074_DK68879_FQ21_20100520_172458_HH_VV_HV_VH_SLC_MapReady.meta
drwx------ 5 root root    4096 Feb 13 09:24 RS2_OK5491_PK71074_DK68879_FQ21_20100707_172459_HH_VV_HV_VH_SLC/
drwxr-xr-x 3 root root    4096 Apr 20 08:25 RS2_OK5491_PK71074_DK68879_FQ21_20100707_172459_HH_VV_HV_VH_SLC_MapReady/
-rw-r--r-- 1 root root  364496 Apr 20 08:25 RS2_OK5491_PK71074_DK68879_FQ21_20100707_172459_HH_VV_HV_VH_SLC_MapReady.meta
-rw-rw-r-- 1 root root   63353 Apr 20 08:33 ZFL-Course-Part1.ipynb
-rw-rw-r-- 1 root root   25757 Apr 20 07:26 ZFL-Course-Part2.ipynb
-rw-rw-r-- 1 root root   19354 Apr 18 08:14 ZFL-Course-Part3.ipynb
-rw-rw-r-- 1 root root   30757 Apr 20 08:31 ZFL-Course-Part4.ipynb
drwxr-xr-x 2 root root    4096 Apr 18 08:15 figures/
-rw-rw-r-- 1 root root    4058 Apr  1 08:56 pca.ipynb
In [12]:
run /home/pca /home/imagery/20010525
------------PCA ---------------
Wed Apr 20 08:34:19 2016
Input /home/imagery/20010525
Eigenvalues: [  6.53264847e+03   3.94881303e+02   1.39378715e+02   3.23104634e+01
   1.48719152e+01   3.02456833e+00]
result written to: /home/imagery/20010525_pca
elapsed time: 0.610431909561
In [13]:
run /home/dispms -f /home/imagery/20010525_pca -p [1,2,3] -e 3

Denote the orthogonal and normalized eigenvectors of $\Sigma$ obtained by solving the above problem by $w_1\dots w_N$, sorted according to decreasing eigenvalue $\lambda_1\ge \dots\ge\lambda_N$. These eigenvectors are the principal axes and the corresponding linear combinations $w_i^\top Z$ are projections along the principal axes, called the principal components of $Z$. The individual principal components

$$ Y_1 = w_1^\top Z,\ Y_2= w_2^\top Z,\ \dots,\ Y_N= w_N^\top Z $$

can be expressed more compactly as a random vector $Y$ by writing

$$ Y = W^\top Z, $$

where $W$ is the matrix whose columns comprise the eigenvectors, that is,

$$ W = (w_1\dots w_N). $$

Since the eigenvectors are orthogonal and normalized, $W$ is an orthonormal matrix:

$$ W^\top W= I. $$

If the covariance matrix of the principal components vector $ Y$ is called $\Sigma'$, then we have

$$ \Sigma' = \langle Y Y^\top \rangle= \langle W^\top Z Z^\top W\rangle = W^\top\Sigma W $$

or, since $\Sigma w_i = \lambda_i w_i$,

$$ \Sigma'= W^\top \Sigma W = \pmatrix{\lambda_1 & 0 & \cdots &0\cr 0 &\lambda_2& \cdots&0\cr \vdots&\vdots&\ddots&\vdots\cr 0 & 0& \cdots&\lambda_N} $$

The eigenvalues are thus seen to be the variances of the principal components, and all of the covariances are zero. The first principal component $Y_1$ has maximum variance ${\rm var}(Y_1)=\lambda_1$, the second principal component $Y_2$ has maximum variance ${\rm var}(Y_2)=\lambda_2$ subject to the condition that it is uncorrelated with $Y_1$, and so on. The fraction of the total variance in the original multispectral image which is accounted for by the first $i$ principal components is $$ {\lambda_1+\dots +\lambda_i\over\lambda_1+\dots +\lambda_i+\dots +\lambda_N}. $$

Let's look at the first and last principal components of the image above:

In [14]:
run /home/dispms -f /home/imagery/20010525_pca -p [1,1,1] -e 4 -F /home/imagery/20010525_pca -P [6,6,6] -E 4

Distribution of sample mean vector and sample covariance matrix

In the multivariate case we have a similar situation to the univariate case. The sample mean vector

$$ \bar Z = {1\over m}\sum_{\nu=1}^m Z(\nu) $$

is multivariate normally distributed with mean $\mu$ and covariance matrix $\Sigma/m$ for samples

$$ Z(\nu)\sim\mathcal{N}(\mu,\Sigma),\quad \nu = 1\dots m. $$

Suppose

$$ Z(\nu)\sim\mathcal{N}(0,\Sigma),\quad\nu=1\dots m. $$

Then the sample covariance matrix

$$ S = {1\over m-1}\sum_{\nu=1}^m Z(\nu) Z(\nu)^\top $$

is described by a Wishart distribution:

Define

$$ X = (m-1)S = \sum_{\nu=1}^m Z(\nu) Z(\nu)^\top. $$

The probability density function of $X$ is the Wishart density with $m$ degrees of freedom:

$$ p_W(x) ={|x|^{(m-N-1)/2}\exp(-{\rm tr}(\Sigma^{-1} x)/2) \over 2^{Nm/2}\pi^{N(N-1)/4}|\Sigma|^{m/2}\prod_{i=1}^N\Gamma[(m+1-i)/2]} $$

for $x$ positive definite, and $0$ otherwise.

We write

$$ X \sim \mathcal{W}(\Sigma,N,m). $$

Since the gamma function $\Gamma(\alpha)$, is not defined for $\alpha\le 0$, the Wishart distribution is undefined for $m

We don't need the Wishart distribution here, but later when we talk about SAR change detection, we will need its analog for complex multinormal random variables representing polarimetric data:

$$ X = \sum_{\nu=1}^m Z(\nu) Z(\nu)^+, $$

The probability density function of $X$ is the complex Wishart density with $m$ degrees of freedom:

$$ p_{W_c}( x) ={|x|^{(m-N)}\exp(-{\rm tr}(\Sigma^{-1}x)) \over \pi^{N(N-1)/2}|\Sigma|^{m}\prod_{i=1}^N\Gamma(m+1-i)}. $$

This is denoted

$$ X\sim \mathcal{W}_C(\Sigma,N,m). $$

Clustering or unsupervised classification

We represent the observed pixels in a multispectral image by the set

$$ \{z(\nu) \mid \nu = 1\dots m\}. $$

A given partitioning or clustering may be written in the form

$$ C=[C_1,\dots C_k,\dots C_K], $$

where

$$ C_k = \{\ \nu\mid z(\nu)\hbox{ is in class } k \}. $$

Let $u_{k\nu}$ be the probability that pixel $\nu$ is class $C_k$ given its observed value $z(\nu)$

$$ u_{k\nu} = {\rm Pr}(k \mid z(\nu)) $$

This is called the posterior probability and can be written, from Bayes' Rule, as

$$ u_{k\nu} = {p(z(\nu)\mid k){\rm Pr}(k)\over p(z(\nu))} $$

${\rm Pr}(k)$ is called the prior probability for class $C_k$.

Now assume that the pixels in each class are (approximately) multivariate normally distributed with mean $\mu_k$ and covariance matrix $\Sigma_k$. Then

$$ u_{k\nu} = {1\over \sqrt{|\Sigma_k|}}\exp\left[-{1\over 2}(z(\nu)-\mu_k)^\top\Sigma_k^{-1} (z(\nu)-\mu_k)\right]p_k\quad (1) $$

apart from a normalization constant. In the above expression the prior probability ${\rm Pr}(k)$ has been replaced by

$$ p_k = {m_k\over m} = {1\over m}\sum_{\nu=1}^m u_{k\nu}. \quad (2) $$

To complete the picture we still need expressions for $\mu_k$ and $\Sigma_k$.

$$ \mu_k = {1\over m_k}\sum_{\nu\in C_k}z(\nu) = {\sum_{\nu=1}^m u_{k\nu}z(\nu) \over \sum_{\nu=1}^m u_{k\nu}},\quad k=1\dots K, \quad (3) $$$$ \Sigma_k= {\sum_{\nu=1}^m u_{k\nu}(z(\nu)-\mu_k) (z(\nu)-\mu_k)^\top \over \sum_{\nu=1}^m u_{k\nu}},\quad k=1\dots K.\quad (4) $$

Algorithm (Expectation maximization clustering)

  1. Choose random values for the initial class memberships $u_{k\nu}$ with $\sum_{k=1}^K u_{k\nu}=1$

  2. Determine the cluster means $\mu_k$ with Equation (3) , then the covariance matrices $\Sigma_k$ for each cluster with Equation (4) and the priors $p_k$ with Equation (2)

  3. Calculate the new class membership probabilities $u_{k\nu}$ with Equation (1), and normalize to ensure that $\sum_{k=1}^K u_{k\nu}=1$

  4. If the $u_{k\nu}$ values have stopped changing significantly, stop, else go to step 2.

In [15]:
run /home/em -h
Usage: 
---------------------------------------------------------
python /home/em.py  [-p "bandPositions"] [-d "spatialDimensions"] 
[-K number of clusters] [-M max scale][-m min scale] 
[-t initial annealing temperature] [-s spatial mixing factor] 
[-P generate class probabilities image] filename

bandPositions and spatialDimensions are lists, 
e.g., -p [1,2,4] -d [0,0,400,400]  

If the input file is named 

         path/filenbasename.ext then

The output classification file is named 

         path/filebasename_em.ext

and the class probabilities output file is named

         path/filebasename_emprobs.ext
--------------------------------------------------------
In [16]:
run /home/em -p [1,2,3,4] -K 8 /home/imagery/20010525_pca
--------------------------
     EM clustering
--------------------------
infile:   /home/imagery/20010525_pca
clusters: 8
T0:       0.500000
beta:     0.500000
running EM on 62500 pixel vectors
em iteration 0: dU: 0.992984 loglike: -142410.835111
em iteration 10: dU: 0.935398 loglike: -79530.583980
em iteration 20: dU: 0.844900 loglike: -38381.971290
em iteration 30: dU: 0.551324 loglike: -34653.735612
em iteration 40: dU: 0.290184 loglike: -34529.088433
em iteration 50: dU: 0.153881 loglike: -32662.695967
em iteration 60: dU: 0.350878 loglike: -31429.538092
em iteration 70: dU: 0.091716 loglike: -28967.734363
em iteration 80: dU: 0.156492 loglike: -27767.837900
em iteration 90: dU: 0.157177 loglike: -25611.145438
em iteration 100: dU: 0.125021 loglike: -24820.400279
em iteration 110: dU: 0.207828 loglike: -23860.847494
em iteration 120: dU: 0.155873 loglike: -23410.107456
em iteration 130: dU: 0.089448 loglike: -23493.911966
em iteration 140: dU: 0.028604 loglike: -23665.458450
em iteration 150: dU: 0.009413 loglike: -23749.608202
em iteration 160: dU: 0.003550 loglike: -23784.394462
em iteration 170: dU: 0.001808 loglike: -23798.858433
em iteration 180: dU: 0.000956 loglike: -23805.062674
running EM on 250000 pixel vectors
em iteration 0: dU: 1.000000 loglike: -331527.563610
em iteration 10: dU: 0.012005 loglike: -96562.036722
running EM on 1000000 pixel vectors
em iteration 0: dU: 1.000000 loglike: -1109216.140283
em iteration 10: dU: 0.012697 loglike: -398172.415624
Cluster mean vectors
[[  74.62103944   -7.13074104    5.95243734    4.1241047 ]
 [  69.63007513   -3.07729088   -6.39276865   -1.33247847]
 [  25.86179724   24.13626081    0.46857979   -3.34867348]
 [-112.33759844    0.36225928    1.96702612    4.47247014]
 [ -12.35265105   -2.1842578     2.37854111    3.48808485]
 [  30.87613618  -13.38386552   -4.62034986   -3.7897894 ]
 [ -36.66369901   -0.55262567    1.0924829    -1.51920786]
 [ -92.88117483   16.04333895   -1.96074082   -7.58076503]]
Cluster covariance matrices
cluster: 0
[[ 325.97612386  -12.60123945   12.73977697   13.29576468]
 [ -12.60123945   86.28126396   -7.5366536    -4.39633984]
 [  12.73977697   -7.5366536    20.15372221   -0.92142708]
 [  13.29576468   -4.39633984   -0.92142708    4.7804443 ]]
cluster: 1
[[ 241.91408291  278.97051051   48.43583299   30.13495372]
 [ 278.97051051  603.43679398   77.83267201   37.28282861]
 [  48.43583299   77.83267201   35.50930664    8.65912605]
 [  30.13495372   37.28282861    8.65912605    7.25471729]]
cluster: 2
[[ 395.71735854  -22.72910398   -1.13465277   -1.02362516]
 [ -22.72910398  231.05266693   48.98113715   13.50884401]
 [  -1.13465277   48.98113715   66.20276219   -7.65245324]
 [  -1.02362516   13.50884401   -7.65245324   10.03011669]]
cluster: 3
[[ 1727.94608675   360.57358295  -125.90264488    21.35230116]
 [  360.57358295   141.41727142   -43.49752236    14.64391528]
 [ -125.90264488   -43.49752236    59.8294093    -14.70966272]
 [   21.35230116    14.64391528   -14.70966272     9.08414009]]
cluster: 4
[[  3.31947680e+03  -7.39876566e+01   2.65961713e+02  -3.71068877e+01]
 [ -7.39876566e+01   6.67005769e+01   3.19635063e-01  -4.77632814e-01]
 [  2.65961713e+02   3.19635063e-01   1.00170683e+02  -1.50370400e+01]
 [ -3.71068877e+01  -4.77632814e-01  -1.50370400e+01   1.08749886e+01]]
cluster: 5
[[  1.12557722e+03  -1.02054732e+02   1.69798184e+02   8.54727087e+01]
 [ -1.02054732e+02   2.56959405e+02   3.59332164e-01   4.05944583e-02]
 [  1.69798184e+02   3.59332164e-01   1.01080253e+02   2.82868291e+01]
 [  8.54727087e+01   4.05944583e-02   2.82868291e+01   2.27027029e+01]]
cluster: 6
[[  2.76663559e+03   1.73591160e+02   3.18862616e+01  -3.21478774e+01]
 [  1.73591160e+02   2.07528336e+02  -2.08674572e+00   1.59476112e+00]
 [  3.18862616e+01  -2.08674572e+00   1.42155771e+02  -1.31801277e+01]
 [ -3.21478774e+01   1.59476112e+00  -1.31801277e+01   2.16188889e+01]]
cluster: 7
[[ 6977.47049104  2005.69853604   -43.8231953    204.72093461]
 [ 2005.69853604   731.86906189  -157.5324903     90.59405459]
 [  -43.8231953   -157.5324903    872.75082374  -170.44516029]
 [  204.72093461    90.59405459  -170.44516029    76.30049212]]
classified image written to: /home/imagery/20010525_pca_em
elapsed time: 191.066297054
--done------------------------
In [17]:
run /home/dispms -c [1,2,3,4,5,6,7,8] -f /home/imagery/20010525_pca_em -e 2
In [ ]: