π Method 2: Direct Download via Python¶
π Perfect for Automated Workflows
Ideal for users without Earth Engine access - download pre-processed country-level data
π¦ Prerequisites & Installation¶
### π οΈ **Required Libraries**
# π» Install required packages
pip install google-cloud-storage geopandas rasterio matplotlib numpy
π‘ Pro Tip
Create a virtual environment to avoid conflicts:
python -m venv building_heights_env
π₯ Step 1: Download Country Data¶
π Complete Download Script¶
import os
import requests
import zipfile
import geopandas as gpd
import rasterio
from rasterio.plot import show
import matplotlib.pyplot as plt
import numpy as np
def download_country_data(country_code, year, output_dir):
"""
π Download Open Buildings 2.5D data for a specific country and year
Parameters:
-----------
country_code : str
ISO 3-letter country code (e.g., 'GHA' for Ghana)
year : int
Year between 2016-2023
output_dir : str
Directory to save downloaded files
Returns:
--------
str: Path to downloaded GeoTIFF file
"""
# π Create output directory
os.makedirs(output_dir, exist_ok=True)
# π Construct GCS path
base_url = "gs://open-buildings-temporal/v1"
gcs_path = f"{base_url}/{country_code}_{year}.tif"
# π₯ Download using gsutil (requires Google Cloud SDK)
print(f"π₯ Downloading {country_code} data for {year}...")
os.system(f"gsutil cp {gcs_path} {output_dir}/")
downloaded_file = f"{output_dir}/{country_code}_{year}.tif"
if os.path.exists(downloaded_file):
print(f"β
Successfully downloaded: {downloaded_file}")
return downloaded_file
else:
print(f"β Download failed for {country_code}_{year}")
return None
ποΈ Alternative: HDX Portal Method¶
π Manual Download Steps
1. **π Visit HDX Portal**: [https://data.humdata.org/dataset/google-open-buildings-temporal](https://data.humdata.org/dataset/google-open-buildings-temporal) 2. **π Download Resources**: - Country list CSV - Download script - Documentation 3. **π§ Setup Google Cloud SDK**:π Step 2: Process Downloaded Data¶
π Extract Building Heights Function¶
def extract_building_heights(tif_path, confidence_threshold=0.5):
"""
ποΈ Extract building heights from downloaded GeoTIFF
Parameters:
-----------
tif_path : str
Path to the downloaded GeoTIFF file
confidence_threshold : float
Minimum confidence for building presence (0-1)
Returns:
--------
tuple: (height_array, metadata_profile)
"""
print(f"π Processing: {tif_path}")
with rasterio.open(tif_path) as src:
# π Read all bands
presence = src.read(1) # Band 1: building_presence
height = src.read(2) # Band 2: building_height
count = src.read(3) # Band 3: building_fractional_count
# π― Apply confidence mask
height_masked = np.where(presence > confidence_threshold, height, np.nan)
# π Get metadata
metadata = {
'crs': src.crs,
'bounds': src.bounds,
'resolution': src.res,
'height': src.height,
'width': src.width,
'transform': src.transform
}
print(f"π CRS: {metadata['crs']}")
print(f"π Bounds: {metadata['bounds']}")
print(f"π Resolution: {metadata['resolution']}")
print(f"π Dimensions: {metadata['height']} x {metadata['width']}")
# π Basic statistics
valid_heights = height_masked[~np.isnan(height_masked)]
if len(valid_heights) > 0:
print(f"π Height Statistics:")
print(f" Min: {valid_heights.min():.2f}m")
print(f" Max: {valid_heights.max():.2f}m")
print(f" Mean: {valid_heights.mean():.2f}m")
print(f" Buildings detected: {len(valid_heights):,} pixels")
return height_masked, metadata, src.profile
π¨ Step 3: Visualization Functions¶
π Advanced Visualization Script¶
def create_height_visualization(height_array, metadata, country_code, year):
"""
π¨ Create stunning building height visualizations
Parameters:
-----------
height_array : numpy.ndarray
Array of building heights
metadata : dict
Spatial metadata from rasterio
country_code : str
Country code for title
year : int
Year for title
"""
# π¨ Set up the plot style
plt.style.use('dark_background')
fig, axes = plt.subplots(2, 2, figsize=(16, 12))
fig.suptitle(f'ποΈ Building Heights Analysis: {country_code} {year}',
fontsize=20, fontweight='bold', color='white')
# π Main height visualization
ax1 = axes[0, 0]
im1 = ax1.imshow(height_array, cmap='viridis', vmin=0, vmax=50, aspect='auto')
ax1.set_title('ποΈ Building Heights', fontsize=14, color='white')
ax1.set_xlabel('Longitude β', color='white')
ax1.set_ylabel('Latitude β', color='white')
plt.colorbar(im1, ax=ax1, label='Height (m)')
# π₯ Heat map style
ax2 = axes[0, 1]
im2 = ax2.imshow(height_array, cmap='hot', vmin=0, vmax=30, aspect='auto')
ax2.set_title('π₯ Heat Map Style', fontsize=14, color='white')
ax2.set_xlabel('Longitude β', color='white')
ax2.set_ylabel('Latitude β', color='white')
plt.colorbar(im2, ax=ax2, label='Height (m)')
# π Height histogram
ax3 = axes[1, 0]
valid_heights = height_array[~np.isnan(height_array)]
if len(valid_heights) > 0:
ax3.hist(valid_heights, bins=50, color='#00ff7f', alpha=0.7, edgecolor='white')
ax3.set_title('π Height Distribution', fontsize=14, color='white')
ax3.set_xlabel('Height (m)', color='white')
ax3.set_ylabel('Frequency', color='white')
ax3.tick_params(colors='white')
# π’ Building categories
ax4 = axes[1, 1]
if len(valid_heights) > 0:
categories = ['Low (0-5m)', 'Mid (5-15m)', 'High (15-30m)', 'Very High (30m+)']
counts = [
np.sum((valid_heights >= 0) & (valid_heights < 5)),
np.sum((valid_heights >= 5) & (valid_heights < 15)),
np.sum((valid_heights >= 15) & (valid_heights < 30)),
np.sum(valid_heights >= 30)
]
colors = ['#4CAF50', '#FF9800', '#F44336', '#9C27B0']
wedges, texts, autotexts = ax4.pie(counts, labels=categories, colors=colors,
autopct='%1.1f%%', startangle=90)
ax4.set_title('π’ Building Categories', fontsize=14, color='white')
# Style the text
for text in texts:
text.set_color('white')
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontweight('bold')
plt.tight_layout()
plt.savefig(f'building_heights_{country_code}_{year}.png',
dpi=300, bbox_inches='tight', facecolor='black')
plt.show()
def export_processed_data(height_array, metadata, output_path):
"""
πΎ Export processed height data as GeoTIFF
Parameters:
-----------
height_array : numpy.ndarray
Processed height array
metadata : dict
Spatial metadata
output_path : str
Output file path
"""
profile = {
'driver': 'GTiff',
'dtype': 'float32',
'nodata': np.nan,
'width': metadata['width'],
'height': metadata['height'],
'count': 1,
'crs': metadata['crs'],
'transform': metadata['transform'],
'compress': 'lzw'
}
with rasterio.open(output_path, 'w', **profile) as dst:
dst.write(height_array.astype('float32'), 1)
print(f"πΎ Exported processed data to: {output_path}")
π Complete Usage Example¶
# π Configuration
country_code = "GHA" # Ghana
year = 2023
output_dir = "./open_buildings_data"
# π₯ Download data
print("π Starting building heights extraction...")
tif_path = download_country_data(country_code, year, output_dir)
if tif_path:
# π Process the data
heights, metadata, profile = extract_building_heights(tif_path, confidence_threshold=0.6)
# π¨ Create visualizations
create_height_visualization(heights, metadata, country_code, year)
# πΎ Export processed data
export_path = f"{output_dir}/processed_heights_{country_code}_{year}.tif"
export_processed_data(heights, metadata, export_path)
print("β
Processing complete! Check the output directory for results.")
else:
print("β Failed to download data. Please check your internet connection and try again.")
π§ Troubleshooting¶
π¨ Common Issues
- gsutil not found: Install Google Cloud SDK
- Permission denied: Run
gcloud auth login
- Large memory usage: Process smaller regions or reduce resolution
π‘ Pro Tips
- Batch processing: Loop through multiple countries/years
- Memory optimization: Use chunked processing for large files
- Quality control: Always check confidence thresholds
π Python Method Mastered!
You can now automate building height extraction for entire countries!