Extracting Building Heights from Open Buildings 2.5D Temporal Dataset

In this post, you will learn how to work with the Open Buildings 2.5D Temporal data and download it for many useful downstream applications, such as Visibility Analysis, Population Modeling, and 3D Visualization.

Google has two important large-scale AI-derived open building datasets:

  • Open Buildings V3 Polygons: This was released a few years ago and contains all buildings polygons detected from Google’s corpus of high-resolution imagery. You can read more about it in our post Mapping Building Density with Open Building Datasets.
  • Open Buildings 2.5D Temporal V1: This is a newer dataset that aims to extract useful attributes for buildings such as year of construction and building height. Since this data is derived from open-source medium-resolution Sentinel-2 imagery, it has temporal coverage from 2016-2023. A deep learning model was trained to predict building heights from Sentinel-2 images, so we also get the height information each year.

We will cover a Google Earth Engine workflow to process this data to make it usable in a GIS environment and extract a high-resolution Digital Surface Model (DSM). We will also see how to combine the Open Buildings V3 polygon building footprints with the Open Buildings 2.5D Temporal V1 data to create and extract yearly polygon datasets containing building heights that can be used in a GIS environment.

Open Buildings 2.5D Temporal Data Combined with Open Buildings V3 Polygons and Visualized in QGS

The post is divided into the following sections.

  • Part 1: Extracting Building Height Raster and High-Resolution DSM
  • Part 2: Extracting Building Footprints with Heights

Part 1: Extracting Building Height Raster and High-Resolution DSM

Many parts of the world lack open-access high-resolution Digital Surface Models (DSMs). The Open Buildings 2.5D Temporal dataset provides a raster layer of building heights at 4m spatial resolution. Combined with a bare-earth Digitial Elevation Model (DEM) and Tree Canopy Height data, you can derive a high-resolution DSM that is a great proxy for a LIDAR-derived DSM for urban analysis. The building heights are available across Africa, South Asia, South-East Asia, Latin America, and the Caribbean.

Coverage of the Open Buildigns 2.5D Temporal Dataset

We start by defining a region of interest. You can draw a polygon using the drawing tools in the Code Editor. You may also use any of your uploaded assets and use their geometry.

The drawn polygon is saved as the variable geometry.

Next, we define a year for data extraction and filter the collection to find matching tiles.

var openBuildingsTemporal = ee.ImageCollection(
  'GOOGLE/Research/open-buildings-temporal/v1');
var year = 2023;
var startDate = ee.Date.fromYMD(year, 1, 1);
var endDate = startDate.advance(1, 'year');
var filtered = openBuildingsTemporal
  .filter(ee.Filter.date(startDate, endDate))
  .filter(ee.Filter.bounds(geometry));
print('Image Tiles', filtered);

If your region is large, you may have more than 1 matching tiles. We need to mosaic the tiles to get a single image. In Earth Engine, composites or mosaics lose their original projection and instead assigned the default projection (EPSG:4326). We need to retain the original UTM projection in the output image. The building heights are in meters and keeping the images in a UTM projection ensures we get the X and Y coordinates also in meters. We extract the original project and then use the setDefaultProjection() function to assign the same to the mosaic.

var projection = filtered.first().projection();
var buildingsMosaic = filtered.mosaic()
  .setDefaultProjection(projection);
print('Open Buildings Temporal Image Mosaic',
  buildingsMosaic);

The images contain 3 bands. We select the building_height band and visualize it.

// Select the building_height band
var buildingHeights = buildingsMosaic
  .select('building_height');
// Visualize the heights
var heightPalette = [
    '1d4877', '1b8a5a', 'fbb021', 'f68838', 'ee3e32'];
var heightVisParams = {min:0, max:50, palette: heightPalette};
Map.centerObject(geometry);
Map.addLayer(buildingHeights.clip(geometry),
  heightVisParams, 'Building Heights');

The pixels in the images have values equal to the detected building height above existing terrain. To create a Digital Surface Model (DSM), we need to add the tree canopy height and terrain height at each pixel. We can do this easily in GEE with any of the available datasets. Below are the global high-resolution open datasets that we can use

  • High Resolution 1m Global Canopy Height Maps by Meta/WRI: A Global AI-derived canopy heights at 1m spatial resolution. The data is derived from imagery between 2018-2020.
  • FABDEM (Forest And Buildings removed Copernicus 30m DEM): A 30m global DEM derived from GLO-30 DEM.

You can substitute the above with any other dataset of your choice. You can also skip this part and export the Building Heights Raster, which can be used in a Desktop GIS to combine with your own DEM.

// Add Canopy Height
var canopyHeight = ee.ImageCollection(
  'projects/meta-forest-monitoring-okw37/assets/CanopyHeight')
  .mosaic()
  .rename('canopy_height');
var treeMask = canopyHeight.updateMask(canopyHeight.gte(1));
var treeHeight = treeMask.unmask(0);

// Add tree height to the building height
var buildingsAndTrees = buildingHeights.add(treeHeight);

// Add Terrain Height
var fabdem = ee.ImageCollection(
  'projects/sat-io/open-datasets/FABDEM');

var fabdemFiltered = fabdem
  .filter(ee.Filter.bounds(geometry));
// We extract the projection information an original tile
// which we will assign to the mosaic
var fabdemProjection = fabdemFiltered.first().projection();

var fabdemMosaic = fabdem.mosaic()
  .setDefaultProjection(fabdemProjection);
var dem = fabdemMosaic.select('b1');

// Optionally resample the DEM for smoother
// output at higher resoluton
// 'bicubic' will be more aggresive smoothing
// Uncomment the line below to apply resampling

// dem = dem.resample('bilinear');

// Add terrain height to building heights
var dsm = buildingsAndTrees.add(dem);

Let’s export the images as GeoTIFF files. While the original images are provided at a 0.5m resolution, the effective spatial resolution of the heights is 4m.

var buildingResolution = 4;

// Export the Buildings Heights Raster
Export.image.toDrive({
  image: buildingHeights.clip(geometry),
  description: 'Building_Height_Raster_' + year,
  folder: 'earthengine',
  fileNamePrefix: 'building_height_raster_' + year,
  region: geometry,
  scale: buildingResolution
});

// Export the DSM
Export.image.toDrive({
  image: dsm.clip(geometry),
  description: 'DSM_' + year,
  folder: 'earthengine',
  fileNamePrefix: 'dsm_' + year,
  region: geometry,
  scale: buildingResolution
});

Start the export tasks. Once the tasks are complete, the resulting GeoTIFF files will be added to your Google Drive. You can download and use it in your favorite GIS software. Here’s the exported DSM for the year 2023 loaded and visualized in QGIS.

This exported high-resolution DSM can be used for Visibility Analysis in QGIS. You can check out the excellent tutorial How to run visibility analysis in QGIS by Helen McKenzie for step-by-step instructions.

Part 2: Extracting Building Footprints with Heights

The heights data is more useful in the vector format. We can join the building footprint polygons from the Open Buildings V3 polygons with the Open Buildings 2.5D Temporal Layers to obtain a temporal building footprints with height.

var openBuildingsPolygons = ee.FeatureCollection(
  'GOOGLE/Research/open-buildings/v3/polygons');
var allBuildings  = openBuildingsPolygons
  .filter(ee.Filter.bounds(geometry));

This dataset does not have any temporal information. We need to filter out buildings not present in the chosen year by extracting temporal information from the Open Buildings Temporal dataset. We do a Zonal Statistics operation using the reduceRegions() function to find the average building_presence probability and height values within each polygon. We then filter out polygons with low presence values to locate the buildings present for the chosen year.

var temporalBands = buildingsMosaic.select([
  'building_presence', 'building_height']);
// Extract the presence score and building height
// for each polygon
var allBuildingsData = temporalBands.reduceRegions({
  collection: allBuildings,
  reducer: ee.Reducer.mean(),
  scale: buildingResolution,
  tileScale: 16,
});
// Select buildings with high building_presence score
var buildingsFiltered = allBuildingsData
  .filter(ee.Filter.gt('building_presence', 0.5));

At this point we have extracted the building polygons for the chosen year and added a property to each polygon with average height of pixels within each polygon. The Open Buildings V3 polygons are in EPSG:4326 CRS. Before exporting, we reproject the data to the original UTM projection of the building heights data.

var buildingsReprojected = buildingsFiltered
  .map(function(f) {
    return f.transform({
      proj: projection, 
      maxError: 0.1});
});

We have many properties from the original polygon data along with those extracted from temporal layers Some properties such as longitude_latitude are stored as point objects which cannot be exported to external vector formats. We select the numeric properties we want to export and rename them to ensure they are compliant within the limitations of the shapefile format.

var selectedProperties = ['area_in_meters', 'building_height'];
var renamedProperties = ['area', 'height'];
var buildingsExport = buildingsReprojected.select(
  selectedProperties, renamedProperties);

Finally we export the processed data as a shapefile.

Export.table.toDrive({
  collection: buildingsExport,
  description: 'Building_Polygons_with_Height_' + year,
  folder: 'earthengine',
  fileNamePrefix: 'building_polygons_with_height_' + year,
  fileFormat: 'SHP',
  selectors: renamedProperties
});

We can load the resulting shapefile in QGIS. Each polygon has the height information as an attribute.

You can also visualize the buildings using the 2.5D renderer. Check out our step-by-step tutorial for more creative ways to visualize this data.

The full script can be accessed using this link https://code.earthengine.google.co.in/224db6d61bde64e371e8f20b6f9b821d

I would love to hear your feedback on the quality and usefulness of this dataset. If you have used this dataset and want to share your opinion, please comment on this post below.

4 Comments

Leave a Comment

Leave a Reply