Compositing combines multiple images over time to create a single, cloud-free image. This is essential for creating reliable baselines from noisy data.
Learning objectives
- Create median, mean, and maximum composites.
- Understand when to use each compositing method.
- Build seasonal and annual composites.
- Use qualityMosaic for best-pixel selection.
Why it matters
No single image is perfect—clouds, shadows, and sensor artifacts contaminate individual scenes. Compositing merges the best information from many images into one clean result.
Key vocabulary
- Composite
- A single image created by combining multiple images over time.
- Median composite
- Each pixel takes the median value from the image stack—resistant to outliers.
- Quality mosaic
- Selects pixels from the image with the best quality score (e.g., highest NDVI).
Quick win: Summer median composite
Create a cloud-free summer composite from Landsat 8:
// Cloud masking function
function maskL8sr(image) {
var qaMask = image.select('QA_PIXEL').bitwiseAnd(1 << 3).eq(0)
.and(image.select('QA_PIXEL').bitwiseAnd(1 << 4).eq(0));
return image.updateMask(qaMask)
.multiply(0.0000275).add(-0.2);
}
// Load and filter collection
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
.filterDate('2023-06-01', '2023-08-31')
.filterBounds(ee.Geometry.Point([-82.3, 29.6]))
.filter(ee.Filter.lt('CLOUD_COVER', 30))
.map(maskL8sr);
// Create median composite
var composite = collection.median();
// Visualize
Map.centerObject(collection, 9);
Map.addLayer(composite, {
bands: ['SR_B4', 'SR_B3', 'SR_B2'],
min: 0,
max: 0.3
}, 'Summer 2023 Composite');
print('Images used:', collection.size());
What you should see
A cloud-free true color image representing typical summer conditions. The console shows how many images were combined.
Compositing methods compared
| Method | Best For | Caution |
|---|---|---|
.median() |
General purpose, cloud removal | May blur sharp features |
.mean() |
Smooth averages | Sensitive to outliers (clouds) |
.max() |
Peak greenness (NDVI) | May pick cloudy pixels |
.min() |
Minimum reflectance | Often picks shadows |
.mosaic() |
Latest/first pixel | No quality consideration |
.qualityMosaic() |
Best-pixel selection | Requires quality band |
Seasonal composites
Create composites for each season:
// Define seasons
var year = 2023;
var seasons = {
'Winter': [year + '-01-01', year + '-03-31'],
'Spring': [year + '-04-01', year + '-06-30'],
'Summer': [year + '-07-01', year + '-09-30'],
'Fall': [year + '-10-01', year + '-12-31']
};
// Function to create seasonal composite
var makeComposite = function(startDate, endDate) {
return ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
.filterDate(startDate, endDate)
.filterBounds(roi)
.map(maskL8sr)
.median();
};
// Create and add each season
var summerComp = makeComposite(seasons.Summer[0], seasons.Summer[1]);
var winterComp = makeComposite(seasons.Winter[0], seasons.Winter[1]);
Map.addLayer(summerComp, {bands: ['SR_B4','SR_B3','SR_B2'], min:0, max:0.3}, 'Summer');
Map.addLayer(winterComp, {bands: ['SR_B4','SR_B3','SR_B2'], min:0, max:0.3}, 'Winter');
Quality mosaic: Best-pixel compositing
Select pixels from the image with the best quality score:
// Add NDVI as quality band
var withNDVI = collection.map(function(img) {
var ndvi = img.normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI');
return img.addBands(ndvi);
});
// qualityMosaic selects pixels from the image
// with the highest value in the specified band
var greenest = withNDVI.qualityMosaic('NDVI');
Map.addLayer(greenest, {
bands: ['SR_B4', 'SR_B3', 'SR_B2'],
min: 0,
max: 0.3
}, 'Greenest Pixel Composite');
What you should see
A composite where each pixel comes from the date when vegetation was greenest.
Annual NDVI composite
Create a maximum NDVI composite for a full year:
// NDVI for each image
var ndviCollection = collection.map(function(img) {
return img.normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI');
});
// Maximum NDVI value at each pixel
var maxNDVI = ndviCollection.max();
Map.addLayer(maxNDVI, {
min: 0,
max: 0.8,
palette: ['brown', 'yellow', 'green']
}, 'Max Annual NDVI');
Pro tips
- Cloud mask first: Always apply cloud masking before compositing.
- Pre-filter: Use
.filter(ee.Filter.lt('CLOUD_COVER', 30))to speed up processing. - Check image count: Print
collection.size()to ensure enough images. - Seasonal windows: Match your compositing window to your analysis needs.
- qualityMosaic for dates: Add a date band to track which date each pixel came from.
Try it: Track the date of each pixel
// Add date band (days since epoch)
var withDate = collection.map(function(img) {
var date = ee.Image.constant(img.date().millis().divide(86400000))
.rename('date').toFloat();
var ndvi = img.normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI');
return img.addBands(ndvi).addBands(date);
});
// Get greenest pixel composite with date
var best = withDate.qualityMosaic('NDVI');
Map.addLayer(best.select('date'), {min: 19500, max: 19600}, 'Date of Greenest');
Common mistakes
- Compositing without cloud masking (clouds contaminate result).
- Using mean instead of median for cloudy regions.
- Time window too short (not enough clean pixels).
- Not checking how many images are in the collection.
- Mixing sensors without harmonizing (Landsat 8 vs Sentinel-2).
Quick self-check
- Why is median often better than mean for compositing?
- What does qualityMosaic use to select pixels?
- When would you use max compositing?
- What should you always do before compositing optical imagery?