Building Footprints

Building footprints serve as the foundational data for generating any building inventory with BRAILS++. Users may supply their own footprint datasets or leverage BRAILS++’s capabilities to create an inventory from scratch. BRAILS++ includes four footprint scraper classes that enable automatic retrieval of footprint data from online sources:

  1. MS_FootprintScraper using Microsoft Footprint Database

  2. OSM_FootprintScraper using Open Street Maps (OSM)

  3. USA_FootprintScraper using USA Structures

  4. OvertureMapsFootprintScraper using Overture Maps

Each of these scraper classes implements a method get_footprints, which returns the building footprints for a given RegionBoundary instance. The example below demonstrates how three different scraper classes can be used interchangeably to generate building inventories for a specified location when running the script.

  1# Written: fmk 4/24
  2# Modified: bacetiner 12/24
  3# License: BSD-2
  4
  5"""
  6brails_footprint.py
  7===================
  8
  9This is a simple BRAILS example to demonstrate different methods to obtain
 10building inventories for an area.
 11
 12"""
 13import argparse
 14from brails.utils.importer import Importer
 15
 16
 17def download_footprints(location):
 18    """
 19    Download and analyze building footprint data for a specified location.
 20
 21    Args:
 22        location (str):
 23            The name of the geographic region for which building footprints
 24            are to be downloaded. This is used to specify the boundary region.
 25
 26    Functionality:
 27        1. Initializes a boundary region for the given location.
 28        2. Retrieves building footprints from:
 29           - OpenStreetMap using the `OSM_FootprintScraper`.
 30           - Microsoft Building Footprints data using the
 31            `MS_FootprintScraper`.
 32           - FEMA USA Structures database using the `USA_FootprintScraper`.
 33        3. Prints a summary of the number of buildings retrieved from each
 34           source.
 35        4. Extracts and prints details for a small random subset of the
 36           retrieved footprints from each data source for verification and
 37           sampling.
 38
 39    Prints:
 40        - The number of buildings found in each dataset.
 41        - Information about small random subsets of the inventories for OSM,
 42          Microsoft, and FEMA USA Structures data sources.
 43
 44    Note:
 45        The function uses an `Importer` class to dynamically load the required
 46        scraper classes.
 47        The random sampling is performed to give a quick overview of the data
 48        quality and coverage without loading the full dataset.
 49    """
 50    # Create an Importer to get the classes:
 51    importer = Importer()
 52
 53    # Specify the BoundaryRegion:
 54    region_boundary_class = importer.get_class("RegionBoundary")
 55    region_boundary_object = region_boundary_class(
 56        {"type": "locationName", "data": location})
 57
 58    # Get footprints using OpenStreetMap:
 59    print("Using OSM_FootprintsScraper...")
 60
 61    osm_class = importer.get_class("OSM_FootprintScraper")
 62    osm_scraper = osm_class({"length": "ft"})
 63    osm_inventory = osm_scraper.get_footprints(region_boundary_object)
 64
 65    # Get footprints using Microsoft Building Footprints data:
 66    print("\nUsing Microsoft Footprint Database...")
 67
 68    ms_class = importer.get_class("MS_FootprintScraper")
 69    ms_scraper = ms_class({"length": "ft"})
 70    ms_inventory = ms_scraper.get_footprints(region_boundary_object)
 71
 72    # Get footprints from FEMA USA Structures database:
 73    print("\nUsing USA_FootprintsScraper...")
 74
 75    usa_class = importer.get_class("USA_FootprintScraper")
 76    usa_scraper = usa_class({"length": "ft"})
 77    usa_inventory = usa_scraper.get_footprints(region_boundary_object)
 78
 79    # Print number of buildings found:
 80    seperator = '-' * 27
 81    print('\n\n')
 82    print(seperator)
 83    print(f"{'Scraper':<15}  {'# building':<10}")
 84    print(seperator)
 85    print(f"{'OSM':<15}  {len(osm_inventory.inventory):<10}")
 86    print(f"{'Microsoft':<15}  {len(ms_inventory.inventory):<10}")
 87    print(f"{'USA':<15}  {len(usa_inventory.inventory):<10}")
 88    print(seperator)
 89
 90    # Test obtaining a smaller random subset of each, method needed as we will
 91    # not always want to get all the images. Print to see what we are getting
 92    # from each:
 93    print('\n\nSmall Subset of USA Inventory: ')
 94    small_inventory = usa_inventory.get_random_sample(2, 200)
 95    small_inventory.print_info()
 96
 97    print('\n\nSmall Subset of OSM Inventory: ')
 98    small_inventory = osm_inventory.get_random_sample(2, 200)
 99    small_inventory.print_info()
100
101    print('\n\nSmall Subset of MS Inventory: ')
102    small_inventory = ms_inventory.get_random_sample(2, 200)
103    small_inventory.print_info()
104
105
106if __name__ == '__main__':
107    # Set up command-line arguments:
108    parser = argparse.ArgumentParser(description='Download footprints for a '
109                                     'specified location using BRAILS++ '
110                                     'footprint scrapers.')
111    parser.add_argument('location', type=str, nargs='?', default='Tiburon, CA',
112                        help="Name of the location to analyze.")
113
114    # Parse the command-line arguments:
115    args = parser.parse_args()
116
117    # Get the building footprints for the specified location:
118    download_footprints(args.location)

To run the example in brails_footprint.py for the location Berkeley, CA, use the following command

python3 brails_footprint.py "Berkeley, CA"

The example will print out the number of buildings obtained for each scraper.

---------------------------
Scraper          # building
---------------------------
OSM              35547
Microsoft        29469
USA              28404
---------------------------

When run, the example also prints a two-inventory subset of the data retrieved by each footprint scraper. As shown below, the features obtained for each asset vary between scrapers.

 1Small Subset of USA Inventory: 
 2AssetInventory
 3Inventory stored in:  dict
 4Key:  1494 Asset:
 5	 Coordinates:  [[-122.251349037992, 37.8918864620566], [-122.251516845084, 37.8918428029327], [-122.251549765644, 37.8919222669851], [-122.251381955857, 37.891965925353], [-122.251349037992, 37.8918864620566]]
 6	 Features:  {'type': 'Building', 'buildingheight': 17.4, 'fpAreas': 1554}
 7Key:  6666 Asset:
 8	 Coordinates:  [[-122.249638045616, 37.8518085710136], [-122.249704555083, 37.8517353439222], [-122.249817801199, 37.8518000117672], [-122.249751291732, 37.8518732380851], [-122.249638045616, 37.8518085710136]]
 9	 Features:  {'type': 'Building', 'buildingheight': 21.6, 'fpAreas': 1326}
10
11
12Small Subset of OSM Inventory: 
13AssetInventory
14Inventory stored in:  dict
15Key:  2989 Asset:
16	 Coordinates:  [[-122.2539358, 37.8823889], [-122.2538841, 37.8822577], [-122.2538636, 37.882258], [-122.2538454, 37.8821659], [-122.2540379, 37.8821623], [-122.2540337, 37.8822459], [-122.2539784, 37.882245], [-122.2540264, 37.8823667], [-122.2539358, 37.8823889]]
17	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 1, 'roofshape': 'NA', 'fpAreas': 2973}
18Key:  13333 Asset:
19	 Coordinates:  [[-122.2743673, 37.8721826], [-122.2743469, 37.8720391], [-122.2743897, 37.8720353], [-122.2743867, 37.8720143], [-122.2744387, 37.8720097], [-122.2744416, 37.8720305], [-122.2744612, 37.8720287], [-122.2744816, 37.8721725], [-122.2743673, 37.8721826]]
20	 Features:  {'type': 'Building', 'buildingheight': 'NA', 'erabuilt': 'NA', 'numstories': 'NA', 'roofshape': 'NA', 'fpAreas': 1866}
21
22
23Small Subset of MS Inventory: 
24AssetInventory
25Inventory stored in:  dict
26Key:  1494 Asset:
27	 Coordinates:  [[-122.2832593562512, 37.8673577272146], [-122.2831763030742, 37.86735994820125], [-122.2831818391027, 37.86748896307548], [-122.2832648922797, 37.86748674209271], [-122.2832593562512, 37.8673577272146]]
28	 Features:  {'type': 'Building', 'buildingheight': 13.4, 'fpAreas': 1129}
29Key:  6666 Asset:
30	 Coordinates:  [[-122.28236720333845, 37.86313236995723], [-122.2823711059354, 37.86320635580323], [-122.28259869901714, 37.86319887333546], [-122.28259568844234, 37.86314179854076], [-122.28253945956331, 37.86314364715192], [-122.28253856754118, 37.863126736093584], [-122.28236720333845, 37.86313236995723]]
31	 Features:  {'type': 'Building', 'buildingheight': 19.1, 'fpAreas': 1675}

Footprint Notebook

Here is a link to a Jupyter Notebook that runs the basic code, accompanied by graphics to better illustrate the output.

Note

  1. The number of buildings varies across datasets due to differences in data sources, processing methods, geographic coverage, and update frequency. Since no dataset is perfect, users are encouraged to compare building inventories for their area of interest by overlaying them with satellite imagery to verify accuracy.

  2. OSM is a community-driven platform where volunteers manually contribute building footprints using ground surveys, GPS data, and licensed aerial imagery. Data quality varies by region and contributor activity, with particularly active communities in non-urban areas. Some buildings may have NA values where community data is not yet available.

  3. OSM, Microsoft Footprints, and Overture Maps provide global coverage, whereas USA Structures is limited to the United States.

  4. OSM data is updated in real time by contributors; Microsoft and Overture Maps datasets are updated periodically; USA Structures updates occur infrequently.