├── LICENSE ├── README.md └── javascript_codes └── LST-downscaling_GEE_APP.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Daniel Paluba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Landsat-8 Land Surface Temperature downscaling using Sentinel-2 in Google Earth Engine 2 | A Google Earth Engne tool to downscale Landsat Land Surface Temperature data to 10 m resolution using Sentinel-2 data. 3 | This code repository is an attachment for the article in Remote Sensing: Onačillová, K.; Gallay, M.; Paluba, D.; Péliová, A.; Tokarčík, O.; Laubertová, D. Combining Landsat 8 and Sentinel-2 Data in Google Earth Engine to Derive Higher Resolution Land Surface Temperature Maps in Urban Environment. Remote Sens. 2022, 14, 4076. [https://doi.org/10.3390/rs14164076](https://www.mdpi.com/2072-4292/14/16/4076/htm). 4 | 5 | This repository contains a folder "javascript_codes" where you can find: 6 | - A JavaScript Google Earth Engine (GEE) code "LST_downscaling_GEE_APP.js" used in the [LST-downscaling GEE Application](https://danielp.users.earthengine.app/view/lst-downscaling) to downscale (sharpen) the Land Surface Temperature (LST) derived from Landsat thermal sensing using the spectral bands of Sentinel-2 7 | 8 | ## How to use the [LST-downscaling GEE Application](https://danielp.users.earthengine.app/view/lst-downscaling) 9 | 1. Define the 5 input parameters: 10 | - start and end date (to select the desired time frame), 11 | - Landsat collection (to select whether to use the Landsat 8 or Landsat 9 image collection), 12 | - maximum cloud cover allowed for the image tiles and 13 | - the region of interest (ROI). 14 | - The default ROI set-ting is focused on Košice City. However, the user can change the location where the analysis will be performed. The ROI is created using the Geometry Tools in the GEE, which allow users to move or delete and then delineate their own new geometric fea-tures, such as polygons, to be applied in the analyses. 15 | 16 | 2. Click on **“Generate Landsat 8/9 and Sentinel-2 Image Collections”** button to generate available image IDs. 17 | - Based on this information, the list of Landsat 8/9 and Sentinel-2 imagery IDs that meet the entry criteria will be displayed under the button in the right panel. 18 | - The user will recieve a list of Landsat 8/9 and Sentinel-2 Image IDs that meet the selected criteria. 19 | 3. Enter Image IDs for the Landsat and for the Sentinel-2 Collection. 20 | - The user can select two image IDs from the resulting list – one ID for the Landsat 8/9 collection and one for the Sentinel-2 collection and enter their exact ID to the newly displayed text fields. Several Landsat 8/9 and Sentinel-2 imagery may be available in a given time window, therefore we recommend selecting data sets that were acquired on the same day. If images for Landsat 8/9 and Sentinel-2 collections are not available on the same acquisition day, we recommend choosing the datasets by the closest acquisition time to account for similar spectral characteristics of the derived spectral indices from both satellites. 21 | 4. Click on **"Generate Downscaled LST"** button to perform the Landsat 8/9 LST Downscaling to 10 m spatial resolution. 22 | **Note:** All input parameters, including image IDs, are pre-filled with parameters required to perform analysis showed in this paper. Without modifying the input parameters, the user gets the (slightly different) results produced in this article. 23 | - Tthe following 5 images: Landsat 8/9 and Sentinel-2 natural color images (RGB), original Landsat 8/9 LST in 30 m, downscaled LST to 10 m spatial resolution with and without assuming residuals are added to the Map. 24 | 5. (Optional) Click on **"Generate charts of spectral indices vs Landsat LST"** to generate scatterplots of correlation between Landsat 8/9 NDVI, NDWI and NDBI spectral indices and Landsat 8/9 LST bands. 25 | 26 | ### Final LST product download option 27 | To download the downscaled LST images use the [GEE Code Editor version](https://code.earthengine.google.com/005680c8acf54715c9b10e946400d842) or directly the code provided in the "LST_downscaling_GEE_APP.js" code in the "javascript_codes" folder. 28 | 29 | ## Outputs of the algorithm 30 | There are three different output types of the algorithm: (1) the main output is the downscaled LST 10 m with residuals, (2) bivariate scatter plots of LSTL8 vs. NDVIL8, NDBIL8, NDWIL8, (3) downscaling regression model. In the GEE code, the user will obtain the following outputs: 31 | - LST 10 m with residuals - final downscaled LST with regression residuals in 10 m spatial resolution 32 | - LST 10 m (no residuals) - downscaled LST in 10 m spatial resolution (without added regression residuals) 33 | - Landsat 8/9 LST – Landsat 8 Land Surface Temperature in 30 m spatial resolution 34 | - Landsat 8/9 LST regression residuals – regression residuals of LST computed as the difference between model estimation and the corresponding observation by Landsat 8/9 at 30 m resolution 35 | - Sentinel-2 RGB – true color composite for Sentinel-2 36 | - Landsat 8/9 RGB – true color composite for Landsat 8/9 37 | 38 | 39 | ## About the Landsat-8 Land Surface Temperature downscaling using Sentinel-2 in GEE 40 | This algorithm aims to downscale the coarse spatial resolution (100/30 m) Landsat 8/9 LST to finer spatial resolution (10 m) for more accurate mapping of LST. Three different indices, namely the normalized difference vegetation index (NDVI), built-up index (NDBI), and water index (NDWI) were used for disaggregation of Landsat LST (100/30 m) to 10 m Sentinel-2 spatial resolution using linear regression. The algorithm was developed in the cloud-based platform Google Earth Engine (GEE) using Landsat-8 and Sentinel-2 open access data. We conclude that the proposed downscaling model, by addressing the linear relationship of LST at coarse and fine spatial resolutions, can be successfully applied to produce high-resolution LST maps suitable for studies of the urban thermal environment at local scales. The performance was validated by the adjusted R2 returned at the stage of model development as well as by the validation of downscaled LST results using data logger measurements at 6 sites in the Košice city, Slovakia, to represent different types of land cover. 41 | 42 | ## A brief description of the methodology: 43 | Based on the input parameters, the respective images of Landsat Surface Reflectance (SR) Collection 2 and Sentinel-2 Level 2A (L2A) collections are used to NDVI, NDBI, and NDWI spectral indices for Landsat 8/9 (NDVIL8, NDBIL8, NDWIL8) in 30 m resolution and for Sentinel-2 in a 10 m resolution, respectively. 44 | The LST is then calculated at a 30 m resolution using the Landsat 8/9 thermal band (B10) converted to brightness temperature in degrees Celsius (LSTL8). Then, the linear regression model between LSTL8 and the spectral indices NDVIL8, NDBIL8, NDWIL8 is used to calculate regression coefficients. Finally, these regression coefficients are used to calculate the downscaled LST using Sentinel-2 NDVI, NDBI, and NDWI spectral indices in a 10 m resolution. Regression residuals are resampled using bicubic interpolation, filtered using Gaussian convolution and added back to the downscaled LST. Also, Landsat 8/9 and Sentinel-2 natural color images (RGB) are generated to compare with the final LST layers. 45 | For more detailed information see [the published article in Remote Sensing journal](https://www.mdpi.com/journal/remotesensing). 46 | -------------------------------------------------------------------------------- /javascript_codes/LST-downscaling_GEE_APP.js: -------------------------------------------------------------------------------- 1 | /* 2 | Authors: Onačillová, K., Gallay, M., Paluba, D., Péliová, A., Tokarčík, O., Laubertová, D. 3 | (For more info contact: katarina.onacillova@upjs.sk) 4 | 5 | This code is free and open. 6 | By using this code and any data derived with it, 7 | you agree to cite the following reference 8 | in any publications derived from them: 9 | 10 | Onačillová, K., Gallay, M., Paluba, D., Péliová, A., Tokarčík, O., Laubertová, D. 2022: 11 | Combining Landsat 8 and Sentinel 2 data in Google Earth Engine 12 | to derive higher resolution land surface temperature maps in urban environment 13 | 14 | This function selects the Landsat 8 and Sentinel 2 data based on user inputs 15 | and performes the downscaling of LST 16 | 17 | ########################################################################################################################################################################### 18 | */ 19 | 20 | // Set up panels and widgets for display 21 | // Set up title and summary widgets 22 | 23 | // // drawing tools 24 | // var drawingTools = Map.drawingTools(); 25 | 26 | // // Use the addLayer method on the drawing tools directly. 27 | // var geometries = [ee.Geometry.Polygon( 28 | // [[[21.134189623651263, 48.82947658234015], 29 | // [21.134189623651263, 48.57888560664585], 30 | // [21.433567065057513, 48.57888560664585], 31 | // [21.433567065057513, 48.82947658234015]]], null, false)]; 32 | 33 | // drawingTools.addLayer(geometries, 'my_geometry1', 'red'); 34 | // This sets the available draw modes. point and line would also be available 35 | 36 | var map = ui.Map(); 37 | // Prints true since drawingTools() adds drawing tools to the map. 38 | map.drawingTools().setDrawModes(["polygon", "rectangle"]) 39 | // Replace the default Map with the newly created map. 40 | ui.root.widgets().reset([map]); 41 | 42 | // App title 43 | var header = ui.Label('Landsat Land Surface Temperature downscaling using Sentinel-2', {fontSize: '23px', fontWeight: 'bold', color: '77797e'}); 44 | 45 | // App summary 46 | var text = ui.Label( 47 | 'Landsat land surface temperature downscaled at 10 m by Sentinel-2 data. ' + 48 | 'Developed for urban management.', 49 | {fontSize: '15px'}); 50 | 51 | // App title2 52 | var header2 = ui.Label('How to cite:', {fontSize: '16px', fontWeight: 'bold', margin:'0px 0px -5px 8px'}); 53 | 54 | // App summary2 55 | var text2 = ui.Label( 56 | 'Onačillová, K.; Gallay, M.; Paluba, D.; Péliová, A.; Tokarčík, O.; Laubertová, D. Combining Landsat 8 and Sentinel-2 Data in Google Earth Engine to Derive Higher Resolution Land Surface Temperature Maps in Urban Environment. Remote Sens. 2022, 14, 4076.', 57 | {fontSize: '15px', margin:'5px 0px 0px 8px'}); 58 | 59 | var textLink = ui.Label(' https://doi.org/10.3390/rs14164076', 60 | {fontSize: '15px', margin:'0px 0px 0px 8px',color:'blue'}) 61 | .setUrl('https://doi.org/10.3390/rs14164076'); 62 | 63 | // Create a panel to hold text 64 | var panel = ui.Panel({ 65 | widgets:[header, text, header2],//Adds header and text 66 | style:{width: '500px',position:'middle-right', margin: '10px'}}); 67 | 68 | panel.add(text2) 69 | panel.add(textLink) 70 | 71 | // Create variable for additional text and separators 72 | 73 | // This creates another panel to house a line separator and instructions for the user 74 | var intro = ui.Panel([ 75 | ui.Label({ 76 | value: '__________________________________________________________', 77 | style: {fontWeight: 'bold', color: '77797e'}, 78 | })]); 79 | 80 | // Add panel to the larger panel 81 | panel.add(intro) 82 | 83 | // Add main panel to the root of GUI 84 | ui.root.insert(1,panel) 85 | 86 | 87 | 88 | // Defining startDate and endDate in the UI 89 | var dateLabel = ui.Label({ 90 | value:'Select start and end dates to find a proper L8/9 and S2 image pair', 91 | style: {fontWeight: 'bold', fontSize: '14px', margin: '10px 5px'} 92 | }) 93 | 94 | var startLabel = ui.Label({ 95 | value:'Start date', 96 | style: {margin: '0 55px 0 10px',fontSize: '12px',color: 'gray'} 97 | }) 98 | var endLabel = ui.Label({ 99 | value:'End date', 100 | style: {margin: '0 0px 0 10px',fontSize: '12px',color: 'gray'} 101 | }) 102 | var startDate_selected = ui.Textbox({placeholder: 'Start Date', value: '2018-08-21', 103 | style: {width: '100px'}}); 104 | var endDate_selected = ui.Textbox({placeholder: 'End Date', value: '2018-08-27', 105 | style: {width: '100px'}}); 106 | 107 | var Landsat_collection_label = ui.Label('Choose a Landsat Collection', 108 | {fontWeight: 'bold', fontSize: '14px', margin:'5px 0px 0px 8px'}); 109 | 110 | var cloudSliderLabel = ui.Label('Set the maximum cloud coverage (in %)', 111 | {fontWeight: 'bold', fontSize: '14px', margin:'5px 0px 0px 8px'}); 112 | 113 | // Define labels for Landsat 8 and 9 Collections 114 | var L8 = 'Landsat 8 Image Collection', 115 | L9 = 'Landsat 9 Image Collection'; 116 | 117 | // Define the select button for the AOI 118 | var selectCollection = ui.Select({ 119 | items:[L8,L9], 120 | placeholder:'Select Landsat Collection',value: 'Landsat 8 Image Collection' 121 | }); 122 | 123 | function setLandsatCollection(){ 124 | LCOll = selectCollection.getValue(); 125 | if (LCOll == L8){ 126 | collection = "L8"; 127 | } 128 | else if(LCOll == L9){ 129 | collection = "L9"; 130 | } 131 | }; 132 | 133 | // Add a slider bar widget 134 | var cloudSlider = ui.Slider({min:0,max:100, style:{width:'200px'}}).setValue(5); 135 | 136 | var GenerateImagesButton = ui.Button('Generate Landsat 8/9 and Sentinel-2 Image Collections', generateImsButton); 137 | 138 | var appUseText1 = ui.Label('A brief description of how to work with the application can found at the', 139 | {fontWeight: 'italic', fontSize: '14px', margin:'5px 0px 0px 8px'}); 140 | var appUseLink1 = ui.Label(' GitHub repository ', 141 | {fontWeight: 'italic', fontSize: '14px', margin:'0px 0px 0px 3px',color:'blue'}) 142 | .setUrl('https://github.com/palubad/LST-downscaling-to-10m-GEE#how-to-use-the-lst-downscaling-gee-application'); 143 | var appUseText3 = ui.Label(' or in the ', 144 | {fontWeight: 'italic', fontSize: '14px', margin:'0px 0px 0px 3px'}); 145 | var appUseLink2 = ui.Label(' article', 146 | {fontWeight: 'italic', fontSize: '14px', margin:'0px 0px 0px 3px',color:'blue'}) 147 | .setUrl('https://www.mdpi.com/2072-4292/14/16/4076/htm'); 148 | var appUseText4 = ui.Label('.', 149 | {fontWeight: 'italic', fontSize: '14px', margin:'0px 0px 0px 0px'}); 150 | 151 | var appUseText5 = ui.Label('To download the downscaled LST images use the ', 152 | {fontWeight: 'italic', fontSize: '14px', margin:'5px 0px 0px 8px'}); 153 | var appUseLink5 = ui.Label(' GEE Code Editor version', 154 | {fontWeight: 'italic', fontSize: '14px', margin:'5px 0px 0px 3px',color:'blue'}) 155 | .setUrl('https://code.earthengine.google.com/005680c8acf54715c9b10e946400d842'); 156 | var appUseText6 = ui.Label('.', 157 | {fontWeight: 'italic', fontSize: '14px', margin:'5px 0px 0px 0px'}); 158 | 159 | panel.add(appUseText1) 160 | .add((ui.Panel([appUseLink1, appUseText3, appUseLink2, appUseText4],ui.Panel.Layout.flow('horizontal'),{margin:'0 0 10px 0px'}))) 161 | .add((ui.Panel([appUseText5, appUseLink5, appUseText6],ui.Panel.Layout.flow('horizontal'),{margin:'0 0 10px 0px'}))) 162 | .add(dateLabel) 163 | .add((ui.Panel([startLabel, endLabel],ui.Panel.Layout.flow('horizontal')))) 164 | .add((ui.Panel([startDate_selected, endDate_selected],ui.Panel.Layout.flow('horizontal')))) 165 | .add(Landsat_collection_label) 166 | .add(selectCollection) 167 | .add(cloudSliderLabel) 168 | .add(cloudSlider) 169 | .add(GenerateImagesButton); 170 | 171 | // Define input parameters 172 | var startDate = startDate_selected.getValue(), 173 | endDate = endDate_selected.getValue(), 174 | collection = selectCollection.getValue(), // select "L8" or "L9" 175 | // selected_geometry = map.drawingTools().layers().get(0).toGeometry(), 176 | cloud_cover = ee.Number(cloudSlider.getValue()); 177 | 178 | var ROI = /* color: #98ff00 */ee.Geometry.Polygon( 179 | [[[21.134189623651263, 48.82947658234015], 180 | [21.134189623651263, 48.57888560664585], 181 | [21.433567065057513, 48.57888560664585], 182 | [21.433567065057513, 48.82947658234015]]], null, false); 183 | 184 | map.centerObject(ROI,12); 185 | map.drawingTools().addLayer([ROI], 'ROI', 'green') 186 | 187 | // Create a panel to hold the the next part. 188 | var panel2 = ui.Panel(); 189 | panel2.style().set({ 190 | width: '500px', 191 | position: 'bottom-right' 192 | }); 193 | panel.add(panel2); 194 | 195 | function generateImsButton () { 196 | panel2.clear(); 197 | var selected_geometry = map.drawingTools().layers().get(0).toGeometry(); 198 | // var selected_geometry = ROI; 199 | 200 | // Set image collection conditions 201 | if (selectCollection.getValue() == "Landsat 8 Image Collection") { 202 | var collection_id = "LANDSAT/LC08/C02/T1_L2"; 203 | } 204 | if (selectCollection.getValue() == "Landsat 9 Image Collection") { 205 | var collection_id = "LANDSAT/LC09/C02/T1_L2"; 206 | } 207 | //Select Landsat 8 Surface Reflectance dataset coverage 208 | var Landsat_collection = ee.ImageCollection(collection_id) //Select the ImageCollection 209 | .filterBounds(selected_geometry) //Filter the ImageCollection by your study area 210 | .filterDate(startDate_selected.getValue(), endDate_selected.getValue()) //Filter the ImageCollection by the date interval 211 | .filterMetadata("CLOUD_COVER", "less_than", ee.Number(cloudSlider.getValue())); //Filter the ImageCollection by the % of the cloud cover 212 | print(Landsat_collection, "- available Landsat images","that meet the input criteria"); /*Print available features (datasets) of Landsat_collection 213 | that meet the input criteria - see the results in the Console window*/ 214 | 215 | //Select Sentinel-2 Level-2A collection dataset coverage 216 | var S2_collection = ee.ImageCollection("COPERNICUS/S2_SR") 217 | .filterBounds(selected_geometry) 218 | .filterDate(startDate_selected.getValue(), endDate_selected.getValue()) 219 | .filterMetadata("CLOUDY_PIXEL_PERCENTAGE", "less_than", ee.Number(cloudSlider.getValue())); 220 | print(S2_collection, "- available Sentinel-2 images","that meet the input criteria"); 221 | 222 | var landsatList = Landsat_collection.toList(Landsat_collection.size()) 223 | var landsatImagesText = ""; 224 | 225 | if ((Landsat_collection.size().getInfo() > 0) && (S2_collection.size().getInfo()>0)) { 226 | for (var i=0; i