What You'll Learn
- Calculate NBR from Landsat NIR and SWIR bands
- Compute dNBR (delta NBR) from pre- and post-fire imagery
- Classify burn severity using USGS thresholds
- Summarize burned area by severity class within fire perimeters
- Export burn severity maps and statistics
Why This Matters
Burn severity mapping supports wildfire management:
- Recovery planning: High-severity areas need different restoration strategies
- Erosion risk: Burned areas are vulnerable to debris flows and floods
- Carbon accounting: Fires release stored carbon to the atmosphere
- Insurance/damage assessment: Quantify impacts for recovery funding
Before You Start
- Prerequisites: Understand spectral indices and image differencing.
- Estimated time: 75 minutes
- Materials: Earth Engine account and a known fire event with perimeter data.
Key Terms
- NBR (Normalized Burn Ratio)
- A spectral index using NIR and SWIR bands that is sensitive to vegetation moisture and burn severity: (NIR - SWIR2) / (NIR + SWIR2)
- dNBR (delta NBR)
- The difference between pre-fire and post-fire NBR. Positive values indicate burn severity.
- Burn Severity
- The degree to which fire has altered an ecosystem, from unburned to high severity.
- MTBS
- Monitoring Trends in Burn Severity - a USGS/USFS program providing burn severity data for the US.
USGS Burn Severity Thresholds
| Class | dNBR Range | Description |
|---|---|---|
| 0 | < 0.1 | Unburned/Low regrowth |
| 1 | 0.1 - 0.27 | Low severity |
| 2 | 0.27 - 0.44 | Moderate-low severity |
| 3 | 0.44 - 0.66 | Moderate-high severity |
| 4 | > 0.66 | High severity |
Step 1: Define AOI and Date Ranges
Set up your study area and pre/post fire dates:
// AOI and dates (adjust for your fire)
var aoi = ee.Geometry.Rectangle([-118.2, 34.1, -117.5, 34.4]);
Map.centerObject(aoi, 10);
// Pre-fire: before ignition
var preStart = '2020-07-01';
var preEnd = '2020-08-31';
// Post-fire: after containment, before vegetation recovery
var postStart = '2020-10-01';
var postEnd = '2020-11-30';
Step 2: Calculate NBR
Create a function to mask clouds and calculate NBR:
// Mask clouds and shadows using QA_PIXEL
function maskL2(img) {
var qa = img.select('QA_PIXEL');
var cloud = qa.bitwiseAnd(1 << 3).neq(0);
var shadow = qa.bitwiseAnd(1 << 4).neq(0);
var mask = cloud.or(shadow).not();
return img.updateMask(mask);
}
// Calculate NBR from Landsat
function prep(img){
var sr = maskL2(img);
var nir = sr.select('SR_B5').multiply(0.0000275).add(-0.2);
var sw2 = sr.select('SR_B7').multiply(0.0000275).add(-0.2);
var nbr = nir.subtract(sw2).divide(nir.add(sw2)).rename('NBR');
return nbr.copyProperties(img, img.propertyNames());
}
// Load Landsat 8 and create pre/post NBR composites
var L = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2').filterBounds(aoi);
var pre = L.filterDate(preStart, preEnd).map(prep).median().clip(aoi);
var post = L.filterDate(postStart, postEnd).map(prep).median().clip(aoi);
Map.addLayer(pre, {min:-1, max:1, palette:['#1a9850','#ffffbf','#d73027']}, 'NBR pre');
Map.addLayer(post,{min:-1, max:1, palette:['#1a9850','#ffffbf','#d73027']}, 'NBR post');
Step 3: Calculate dNBR and Classify Severity
// Calculate delta NBR
var dnbr = pre.subtract(post).rename('dNBR');
Map.addLayer(dnbr, {min:-0.2, max:1, palette:['#2c7bb6','#ffff8c','#d7191c']}, 'dNBR');
// Classify burn severity using USGS thresholds
var sev = dnbr.expression(
'b(0) <= 0.1 ? 0 : ' +
'b(0) <= 0.27 ? 1 : ' +
'b(0) <= 0.44 ? 2 : ' +
'b(0) <= 0.66 ? 3 : 4'
).rename('severity');
Map.addLayer(sev, {
min: 0, max: 4,
palette: ['#1a9641','#ffffbf','#fdae61','#d7191c','#a50026']
}, 'Severity classes');
Step 4: Summarize Area by Severity Class
// Fire perimeter (replace with actual perimeter if available)
var perimeter = aoi; // Use actual fire perimeter FeatureCollection
// Calculate area (hectares) by severity class
var areaImg = ee.Image.pixelArea().divide(10000).addBands(sev);
var byClass = areaImg.reduceRegion({
reducer: ee.Reducer.sum().group({groupField: 1, groupName: 'severity'}),
geometry: perimeter,
scale: 30,
maxPixels: 1e9
});
print('Area (ha) by severity class', byClass);
Step 5: Export Results
// Convert grouped dictionary to FeatureCollection for CSV export
var groups = ee.List(byClass.get('groups'));
var table = ee.FeatureCollection(groups.map(function(g){
g = ee.Dictionary(g);
return ee.Feature(null, {
severity: g.get('severity'),
area_ha: g.get('sum')
});
}));
// Export table as CSV
Export.table.toDrive({
collection: table,
description: 'burn_severity_area_by_class',
fileFormat: 'CSV'
});
// Export dNBR as GeoTIFF
Export.image.toDrive({
image: dnbr,
description: 'dnbr_geotiff',
region: aoi,
scale: 30,
maxPixels: 1e13
});
Check Your Understanding
- Why do we use SWIR bands in the NBR calculation?
- What would a negative dNBR value indicate?
- Why is timing of post-fire imagery important?
- How might topography affect burn severity patterns?
Troubleshooting
Problem: Pre-fire NBR shows burn scars
Solution: Check your pre-fire dates - they may overlap with an earlier fire. Adjust date range.
Problem: High dNBR values appear in water bodies
Solution: Add a water mask using the JRC Global Surface Water dataset.
Problem: Clouds in post-fire composite
Solution: Extend the date range or use a different cloud masking approach.
Pro Tips
- Use MTBS data: Compare your results to official MTBS burn severity maps
- Consider RdNBR: Relativized dNBR normalizes by pre-fire NBR for more consistent results
- Multiple fires: Use fire perimeter datasets (NIFC, CalFire) for specific events
- Time series: Track post-fire vegetation recovery over multiple years
?? Lab Submission
Subject: Lab 30 - Wildfire Analysis - [Your Name]
Submit:
- Map layers: NBR pre/post, dNBR, and severity classes
- Table: area (hectares) by severity class within fire perimeter
- Short discussion: Note any unburned/low-severity islands and likely drivers
- EE script URL and exported CSV