Rasterize OpenStreetMap vector features into GeoTIFF rasters
Project description
osm-rasterizer
Convert OpenStreetMap vector features into GeoTIFF rasters. Define feature classes using OSM tags, specify a bounding box and resolution, and get a multi-band or single-layer categorical raster as output.
Installation
Requires Python 3.12+ and uv.
git clone https://github.com/your-org/osm-rasterizer
cd osm-rasterizer
uv sync
Usage
uv run main.py \
--bbox "minx,miny,maxx,maxy" \
--feature 'name:{"osm_key": "value"}' \
--output output.tif \
--resolution 10
Or using the installed script entry point:
osm-rasterizer --bbox ... --feature ... --output ...
Options
| Option | Short | Default | Description |
|---|---|---|---|
--bbox |
-b |
required | Bounding box as minx,miny,maxx,maxy in WGS84 (EPSG:4326) |
--feature |
-f |
required | OSM feature spec (repeatable, see below) |
--output |
-o |
required | Output GeoTIFF path |
--resolution |
-r |
10.0 |
Pixel size in metres |
--single-layer |
False |
Merge all features into one categorical band | |
--fill-nodata |
False |
Fill empty pixels from nearest labelled neighbour | |
--fill-nodata-distance |
unlimited | Max fill distance in pixels (prevents border flooding) | |
--crs |
auto | Output CRS, e.g. EPSG:32630. Auto-detected as best-fit UTM if omitted |
Feature spec format
Each --feature argument is either a bare JSON tag dict or a named spec:
'{"key": value}' # unnamed — name inferred from tags
'name:{"key": value}' # named band/category
Tag values follow the osmnx convention:
'{"building": true}' # any feature with a "building" tag
'{"highway": "residential"}' # exact value match
'{"highway": ["primary", "secondary"]}' # any of these values
Output modes
Multi-band (default): one uint8 band per feature, values 0 (absent) or 1 (present).
Single-layer (--single-layer): one uint8 band with 1-based category indices (0 = no data). Features listed later take priority when areas overlap. Order your features from least to most important.
Band names are stored in the GeoTIFF metadata under the BAND_NAMES tag. In single-layer mode, category names are stored under CATEGORIES.
Example: Cambridge land cover
uv run main.py \
--bbox "-0.24786388455006128, 52.242894345312415, 0.10397291341351336, 52.34506356709806" \
--feature 'bare_ground:{"natural": ["bare_rock", "sand", "scree"], "landuse": ["quarry", "brownfield"]}' \
--feature 'cropland:{"landuse": ["farmland", "orchard", "allotments", "greenhouse_horticulture"]}' \
--feature 'grassland:{"natural": "grassland", "landuse": ["grass", "meadow", "village_green"], "leisure": "park"}' \
--feature 'forest:{"landuse": "forest", "natural": "wood"}' \
--feature 'wetland:{"natural": "wetland"}' \
--feature 'infrastructure:{"building": true, "landuse": ["industrial", "commercial", "retail", "residential", "construction", "railway"]}' \
--feature 'road:{"highway": ["motorway", "trunk", "primary", "secondary", "tertiary", "unclassified", "residential", "service", "track", "motorway_link", "trunk_link", "primary_link", "secondary_link", "tertiary_link"]}' \
--feature 'water:{"natural": "water", "waterway": ["river", "canal", "stream", "drain", "ditch"]}' \
--output cambridge_landcover.tif \
--resolution 10 \
--single-layer \
--fill-nodata \
--fill-nodata-distance 50
This produces a 10 m resolution single-layer categorical raster with 8 land cover classes, with small gaps filled by propagating the nearest label up to 50 pixels away.
Python API
from osm_rasterizer.rasterize import rasterize
result = rasterize(
bbox=(-0.15, 51.48, -0.08, 51.52), # central London
features=[
("building", {"building": True}),
("water", {"natural": "water"}),
("park", {"leisure": "park"}),
],
resolution=10.0,
single_layer=True,
fill_nodata=True,
fill_nodata_distance=30,
)
# result.array — numpy array, shape (1, H, W) in single-layer mode
# result.crs — rasterio CRS
# result.transform — affine transform
# result.categories — ["building", "water", "park"]
# Or write directly to a file:
rasterize(
bbox=(-0.15, 51.48, -0.08, 51.52),
features=[("building", {"building": True})],
output_path="buildings.tif",
)
How it works
- Fetch — OSM features are downloaded via the Overpass API (using osmnx) and clipped to the exact bounding box.
- Project — The bbox and geometries are reprojected to the best-fit UTM CRS (or a user-specified CRS).
- Rasterize — Each feature class is burned into a
uint8grid using rasterio. - Merge / fill — Bands are optionally merged into a single categorical layer, and empty pixels optionally filled using a Euclidean distance transform (scipy).
- Write — Output is a cloud-optimised, LZW-compressed, tiled GeoTIFF.
Development
# Run tests (unit tests only, no network)
uv run pytest
# Run including integration tests (requires Overpass network access)
uv run pytest -m integration
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file osm_rasterizer-0.1.0.tar.gz.
File metadata
- Download URL: osm_rasterizer-0.1.0.tar.gz
- Upload date:
- Size: 53.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
397cfa851825c631c45369b9bd0481591c0306f691497aeb5911abc3dfaad7e2
|
|
| MD5 |
c8635f8d9f25d0ebb12f2abd22c0872a
|
|
| BLAKE2b-256 |
f64121cb81c8cd1cb5527a17f70a90ed602bd12af25cd0329ca8f6eee7e615f9
|
Provenance
The following attestation bundles were made for osm_rasterizer-0.1.0.tar.gz:
Publisher:
publish.yml on ancazugo/osm-rasterizer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
osm_rasterizer-0.1.0.tar.gz -
Subject digest:
397cfa851825c631c45369b9bd0481591c0306f691497aeb5911abc3dfaad7e2 - Sigstore transparency entry: 1180171841
- Sigstore integration time:
-
Permalink:
ancazugo/osm-rasterizer@f4a735d4c1f2782b0d6fe36b082ad50794334a5f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ancazugo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f4a735d4c1f2782b0d6fe36b082ad50794334a5f -
Trigger Event:
push
-
Statement type:
File details
Details for the file osm_rasterizer-0.1.0-py3-none-any.whl.
File metadata
- Download URL: osm_rasterizer-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d93a170339b2a6fbdc81f6ac3a222a0c79081b8081354ab1f220c6688bd1ea1
|
|
| MD5 |
1bbe7bf777e1c81ffe7a69be49a9c6a3
|
|
| BLAKE2b-256 |
828f1fd2c51098c7e7d557e5042321e3aecb2aa20c50b2e3df7453f8e99888a1
|
Provenance
The following attestation bundles were made for osm_rasterizer-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on ancazugo/osm-rasterizer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
osm_rasterizer-0.1.0-py3-none-any.whl -
Subject digest:
1d93a170339b2a6fbdc81f6ac3a222a0c79081b8081354ab1f220c6688bd1ea1 - Sigstore transparency entry: 1180171842
- Sigstore integration time:
-
Permalink:
ancazugo/osm-rasterizer@f4a735d4c1f2782b0d6fe36b082ad50794334a5f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ancazugo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f4a735d4c1f2782b0d6fe36b082ad50794334a5f -
Trigger Event:
push
-
Statement type: