Yeah! mapping with a 10m spatial resolution.
Both new Sentinel-1 and Sentinel-2 satellites take measurements of the earth with a very high spatial and good temporal resolution. These data are very useful for mapping landuse and landuse change. This tutorial show how simple algorithms can be used to identify areas with water, dense vegetation, settlements and rice paddies.
1. Import the Sentinel-1 and Sentinel-2 ImageCollection.
2. Define the geographic and temporal domain.
// Define period var startdate = ee.Date.fromYMD(2014,1,1); var enddate = ee.Date.fromYMD(2016,12,1); // Define geograpic domain var Ca = ee.FeatureCollection('ft:1T7GmJ0tJCu4QwclY5qiG9EGBFgNhhNjttq8F7gQm'); Map.centerObject(Ca,8);
3. Filter the data.
// filter s2 data</pre> var Sentinel2 = s2.filterBounds(Ca) .filterDate(startdate, enddate) .filterBounds(Ca); // filter s1 data var Sentinel1 = ee.ImageCollection('COPERNICUS/S1_GRD') .filterBounds(Ca) .filterDate(startdate, enddate) .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV')) .select('VV');
4. remove the clouds from Sentinel-2
// cloud function to remove clouds var cloudfunction_ST2 = function(image){ //use add the cloud likelihood band to the image var quality = image.select("QA60").unmask(); //get pixels above the threshold var cloud01 = quality.gt(0); //create a mask from high likelihood pixels var cloudmask = image.mask().and(cloud01.not()); //mask those pixels from the image return image.updateMask(cloudmask); }; // remove the clouds var ST2_nocloud = Sentinel2.map(cloudfunction_ST2);
5. Calculate the NDBI, NDVI and NDWI from the median of Sentinel-2
// take the median var st2median = ST2_nocloud.median(); // the normalized difference bare index var ndbi = st2median.normalizedDifference(['B12', 'B8']); // the normalized difference vegetation index var ndvi = st2median.normalizedDifference(['B8', 'B4']); // the normalize difference water index var ndwi = st2median.normalizedDifference(['B3', 'B8']);
6. Set the threshold for the indices.
// define thresholds var bareThreshold = -0.32 var vegetationThreshold = 0.65 var waterThreshold = 0.2
7. Add the different layers to the canvas.
// show the urban area var ndbi_th = ndbi.gt(bareThreshold) var myndbi = ndbi_th.updateMask(ndbi_th).clip(Ca) var ndbi_viz = {palette:"111101"}; Map.addLayer(myndbi, ndbi_viz, 'Urban'); // show the water areas var ndwi_th = ndwi.gt(waterThreshold) var myndwi = ndwi_th.updateMask(ndwi_th).clip(Ca) var ndwi_viz = {palette:"24069b"}; Map.addLayer(myndwi, ndwi_viz, 'Water'); // show the forests var ndvi_th = ndvi.gt(vegetationThreshold) var myndvi = ndvi_th.updateMask(ndvi_th).clip(Ca) var ndvi_viz = {palette:"006b0c"}; Map.addLayer(myndvi, ndvi_viz, 'Vegetation');
8. Compare the wet from the dry conditions using a reducer function on the sentinel-1 images.
// create a map of the wet and dry conditions from sentinel-1 var wet = Sentinel1.reduce(ee.Reducer.percentile([10])) var dry = Sentinel1.reduce(ee.Reducer.percentile([90]))
9. Identify the rice paddies which are inundated in the wet season, but dry in the dry season.
// calculate the difference between wet and dry conditions var paddies = wet.subtract(dry)
10. Mountains can be identified as rice paddies, so we remove all slopes greater than 2 degrees.
// remove the mountains from the data var hydrosheds = ee.Image('WWF/HydroSHEDS/03VFDEM'); var terrain = ee.Algorithms.Terrain(hydrosheds); var slope = terrain.select('slope'); // remove all slopes greater then 2 degrees paddies = paddies.updateMask(slope.lt(2));
11. Also add the paddies to the map based on the threshold of -8.
// set the paddy threshold var paddies_th = -8; // select areas smaller than the threshold var paddies_th = paddies.lt(paddies_th); // mask the areas that are not rice paddies var mypaddies = paddies_th.updateMask(paddies_th).clip(Ca) var paddies_viz = {palette:"c2c64d"}; Map.addLayer(mypaddies, paddies_viz, 'Rice');
Find the full script here.
Hi. Loving this procedure. However I am getting the following error at step 7:
Urban: Layer error: Feature, argument ‘geometry’: Invalid type. Expected: Geometry. Actual: Feature.
Water: Layer error: Feature, argument ‘geometry’: Invalid type. Expected: Geometry. Actual: Feature.
Vegetation: Layer error: Feature, argument ‘geometry’: Invalid type. Expected: Geometry. Actual: Feature.
What could be the issue?
Not sure. Try adding .geometry() to your Feature. Send me the link to your script if that doesn’t help.
Thanks for the speedy response! I am using the exact same script that you have here with some minor modifications at the names, and coordinates. See script below:
//Import the Sentinel-1 and Sentinel-2 ImageCollection.
var s2 = ee.ImageCollection(“COPERNICUS/S2”),
s1 = ee.ImageCollection(“COPERNICUS/S1_GRD”);
ee.ImageCollection(‘COPERNICUS/S2’);
ee.ImageCollection(‘COPERNICUS/S1’);
//Define the geographic and temporal domain
//Define period
var startdate = ee.Date.fromYMD(2016,1,1);
var enddate = ee.Date.fromYMD(2016,12,1);
// Define geographic domain.
var rectangle = ee.Geometry.Rectangle(37.99,-0.403, 38.44,-1.081 );
var Mwi = ee.Feature(rectangle);
Map.centerObject(Mwi, 12);
// filter s2 data
var Sentinel2 = s2.filterBounds(Mwi)
.filterDate(startdate, enddate)
.filterBounds(Mwi);
//// filter s1 data
var Sentinel1 = ee.ImageCollection(‘COPERNICUS/S1_GRD’)
.filterBounds(Mwi)
.filterDate(startdate, enddate)
.filter(ee.Filter.listContains(‘transmitterReceiverPolarisation’, ‘VV’))
.select(‘VV’);
// cloud function to remove clouds
var cloudfunction_ST2 = function(image){
//use add the cloud likelihood band to the image
var quality = image.select(“QA60″).unmask();
//get pixels above the threshold
var cloud01 = quality.gt(0);
//create a mask from high likelihood pixels
var cloudmask = image.mask().and(cloud01.not());
//mask those pixels from the image
return image.updateMask(cloudmask);
};
// remove the clouds
var ST2_nocloud = Sentinel2.map(cloudfunction_ST2);
// take the median
var st2median = ST2_nocloud.median();
//Calculate the NDBI, NDVI and NDWI from the median of Sentinel-2
// the normalized difference bare index
var ndbi = st2median.normalizedDifference([‘B12’, ‘B8’]);
// the normalized difference vegetation index
var ndvi = st2median.normalizedDifference([‘B8’, ‘B4’]);
// the normalize difference water index
var ndwi = st2median.normalizedDifference([‘B3’, ‘B8’]);
// Set the threshold for the indices
var bareThreshold = -0.32;
var vegetationThreshold = 0.65;
var waterThreshold = 0.2;
//Add the different layers to the canvas
Map.addLayer(Mwi);
// show the urban area
var ndbi_th = ndbi.gt(bareThreshold);
var myndbi = ndbi_th.updateMask(ndbi_th).clip(Mwi);
var ndbi_viz = {palette:”111101″};
Map.addLayer(myndbi, ndbi_viz, ‘Urban’);
// show the water areas
var ndwi_th = ndwi.gt(waterThreshold);
var myndwi = ndwi_th.updateMask(ndwi_th).clip(Mwi);
var ndwi_viz = {palette:”24069b”};
Map.addLayer(myndwi, ndwi_viz, ‘Water’);
// show the forests
var ndvi_th = ndvi.gt(vegetationThreshold);
var myndvi = ndvi_th.updateMask(ndvi_th).clip(Mwi);
var ndvi_viz = {palette:”006b0c”};
Map.addLayer(myndvi, ndvi_viz,’Vegetation’);
Also, how did you decide on the thresholds for this:
var bareThreshold = -0.32;
var vegetationThreshold = 0.65;
var waterThreshold = 0.2;
There is a get link button in the GEE. This gives you an unique link for sharing your code. Can you share that one with me?
It’s always hard to come up with an exact value for a threshold. I determined them based on trial and error.
Thanks very much for your speedy response. Here is the link to the script:
https://code.earthengine.google.com/a5896ab327f199ddf73ab77032cf2739
Regards
Pamela
Is this something you can work with? https://code.earthengine.google.com/d51061e27e8333de90bd1566d19ffc54
This looks great! Many many thanks for taking the time to help. Please tell me, where was my script going wrong? and how do you determine the thresholds? Do you click in the image?
Also, would you mind troubleshooting another script that I am trying to run to classify land cover using Sentinel 2? I used training data from a Worldview 2 image of the same site and saved them into a csv format.
https://code.earthengine.google.com/ddcb13c7b670431a319a7d5d71f544c9
Brought in the training data as a fusion table to classify sentinel images. but i get the following error:
‘classification: Layer error: No data was found in classifier training input’
where could I be going wrong?
Regards,
Pamela
Also, do you mind trouble shooting another script that I am trying to run. It is a supervised classification using CART and I extracted the training data from a WorldView2 image in form of pixels for 5 classes. I want to use the training data (in the form of fusion table) to classify Sentinel 2 data. Here is the link to the script:
https://code.earthengine.google.com/fdb2889394aa28f2fbc33a5a2462eb32
Regards,
Pamela
Sorry, I have double posted. Kindly ignore.
Do you guys have experience to transform the image to vector via GEE? I would like to get the building information of the certain area.
please have a look at this post
Hello! I want to automated maped cropland grom my region od interesa. Can you jave any idea how vam I do in Google earth engine? Code?
Iam trying to run your script in GEE but it fails to load the fusion table. How would I fix this? Any help would be appreciated.
Error: Collection.loadTable: Fusion Table ‘1T7GmJ0tJCu4QwclY5qiG9EGBFgNhhNjttq8F7gQm’ not found.
For newest news you have to visit world-wide-web and on web I found this web site as a most excellent website for latest updates.
Was Sentinel 1 really used?
Hello, Loving this procedure.However I don’t understand how was sentinel 1 used?And what create a map of the wet and dry conditions from sentinel-1 for?