Multispectral Image Analysis in a Docker Container: Examples (continued)

Starting the Container

To recap:

sudo docker run -d -p 433:8888 -v yourImageFolder:/crc/imagery --name=crc mort/crcdocker

then point your browser to

http:\localhost:433

Note: If you are running Docker on Linux in VMWare Player on a Windows host in NAT mode, run the browser in the VM as well. If you are in Bridged mode and in a LAN, you can connect to the IPython kernel from your Windows browser by finding the address of the VM (for example in your Router status) and replacing localhost with that address.

Example 3: Solar Illumination Correction in Rough Terrain

Topographic modeling can be used to correct images for the effects of local solar illumination. The local illumination depends not only upon the sun's position (elevation and azimuth) but also upon the slope and aspect of the terrain being illuminated. The Figure below shows the angles involved.

Figure 1 Angles involved in computation of local solar incidence: \(\theta_z=\) solar zenith angle, \(\phi_a=\) solar azimuth, \(\theta_p=\) slope, \(\phi_o=\) aspect, \(\gamma_i=\) local solar incidence angle.

The quantity to be determined is the local solar incidence angle \(\gamma_i\), which determines the local irradiance. From trigonometry we can calculate the relation \[ \cos\gamma_i = \cos\theta_p\cos\theta_z + \sin\theta_p\sin\theta_z\cos(\phi_a-\phi_o). \] For a Lambertian surface, the reflected radiance \(L_H\) from a horizontal surface toward a sensor (ignoring all atmospheric effects) is given by \[ L_H = E\cdot\cos\theta_z\cdot R. \] For a surface in rough terrain the reflected radiance \(L_T\) is similarly \[ L_T = E\cdot\cos\gamma_i\cdot R, \] thus giving the standard cosine correction relating the observed radiance \(L_T\) to that which would have been observed had the terrain been flat, namely \[ L_H = L_T{\cos\theta_z\over\cos\gamma_i}. \] The Lambertian assumption is in general a poor approximation, the actual reflectance being governed by a bidirectional reflectance distribution function (BRDF), which describes the dependence of reflectance on both illumination and viewing angles as well as on wavelength. Particularly for the large range of incident angles involved with rough terrain, the cosine correction will over- or underestimate the extremes and lead to unwanted artifacts in the corrected imagery.

An example of an approach which takes better account of BRDF effects is the semiempirical cosine correction (C-correction) method. We replace Equations above for \(L_H\) and \(L_T\) by \[ L_H = m\cdot \cos\theta_z + b, \quad L_T = m\cdot \cos\gamma_i + b. \] The empirical parameters \(m\) and \(b\) can be estimated from a linear regression of observed radiance \(L_T\) vs.
\(\cos\gamma_i\) for a particular image band. Then, we can write \[ L_H = L_T\left({\cos\theta_z + b/m\over \cos\gamma_i + b/m}\right) \] as a correction formula.

The main difficulty with this method is estimating the slope \(m\) and intercept \(b\) reliably since the natural spread in ground reflectance will tend to mask any correlation with local solar incidence angle. The approach adopted here is to precede the calculation with an unsupervised segmentation of the image into a small number of land-cover classes and then to estimate the regression coefficients separately for each class and each spectral band. Only if the correlation exceeds a threshold (0.2) are the image pixels corrected. Here is the bash script which controls the correction process:

In [2]:
cat /crc/c-correction.sh
#!/bin/sh
#
# C-correction of a multi-spectral image
# Uses masks generated by Gaussian mixture clustering on first 3+ PCs
#
# Usage:
#
#  ./c-correction spatialDims bandPos numClasses solarAzimuth solarElevation msImage demImage
echo 
echo "=================================================="
echo "                  C-Correction"
echo "=================================================="
echo MS image: $6
echo DEM image: $7
echo spatial subset: $1
echo spectral subset: $2
echo number of classes: $3
echo solar azimuth $4:
echo solar elevation $5:
imagePixelSize=$(gdalinfo $6 | grep Pixel | awk '{print $4}')
demPixelSize=$(gdalinfo $7 | grep Pixel | awk '{print $4}')  
echo Image pixel size: $imagePixelSize
echo DEM pixel size: $demPixelSize	   
echo 'PCA... '
pcaImage=$(python /crc/pca.py -n -d $1 -p $2 $6 | tee /dev/tty \
	   | grep written \
	   | awk '{print $4}')
dims=$(echo $1 | sed -e 's/\[[0-9]*\,[0-9]*/[0,0/')
echo 'Gaussian clustering...'
classImage=$(python /crc/em.py -d $dims -p [1,2,3] -K $3 $pcaImage | tee /dev/tty \
	   | grep written \
	   | awk '{print $5}')
echo   Slope and aspect...
python /crc/c_corr.py -d $1 -p $2 -c $classImage $4 $5 $6 $7 | tee /dev/tty \
	   | grep written \
	   | awk '{print $5}'

A selected spatial/spectral subset of the image to be corrected is first of all subjected to a principal components analysis (with the Python script pca.py). Then the first three principal components are passed to the Gaussian mixture clustering script em.py. The resulting class image is then fed to the c-correction program proper (c_corr.py) along with the original image and the DEM. The class labels then act as masks, with the c-correction being applied to each class separately. We'll try it out here with a Landsat 5 TM image acquired over the southeastern part of Vancouver Island, Canada, in July, 1984. The footprint of the spatial subset chosen is shown below.

Figure 2 Footprint of the Landsat 5 TM spatial subset projected onto Google Earth.

Here is an RGB composite of bands 4,5 and 7:

In [16]:
run dispms -f imagery/19840717 -p [4,5,7] -d [3154,3122,2000,2000]

We choose three land-use classes and the non-thermal bands 1,2,3,4,5 and 7 and run the bash script:

In [22]:
!./c-correction.sh [3154,3122,2000,2000] [1,2,3,4,5,7] 3 132.9 54.9 imagery/19840717 imagery/dem_utm

==================================================
                  C-Correction
==================================================
MS image: imagery/19840717
DEM image: imagery/dem_utm
spatial subset: [3154,3122,2000,2000]
spectral subset: [1,2,3,4,5,7]
number of classes: 3
solar azimuth 132.9:
solar elevation 54.9:
Image pixel size: (30.000000000000000,-30.000000000000000)
DEM pixel size: (30.000000000000000,-30.000000000000000)
PCA... 
------------PCA ---------------
Sun Dec 28 10:25:27 2014
Input imagery/19840717
Eigenvalues: [ 1426.12855333   412.87315573    81.60087543    23.07517111     3.221497
     2.37265254]
result written to: imagery/19840717_pca
elapsed time: 4.49293804169
Gaussian clustering...
--------------------------
     EM clustering
--------------------------
infile:   imagery/19840717_pca
clusters: 3
T0:       0.500000
beta:     0.500000
running EM on 250000 pixel vectors
em iteration 0: dU: 0.968381 loglike: -317761.215701
em iteration 10: dU: 0.979458 loglike: -52706.146290
em iteration 20: dU: 0.970466 loglike: -44540.810575
em iteration 30: dU: 0.622085 loglike: -36642.219796
em iteration 40: dU: 0.578088 loglike: -35964.101198
em iteration 50: dU: 0.400728 loglike: -35917.997154
em iteration 60: dU: 0.004074 loglike: -35911.841680
running EM on 1000000 pixel vectors
em iteration 0: dU: 1.000000 loglike: -473921.620709
running EM on 4000000 pixel vectors
em iteration 0: dU: 1.000000 loglike: -1325589.745199
Cluster mean vectors
[[  4.76964538  -9.24774449   0.89495111]
 [ 71.50856999  17.94637299  -9.00700516]
 [-33.98644453  16.19077584   0.74535069]]
Cluster covariance matrices
cluster: 0
[[ 588.88250169  208.71086183   44.45332966]
 [ 208.71086183  134.12569284   21.28015402]
 [  44.45332966   21.28015402   10.0614119 ]]
cluster: 1
[[ 336.49047673   -1.65772365  400.43764968]
 [  -1.65772365    7.74971839  -14.77840234]
 [ 400.43764968  -14.77840234  608.54796635]]
cluster: 2
[[ 909.32302197 -246.84302685  -12.31996572]
 [-246.84302685  631.45694981   13.3175615 ]
 [ -12.31996572   13.3175615    53.49847616]]
classified image written to: imagery/19840717_pca_em
elapsed time: 144.550230026
--done------------------------
Slope and aspect...
0...10...20...30...40...50...60...70...80...90...100 - done.
0...10...20...30...40...50...60...70...80...90...100 - done.
--------------------------------
        Register
---------------------------------
Sun Dec 28 10:28:10 2014
reference image: imagery/nir_band
warp image: imagery/cosgamma
warp band: 1
Warped image written to: imagery/cosgamma_warp
elapsed time: 11.8079419136
-------------------------
   C-Correction
-------------------------
Sun Dec 28 10:28:03 2014
MS  file: imagery/19840717
DEM file: imagery/dem_utm
Class file: imagery/19840717_pca_em
Band: 1 Class: 1 Pixels: 2633217 Slope: 7.185784 Intercept: 7.736593 Correlation: 0.335773
---correcting band 1, class 1
Band: 1 Class: 2 Pixels: 354937 Slope: -1.033239 Intercept: 6.412909 Correlation: -0.062183
Band: 1 Class: 3 Pixels: 1011846 Slope: 19.629053 Intercept: 17.854027 Correlation: 0.214334
---correcting band 1, class 3
Band: 2 Class: 1 Pixels: 2633217 Slope: 7.974967 Intercept: 122.806923 Correlation: 0.316422
---correcting band 2, class 1
Band: 2 Class: 2 Pixels: 354937 Slope: 5.071754 Intercept: 108.679368 Correlation: 0.094166
Band: 2 Class: 3 Pixels: 1011846 Slope: 18.996278 Intercept: 124.906750 Correlation: 0.295822
---correcting band 2, class 3
Band: 3 Class: 1 Pixels: 2633217 Slope: 28.488449 Intercept: 19.128719 Correlation: 0.429172
---correcting band 3, class 1
Band: 3 Class: 2 Pixels: 354937 Slope: -2.925635 Intercept: 11.133530 Correlation: -0.074016
Band: 3 Class: 3 Pixels: 1011846 Slope: 49.712085 Intercept: 41.306313 Correlation: 0.293475
---correcting band 3, class 3
Band: 4 Class: 1 Pixels: 2633217 Slope: 56.666179 Intercept: 34.859007 Correlation: 0.423105
---correcting band 4, class 1
Band: 4 Class: 2 Pixels: 354937 Slope: -12.126413 Intercept: 22.827258 Correlation: -0.107649
Band: 4 Class: 3 Pixels: 1011846 Slope: 57.151964 Intercept: 40.168240 Correlation: 0.380918
---correcting band 4, class 3
Band: 5 Class: 1 Pixels: 2633217 Slope: 5.147677 Intercept: 13.932032 Correlation: 0.393374
---correcting band 5, class 1
Band: 5 Class: 2 Pixels: 354937 Slope: -11.521794 Intercept: 25.880527 Correlation: -0.104113
Band: 5 Class: 3 Pixels: 1011846 Slope: 10.758103 Intercept: 20.879912 Correlation: 0.189387
Band: 7 Class: 1 Pixels: 2633217 Slope: 6.386597 Intercept: 56.343782 Correlation: 0.375037
---correcting band 7, class 1
Band: 7 Class: 2 Pixels: 354937 Slope: -18.213335 Intercept: 83.069879 Correlation: -0.120214
Band: 7 Class: 3 Pixels: 1011846 Slope: 11.527516 Intercept: 63.799112 Correlation: 0.178255
c-corrected image written to: imagery/19840717_corr
elapsed time: 25.1973931789
imagery/cosgamma_warp
imagery/19840717_corr

Examining the above output we see that pixel intensities in class 2 always have a very low correlation with the local incidence angle so that no correction is applied. For bands 1 through 4, classes 1 and 3 are corrected, whereas for bands 5 and 7 only class 1 pixels exhibit a strong enough correlation to warrant the c-correction. In fact class 2 corresponds to low-lying areas and water surfaces as can be seen here in a linear stretch of the class image (class 1 = black, class 2 = gray, class 3 = white, the \(\cos(\gamma_i)\) image is shown for camparison on the right).

In [4]:
run dispms -f imagery/19840717_pca_em -F imagery/COSGAMMA -e 2 -E 4

The effect of the illumination correction can be seen clearly in band 4, first for the full subset:

In [5]:
run dispms -f imagery/19840717_corr -p [4,4,4] -e 3 -F imagery/19840717 -D [3154,3122,2000,2000] -P [4,4,4]

And for a \(1000\times 1000\) subset at the lower left:

In [6]:
run dispms -f imagery/19840717_corr -p [4,4,4] -d [0,800,1000,1000] -e 3 -F imagery/19840717 -D [3154,3922,1000,1000] -P [4,4,4]
In []: