Skip to content

Hand made label shapefile to raster conversion #22

Description

@AMarkWarren

Feature

Story / Description

As an end user of terrakit with a specific usecase
I want to be able to label satellite images manually in a GIS system since open source labels are unavailable.
This is so that I can use the terrakit processing pipeline tools in the knowledge that my data and their geospatial extent are maintained. Currently this feature does not seem to exist but I am providing code that worked for me and could become a feature.

Test Cases

For small object detection using segmentation there are currently no easily downloadable labels in the appropriate raster format that terrakit can readily take in and process within the example workflows as they stand.

Implementation Details

Using rasterio and geopandas packages I have produced python code (AI assisted!) (currently deployed directly in a jupyter cell) that handled the conversion of shapefiles (containing handmade labels) whilst maintaining geospatial extent of the full image scene used by labels.

from rasterio import features
import geopandas as gpd
from pathlib import Path

# 1. Define your directories
img_dir = Path(<"path_to_save_rasterised_labels">)
shp_dir = Path("<path_to_label_shapefiles>")

# 2. Loop through every TIFF with the specific suffix
for img_path in img_dir.glob("*_imputed.tif"):
    
    # Logic: If img is 'date_imputed.tif' -> base_name = 'date'
    base_name = img_path.stem.replace("_imputed", "")

    # Construct the matching shapefile path with '_labels.shp'
    # Example: 'date' -> 'date_labels.shp'
    shp_path = shp_dir / f"{base_name}_labels.shp"

    if not shp_path.exists():
        print(f"Skipping: {img_path.name} (Missing {shp_path.name})")
        continue
    # Safety check - does the shapefile exist? If not skip to next file in the loop

    print(f"Processing: {img_path.name}")

    # 3. Setting grid template
    with rasterio.open(img_path) as src:
        template_meta = src.meta.copy() # Grab projection, size etc
        template_transform = src.transform # Tells where pixels located on Earth and number rows/columns for grid
        template_shape = src.shape

    # 4. Load & Re-project Shapefile to match the TIFF exactly
    gdf = gpd.read_file(shp_path)
    gdf = gdf.to_crs(template_meta['crs']) # re-project shapefile cords to match those of tif

    # 5. Rasterize polygons into the template grid (burning labels)
    rasterized_labels = features.rasterize(
        ((geom, 1) for geom in gdf.geometry), #For every polygon in file assign (paint it) 1
        out_shape=template_shape,
        transform=template_transform,
        fill=0, # set background where no polygons to 0
        dtype='uint8'
    )

    # 6. Save the label in the SAME folder as the image
    template_meta.update(dtype='uint8', count=1, nodata=0)
    output_filename = img_dir / f"{base_name}_labels.tif"
    
    with rasterio.open(output_filename, 'w', **template_meta) as dst:
        dst.write(rasterized_labels, 1)

print("\nDone! All labels converted and saved in:", img_dir)```



## Acceptance Criteria
<!-- Include the minimum requirements for the issue to be marked as completed. -->

- [ ] Code reviewed by ___.
- [ ] Automated tests exist.
- [ ] Manually tested in ___.
- [ ] Documentation written here: 
- [ ] ...

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions