How to Implement Sunglint Detection for Sentinel 2 Images in Python using Metadata Info  | Towards Data Science

Optical Remote Sensing analysis depends on understanding the processes of absorption and scattering of solar radiance on ground objects. If we measure the solar incidence radiance and the surface’s irradiance, we will be able to estimate surface’s reflectance. Reflectance in various wavelengths is the key to understand the target we are observing, as each material will reflect and absorb energy differently depending on the considered wavelength. Figure 1 shows the mean reflectance spectra of different materials such as water, soil, vegetation and rocks.
Some undesired effects, though, can interfere in the observed reflectance. These effects are specially present in space-borne sensors, as they are located outside Earth’s atmosphere and the presence of clouds, water vapor, etc. are constantly absorbing and scattering electromagnetic energy. Another important effect that can interfere in the observed reflectance is sunglint.
Sunglint is caused by the specular (or mirror-like) reflectance of incident radiance on some surfaces in the same angle of the satellite or other sensor viewing it. In these cases, the sensor will not measure the characteristics of the observed target, but a mixture with the spectra of the emitting source. And this can bring issues for many remote sensing applications.
In fire detection, for example, Giglio et. al. (2003)[1] shows that the effect of sunglint on some targets like water bodies, wet soil, cirrus clouds and even bare soil can cause false fire alarms. In water resources, this effect is specially important as water surfaces are the most affected by the sunglint (Figure 2).
Because of this, glint correction or at least glint identification is an important task for most remote sensing applications.
As our objective is not to dig deep in electromagnetic radiance theory, but to show how one can use Python and Sentinel 2 metadata info to estimate the occurrence of sunglint in the scene. For a full glint removal in aquatic systems, I suggest the paper from Harmel et. al. (2018)[2]. Instead, we will show how to predict the presence of sunglint using the approach proposed by Giglio et. al. (2003). In this approach we have to check the relationship between the solar and viewing angles (zenith and azimuth) at the moment the image has been acquired, according to the following equation:
In this equation the subscripts v, s and g stands for viewing, solar and glint angles, θ refers to zenith angles and Φ is the azimuth angle difference between the sun and the sensor, as represented in Figure 3.
The final glint angle value will be obtained by Arccos(θg) . According to the author, the resulting glint angle is a predictor of occurrence of sunglint. The smaller the glint angle value, the more “aligned” are the sensor and the sun and it will be higher the probability of sunglint.
All the information we need for this calculation is contained in the Sentinel’s 2 metadata file MTD_TL.xml. This file is located inside the GRANULE subdirectory. So, let’s take a look at it. It can be overwhelming if we open this file for the first time, but if we look for Sun_Angles_Grid tag, we can find all the information we need concerning the sun position:
Note that it is presented in steps of 5000m (23x23 grid), so this is not exactly a “pixelwise” information, but we can interpolate it to match pixel resolution afterwards. We will start by reading the sun angles from the metadata through the lxml package. At the end, we will use a pandas Dataframe just for visualization purpose.
Code output:
(         0        1        2        3        4 0  19.5389  19.4952  19.4514  19.4076  19.3638 1  19.5431  19.4994  19.4556  19.4119  19.3681 2  19.5474  19.5037  19.4600  19.4162  19.3725 3  19.5518  19.5081  19.4644  19.4207  19.3769 4  19.5564  19.5126  19.4689  19.4252  19.3815,          0        1        2        3        4 0  80.1116  80.1092  80.1067  80.1041  80.1014 1  79.9860  79.9833  79.9804  79.9775  79.9745 2  79.8605  79.8574  79.8543  79.8510  79.8477 3  79.7350  79.7316  79.7281  79.7246  79.7209 4  79.6095  79.6058  79.6021  79.5982  79.5942)
If we compare with the angles from the XML file, we can see that our data was loaded correctly. We could do the same for the sensors, but if you look carefully, you will see that we have many different sensors, and they have different angles. As we want to have a mean glint prediction for our scene, we will use an average of the angles for each sensor. To accomplish this, we will create a generic function that reads the arrays of a given node name and returns its average to retrieve mean zenith and azimuth for the sensors. At the end we will plot the angles using matplotlib.
Code output:
Note: We may see that the viewing azimuth angles have some issues in detectors transitions. The discussion thread about this problem can be found here (https://forum.step.esa.int/t/sentinel-2-viewing-angles-interpolation-on-per-pixel-basis/2776/4)
Now that we have all the angles we need, it’s time to calculate the glint angle. First we should convert them all to radians (the unit used by numpy’s trigonometric functions). Then, the final calculation is pretty straightforward. To visualize the results, we will create an annotated heatmap with its values.
Code output:
To visualize the portions of the image that are more prone to have sunglint, nothing better than superimposing the glint angles grid with the image’s rgb representation. To get the rgb representation of the satellite image, we will use the rasterio package to read the Red, Green and Blue bands, as explained in the Python for Geosciences: Satellite Image Analysis series(here).
Code output:
Now, we can superimpose both grids using the imshow function from matplotlib and adjusting correctly the extents argument and the alpha to apply a transparency.
ax.imshow(rgb*4, alpha=0.6, extent=(-0.5, 22.5, 22.5, -0.5))fig
In this story we’ve discussed how to estimate the sunglint occurrence based on the solar and viewing angles available en Sentinel’s 2 metadata as proposed by Giglio (2003). With this information it is possible to adjust any remote sensing application that is affected by the sunglint presence. As an example, this simple sunglint prediction is being currently implemented in the waterdetect python package (here)[3] as a way to adjust the maximum thresholds levels when sunglint is expected. It could also be used in cloud detectors, to avoid water as being identified as clouds or in fire detection to prevent false positives.
If you have any doubts our comments about this subject, don’t hesitate to write it in the comments. And don’t forget to follow me if you want to receive more stories like this. So stay tuned and see you in the next story.
For more stories like this: https://cordmaur.medium.com/
If you liked this article and want to continue reading/learning these and other stories without limits, consider becoming a Medium member. You can also check out my portfolio at https://cordmaur.carrd.co/.
cordmaur.medium.com
[1] Giglio, L.; Descloitres, J.; Justice, C. O.; Kaufman, Y. J. An Enhanced Contextual Fire Detection Algorithm for MODIS. Remote Sensing of Environment 2003, 87 (2), 273–282. https://doi.org/10.1016/S0034-4257(03)00184-6.
[2] Harmel, T.; Chami, M.; Tormos, T.; Reynaud, N.; Danis, P.-A. Sunglint Correction of the Multi-Spectral Instrument (MSI)-SENTINEL-2 Imagery over Inland and Sea Waters from SWIR Bands. Remote Sensing of Environment 2018, 204, 308–321. https://doi.org/10.1016/j.rse.2017.10.022.
[3] Cordeiro, M. C. R.; Martinez, J.-M.; Peña-Luque, S. Automatic Water Detection from Multidimensional Hierarchical Clustering for Sentinel-2 Images and a Comparison with Level 2A Processors. Remote Sensing of Environment 2021, 253, 112209. https://doi.org/10.1016/j.rse.2020.112209.