Sentinel-1 SAR data Visualization in EO Browser using a Custom Script

Custom script to create visualizations from Sentinel-1 SAR data

Grand Bahama Island

Grand Bahama Island Sentinel-1 SAR image

Visualizing Sentinel-1 SAR data in the EO Browser

Sentinel-1 SAR data can be hard to interpret, and even the best visualization can’t really change that. But a good visualization can help you to focus on specific aspects of the data and also generate images that might be used for the general public, as they are more alike to what people are used to see (blue water, green land).

This script is easily adaptable to include other visualizations or change the included ones. Don’t be shy to try out all variables and see what is working best for you, Earth is very versatile and no single fixed script could be used to really get the best result for each location, so try to experiment.

And as I have said in other posts before, see the result you get with this script as a start. While it can produce really good images directly within the amazing EO Browser, you might want to post-process them with other tools to get even more out of the data or produce images that are easier to understand for your audience. To show the capabilities of the script all examples in this post are solely made with the script within the EO Browser, without any further post-processing.

Note This script is meant to work with Sentinel-1 images in acquisition mode IW (Interferometric Wide Swath) and polarization VV+VH.

The Script

// Sentinel-1 False-Color Visualization V1.0.0
// Twitter: Pierre Markuse (@pierre_markuse)
// Website: https://pierre-markuse.net/
// CC BY 4.0 International - https://creativecommons.org/licenses/by/4.0/

function stretch(val, min, max)  {
	return (val - min) / (max - min);
}

function satEnh(rgbArr) {
    var avg = rgbArr.reduce((a, b) => a + b, 0) / rgbArr.length;
    return rgbArr.map(a => avg * (1 - saturation) + a * saturation);
}

var BLUE = [0.0, 0.2, 1.0];
var GREEN = [0.0, 0.7, 0.0];
var BLACK = [0.0, 0.0, 0.0];
var RED = [1.0, 0.0, 0.0];

var water_normal = [stretch(VV*1,0.0,0.99),stretch(VV*8,0.0,0.99),0.5+VV*3+stretch(VH*2000,0.0,0.99)];
var water_bright = [stretch(VV*1.33,0.0,0.99),stretch(VV*10,0.0,0.99),0.5+VV*4+stretch(VH*3000,0.0,0.99)];
var oilspill_1 = [stretch(VV*5.0,0.2,0.99),0.0+stretch(VV*10,0.10,0.50),0.0+stretch(VV*20,0.10,0.50)];
var oilspill_2 = [stretch(VV*5.0,0.2,0.99),0.0+stretch(VV*10,0.15,0.40),0.1+stretch(VV*20,0.15,0.40)];
var oilspill_3 = [stretch(VV*5.0,0.2,0.99),0.1+stretch(VV*11,0.03,0.60),0.1+stretch(VV*23,0.01,0.58)];
var land_redder = [stretch(VV*3.4,-0.0,0.99),(stretch(VV*1.1,-0.0,0.99)+stretch(VH*8.75,-0.0,0.99)),stretch(VH*1.75,-0.0,0.99)];
var land_normal = [stretch(VV*3.0,-0.0,0.99),(stretch(VV*1.1,-0.0,0.99)+stretch(VH*8.75,-0.0,0.99)),stretch(VH*1.75,-0.0,0.99)];
var land_greener = [stretch(VV*3.0,-0.0,0.99),(stretch(VV*1.4,-0.0,0.99)+stretch(VH*9.75,-0.0,0.99)),stretch(VH*1.75,-0.0,0.99)];
var city = [0.9-VV-2*VH,0.9-VV-3*VH,0.9-0.3*VV-6*VH];


var watervis = water_normal;
var landvis = land_normal;
var water_threshold = 25; //lower means more water
var saturation = 1.0; //Standard 1.0
var brightness = 1.0; //Standard 1.0
var avoid_dark_land = 0; //0=off,1=on
var avoid_dark_land_threshold = 0.1; //Standard 0.05
var avoid_dark_water = 0; //0=off,1=on
var avoid_dark_water_threshold = 1.00; //Standard 1.00
var manualCorrection_water = [0.00, 0.00, 0.00];
var manualCorrection_land = [0.00, 0.00, 0.00];

var i = 0;
while (i<3) {
 watervis[i] = watervis[i] + manualCorrection_water[i];
 landvis[i] = landvis[i] + manualCorrection_land[i];
 landvis[i] = landvis[i] * brightness;
 i++;
};

var watervis = satEnh(watervis);
var landvis = satEnh(landvis);

if (avoid_dark_land) {
 var dark = landvis[0]+landvis[1]+landvis[2];
 if (dark < avoid_dark_land_threshold) {var landvis=BLUE;}; //Try other things than BLUE!
};

if (avoid_dark_water) {
 var dark = watervis[0]+watervis[1]+watervis[2];
 if (dark < avoid_dark_water_threshold) {var watervis=BLUE;}; //Try other things than BLUE!
};

return ((VV/VH) > water_threshold)
? watervis :
 landvis;

Copy and paste the script or right-click and download it here. Together with many other scripts it is also available in the Sentinel Hub Custom Script Repository.

A few explanations

var watervis = water_normal;
var landvis = land_normal;
var water_threshold = 25; //lower means more water

In these two lines, you choose which visualization should be used for water and land. The water/land distinction is simple but good enough for most images, change water_threshold to adapt to your scene.

land_normal usually yields good results, but if you want your scene to appear greener use land_greener, and in case you want it to appear more reddish and arid use land_redder. city can help when showing bigger cities with lots of artifacts caused by big buildings and bridges as it is a more subtle visualization, not showing cities as bright as the other land visualizations, it can also look nice with hilly terrains.

For water, you have even more choices. water_normal is usually the best choice, with water_bright giving you some more vivid colors for your water. oilspill_1, oilspill_2, and oilspill_3 are three slightly different visualizations to better show oil spills in water by creating more contrast. Choose the one you think is working best for your scene.

ImportantShould you be trying to show oil spills the variables avoid_dark_land and avoid_dark_water should be set to 0.

var saturation = 1.0; //Standard 1.0
var brightness = 1.0; //Standard 1.0

Pretty self-explanatory, these variables can be used to change the saturation and brightness of the scene. Note that while saturation does work on land and water, brightness is just working on land as water usually renders okayish or not at all, depending on your scene. However, should you want to get darker or brighter water, you can always change the visualization itself to fit your needs.

var avoid_dark_land = 0; //0=off,1=on
var avoid_dark_land_threshold = 0.1; //Standard 0.05
var avoid_dark_water = 0; //0=off,1=on
var avoid_dark_water_threshold = 1.00; //Standard 1.00

These variables can be used to avoid black or too dark pixels in your resulting image. Using these you can usually get a way better visualization of water (sea as well as inland water bodies). The thresholds can be used to adapt the function to your specific scene. Play with it to get the best results.

ImportantIn case you’re using this function to get better water visualization, the variables landvis and watervis in lines 56 and 61 should be set to their standard of BLUE.

var manualCorrection_water = [0.00, 0.00, 0.00];
var manualCorrection_land = [0.00, 0.00, 0.00];

You can use these variables to manually change the appearance of the visualization by directly adding (positive values) or subtracting (negative values) RGB values.

Feel free to experiment with the script and share the images you produce with it!

Examples

A few example images created with the script, a lot more is possible, but I guess these are some of the things people might want to do.

Hawaiʻi Sentinel-1 satellite image

Hawaiʻi, beautifully rendered using water_normal and land_normal. I find it amazing how it is possible to get results like this one directly from the EO Browser.

Hawaiʻi Sentinel-1 satellite image

And the same image with watervis set to BLACK.

Oil spill Sentinel-1 satellite image

An oil spill in water_normal visualization.

Oil spill Sentinel-1 satellite image

And in oilspill_1 visualization to better show it.

London Sentinel-1 satellite image

London in city visualization.

Sundabarn National Parl Sentinel-1 satellite image

Sundabarn National Park in land_normal and water_normal.

Kamchatka, Russia, Sentinel-1 satellite image

Kamchatka, Russia in land_normal and water_normal.

Kamchatka, Russia, Sentinel-1 satellite image

And the same scene with landvis set to city, showing nice hills. Really love the look of it.

Other scripts

You may or may not know, but I also wrote scripts to visualize Sentinel-2 and Sentinel-3 data. You can find the Sentinel-2 script here, and although it focuses on wildfires it can be used for basically any Sentinel-2 scene given the many variables and options. The Sentinel-3 script is available here and creates more or less natural color scenes from Sentinel-3 data. In case you haven’t already, check those scripts out as well.

Feedback / Questions

Sentinel Hub Custom Script Contest

Take part in the second round of the Custom Script Contest

If you have some kind of feedback or questions regarding this article, or ideas on how it could be made better, feel free to share. Comment on this post or contact me via email or on Twitter.

In case you have general questions about the EO Browser you should read this FAQ and register at the Sentinel Hub Forum here to ask questions or maybe contribute your own scripts for the EO Browser. You can find all scripts in this Custom Script Repository, and a very good tutorial for custom scripting here.

Sentinel Hub Custom Script Contest

I’d also like to guide your attention to the second round of the Sentinel Hub Custom Script Contest, which started on October 15th and runs until January 15th, 2020. Once more giving you the opportunity to win attractive prizes with your Sentinel or Landsat script for the EO Browser.

Find more information on it here.

A good overview of the first contest’s winning scripts to get you started you can find in this blog post by Sabina Dolenc.

Images if not otherwise stated: Contains modified Copernicus Sentinel data [2019], processed by Pierre Markuse, CC BY 4.0 license

Leave a Reply

Your email address will not be published.