Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ worked_examples/**/tmp_checkpoints/*
/tmp_checkpoints/*
/tests/sample_files/cropped_74488689.tif
/tests/sample_files/cropped_L.tif

# testing_noteooks dev
testing_notebooks/*
testing_notebooks/data/*
!testing_notebooks/*.ipynb
testing_notebooks/.ipynb_checkpoints/
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ repos:
rev: "23.9.1"
hooks:
- id: black-jupyter
language_version: python3.9
language_version: python3.12

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.0.290"
Expand Down
68 changes: 68 additions & 0 deletions mapreader/load/geo_utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#!/usr/bin/env python
from __future__ import annotations

import geopandas as gpd
import numpy as np
import rasterio
from geopy.distance import geodesic, great_circle
from pyproj import Transformer
from rasterio.features import geometry_mask
from shapely.geometry import box


def extractGeoInfo(image_path):
Expand Down Expand Up @@ -102,3 +105,68 @@
size_in_m = None

return tiff_shape, tiff_proj, target_crs, coord, size_in_m


def apply_mask_to_raster(
input_tif: str,
gdf: gpd.GeoDataFrame,
output_tif: str,
mask_color: str = "white",
buffer_distance: float = 0,
):
"""
Apply a geospatial mask to a GeoTIFF file based on a GeoDataFrame, clipping geometries to the raster bounds.

Parameters:
- input_tif (str): Path to the input GeoTIFF file.
- gdf (geopandas.GeoDataFrame): GeoDataFrame containing geometries to mask.
- output_tif (str): Path to save the masked GeoTIFF.
- mask_color (str): Color of the mask, either "white" or "black". Defaults to "white".
- buffer_distance (float): Buffer distance in meters for polylines. Defaults to 0 (no buffering).

Returns:
- None
"""
if mask_color not in ["white", "black"]:
raise ValueError("mask_color must be either 'white' or 'black'")

Check warning on line 131 in mapreader/load/geo_utils.py

View check run for this annotation

Codecov / codecov/patch

mapreader/load/geo_utils.py#L130-L131

Added lines #L130 - L131 were not covered by tests

with rasterio.open(input_tif) as src:
gdf = gdf.to_crs(src.crs)

Check warning on line 134 in mapreader/load/geo_utils.py

View check run for this annotation

Codecov / codecov/patch

mapreader/load/geo_utils.py#L133-L134

Added lines #L133 - L134 were not covered by tests

# Clip geometries to raster bounds
raster_bounds = box(*src.bounds)
raster_bbox = gpd.GeoDataFrame({"geometry": [raster_bounds]}, crs=src.crs)
gdf = gpd.clip(gdf, raster_bbox)

Check warning on line 139 in mapreader/load/geo_utils.py

View check run for this annotation

Codecov / codecov/patch

mapreader/load/geo_utils.py#L137-L139

Added lines #L137 - L139 were not covered by tests

# Buffer polylines if applicable
if buffer_distance > 0:
gdf["geometry"] = gdf.geometry.apply(

Check warning on line 143 in mapreader/load/geo_utils.py

View check run for this annotation

Codecov / codecov/patch

mapreader/load/geo_utils.py#L142-L143

Added lines #L142 - L143 were not covered by tests
lambda geom: geom.buffer(buffer_distance)
if geom.geom_type in ["LineString", "MultiLineString"]
else geom
)

# Read raster data
raster_data = src.read()
transform = src.transform
out_meta = src.meta.copy()

Check warning on line 152 in mapreader/load/geo_utils.py

View check run for this annotation

Codecov / codecov/patch

mapreader/load/geo_utils.py#L150-L152

Added lines #L150 - L152 were not covered by tests

# Create the mask
mask = geometry_mask(

Check warning on line 155 in mapreader/load/geo_utils.py

View check run for this annotation

Codecov / codecov/patch

mapreader/load/geo_utils.py#L155

Added line #L155 was not covered by tests
[geom for geom in gdf.geometry if geom.is_valid],
transform=transform,
invert=True,
out_shape=(src.height, src.width),
)

# Apply the mask
masked_raster = np.copy(raster_data)
fill_value = 255 if mask_color == "white" else 0
for band in range(masked_raster.shape[0]):
masked_raster[band][mask] = fill_value

Check warning on line 166 in mapreader/load/geo_utils.py

View check run for this annotation

Codecov / codecov/patch

mapreader/load/geo_utils.py#L163-L166

Added lines #L163 - L166 were not covered by tests

# Save the masked raster
with rasterio.open(output_tif, "w", **out_meta) as dst:
dst.write(masked_raster)

Check warning on line 170 in mapreader/load/geo_utils.py

View check run for this annotation

Codecov / codecov/patch

mapreader/load/geo_utils.py#L169-L170

Added lines #L169 - L170 were not covered by tests

print(f"Masked GeoTIFF saved to {output_tif}")

Check warning on line 172 in mapreader/load/geo_utils.py

View check run for this annotation

Codecov / codecov/patch

mapreader/load/geo_utils.py#L172

Added line #L172 was not covered by tests
Loading