[DOC] Generating Thumbnails From Sentinel-3 300m GSD Satellite Imagery

Sentinel-3 open data provides an interesting option for ML dataset generation

Right after the earthquake in Nepal in 2015, I felt restless being stuck in Korea with my hands completely cuffed. To get a little peace of mind and feel like I am contributing somehow, I took a class in remote sensing at Seoul National which led me to write this journal paper [HERE]. The thing is, if you have ever worked on imagery data either from USGS or ESA, you will know that products are 1) very large, that 2) you will need a proper software to open those products (not free) and that it takes an excruciatingly long time to get one image processed. For instance, a data product with all the bands can be up to and not limited to 1.5 GB, which then needs to be opened through a software like ESRI, create a ROI (Region of Interest) and then do the actual processing. That's for ONE image. 

Enter google's Earth Engine [HERE], which disrupts the process pretty spectacularly. With a few lines of coding [Do the code HERE], you are able access large datasets from all open satellite imagery, filter bands, create a preview on the website itself through it's Javascript based API (Application Programming Interface) and export the ROI onto your drive. Very neat. What's also interesting is the ability to create thumbnails of any data that's been previewed. 

Why are Thumbnails Useful?

256x256 thumbnail generated from Sentinel-3
Type: True Color

Normally, it's the product that comes into use and not the thumbnails. However, there is real value in generating thumbnails that allow, quite possibly, to use as a training data set for Machine Learning (ML) algorithms. Sentinel-3 nadir pointing imagery of 300 Ground Sampling Distance (GSD) -popularly known as the "resolution" of the satellite image- simulates images taken from CubeSats from Low Earth Orbit (LEO). Case in point, NepaliSat-1's calculated GSD hovers around the same number. If done correctly, the potential here is that we can generate a rich dataset for customized, mission specific ML for image categorization. 

Satellite imagery taken by 1U satellite with similar orbit and pixel characteristics to NepaliSat-1's payload

As the images above and below illustrate, satellite imagery taken with a Size, Weight and Power (SWAP) requirements of 1U CubeSat can come close to about the same resolution taken by Sentinel-3. I am personally a huge fan of EstCube 1U satellite design and the level of optimization they were able to achieve. Says a lot about their engineering technique. The data that's coming out from the satellite is, in fact, very, very good. 

1U CubeSat's have the potential, if done correctly, to provide very good 300 GSD images

Extracting Thumbnails
Now that I have clarified why creating thumbnails (could) have real value, let's start cooking.

Full code below, explanation of each step after that. It's not as colorful as I wanted but does the trick.

//Select dataset from Sentinel-3
var dataset = ee.ImageCollection('COPERNICUS/S3/OLCI')
              //Select the dates through .filterDate function
              .filterDate('2018-04-01', '2018-04-04');
               
//Print collection to the console
print('Collection', dataset);

//Select data from Sentinel-3
//You can select one image from the 'Collection' printed on the 'Console'
var data = ee.Image('COPERNICUS/S3/OLCI/S3A_20180403T124616_20180403T124916')

//Select bands for visualization and apply band-specific scale factors.
var rgb = data.select(['Oa08_radiance', 'Oa06_radiance', 'Oa04_radiance'])
              // Convert to radiance units
              .multiply(ee.Image([0.00876539, 0.0123538, 0.0115198]));

//Change parameters for image preview
var visParams = {
  min: 0,
  max: 3,
  gamma: 1.5,
};

//Create RGB image on the map using the parameters above
Map.addLayer(rgb, visParams, 'RGB');

//Create box that encloses the data that will be on the thumbnail
//Coordinates c by using "Inspector" and then clicking on the map
var box = ee.Geometry.Rectangle(-50.444, -5.33, -46.742, -9.012);

//Use Earth Engine's thumbnail widget to create the thumbnails 
//Prints it on the "Console"
var image = ee.Image(data).visualize({
  bands: ['Oa08_radiance', 'Oa06_radiance', 'Oa04_radiance'],
  min: 0,
  max: 250,
  gamma: [1.5, 1.5, 1.5]
});

//Print a thumbnail to the console
print(ui.Thumbnail({
  image: image,
  params: {
    dimensions: '256x256',
    region: box.toGeoJSON(),
    format: 'png'
  },
  style: {height: '300px', width: '300px'}
}));

Step by Step Approach
A. Data Collection Selection
Check for the dataset availability first before moving on to coding. Also, make sure to be registered with the website. Earth Engine should have the complete dataset for a particular satellite, like Sentinel-3. You can get the dataset code [HERE].

Sentinel-3 data over Nepal

The dataset variable selects Sentinel-3 data, then filters through April 1st, 2018 to April 4th, 2018 data. dataset now stores only the images from that time frame. In order to see what the names of the data are, use the print function to check on the "Console."

//Select dataset from Sentinel-3
var dataset = ee.ImageCollection('COPERNICUS/S3/OLCI')
              //Select the dates through .filterDate function
              .filterDate('2018-04-01', '2018-04-04');
             
//Print collection to the console
print('Collection', dataset);

B. Specific Data Selection
Once you have the collection of the data stored on dataset, we now move into selecting a specific data to process. On the "Console," you can observe what the ID is and then paste it inside the ee.Image().  Variable data will have that stored. Documentation can be observed on "Docs" tab on the left.

As we want true color images (RGB), we need to now select the bands. The name of the bands are documented [HERE] under the "Band" tab. The RGB image is now stored on the variable rgb. 

//Select data from Sentinel-3
//You can select one image from the 'Collection' printed on the 'Console'
var data = ee.Image('COPERNICUS/S3/OLCI/S3A_20180403T124616_20180403T124916')

//Select bands for visualization and apply band-specific scale factors.
var rgb = data.select(['Oa08_radiance', 'Oa06_radiance', 'Oa04_radiance'])
              // Convert to radiance units
              .multiply(ee.Image([0.00876539, 0.0123538, 0.0115198]));

C. Creating Preview Layer on Map
The rgb variable can now be visualized. In order to use the Map.addLayer() function, rgb provides the imagery and visParams provides visualizing parameters. visParams can be modified through min, max and gamma. max changes brightness. 

//Change parameters for image preview
var visParams = {
  min: 0,
  max: 3,
  gamma: 1.5,
};

//Create RGB image on the map using the parameters above
Map.addLayer(rgb, visParams, 'RGB');

D. Creating Basis for Thumbnail
To create thumbnail, we must 1) define the boundaries and 2) create visualization parameters. There are many ways to define the boundary but I have found that making a box seems to be an easier route. The "Inspector" tab on the right allows you to inspect the coordinates by simply clicking on the point of interest. The box information is then stored on the box variable. 

Visualizing is similar to the steps we did before. The image will be stored on image variable. max allows to change the brightness. You could play around with the numbers to get a feel of how changing numbers changes the thumbnail output. 

//Create box that encloses the data that will be on the thumbnail
//Coordinates c by using "Inspector" and then clicking on the map
var box = ee.Geometry.Rectangle(-50.444, -5.33, -46.742, -9.012);

//Use Earth Engine's thumbnail widget to create the thumbnails 
//Prints it on the "Console"
var image = ee.Image(data).visualize({
  bands: ['Oa08_radiance', 'Oa06_radiance', 'Oa04_radiance'],
  min: 0,
  max: 250,
  gamma: [1.5, 1.5, 1.5]
});

E. Generating Thumbnail
Earth Engine has this neat widget that generates the thumbnail for you on the "Console." All I did was copy and paste the source code making sure that the variables match up. You change the format to .jpg and the dimensions accordingly. For mine, the dimensions have been set to 256x256 thumbnails. 

//Print a thumbnail to the console
print(ui.Thumbnail({
  image: image,
  params: {
    dimensions: '256x256',
    region: box.toGeoJSON(),
    format: 'png'
  },
  style: {height: '300px', width: '300px'}
}));

That's your lot, there's loads to improve on but this should get anyone started. I haven't centered the map to the data location so do make sure to zoom out and locate the imagery.

Comments

Popular Posts