Fast, clean GIS raster-to-vector conversion with sliver removal and optional edge smoothing.
Convert satellite imagery, drone data, and other raster formats into clean vector polygons—automatically removing small artifacts and smoothing jagged boundaries.
- 🚀 Fast Processing - Uses
rasterioand GDAL for optimized raster I/O - 🎯 Clean Boundaries - Removes rasterization artifacts and jagged edges
- 🗑️ Sliver Removal - Automatically filters small/invalid polygons
- ✨ Optional Smoothing - Chaikin's algorithm for beautiful edges
- 📁 Multiple Formats - GeoTIFF, JPEG2000, and more (anything rasterio reads)
- 💾 Flexible Output - Shapefile, GeoJSON, or in-memory geometries
- 🐍 Beginner-Friendly - Simple Python API, intuitive CLI
- ✅ 100% Tested - Production-ready with full test coverage
Ensure you have Python 3.8+ and GDAL libraries installed on your system:
Ubuntu/Debian:
sudo apt-get install gdal-bin libgdal-devmacOS (with Homebrew):
brew install gdalWindows: Download from OSGeo4W or use conda (recommended)
pip install raster-to-polygons-fastOr for development:
git clone https://github.com/spatialworkflowIo/raster-to-polygons-fast.git
cd raster-to-polygons-fast
pip install -e ".[dev]"Convert a raster to shapefile with automatic sliver removal and smoothing:
# Basic conversion
raster-to-polygons input.tif output.shp
# Remove slivers and smooth edges
raster-to-polygons input.tif output.shp --remove-slivers --smooth
# Custom minimum area (50 m²) and smoothness (heavy)
raster-to-polygons input.tif output.shp \
--remove-slivers --min-area 50 \
--smooth --smoothness 3.0
# Save as GeoJSON instead
raster-to-polygons input.tif output.geojson --remove-sliversfrom raster_to_polygons import raster_to_polygons
# Simple conversion
polygons = raster_to_polygons('input.tif', output_file='output.shp')
# With all options
polygons = raster_to_polygons(
'input.tif',
output_file='output.shp',
band=1, # Which band to convert
remove_slivers=True, # Filter small polygons
min_area=5.0, # Minimum area in map units
smooth_edges=True, # Smooth boundaries
smoothness=1.5, # 1.0 = light, 3.0 = heavy
)
# In-memory geometries (no file output)
from raster_to_polygons import raster_to_features
features = raster_to_features('input.tif', remove_slivers=True)
for feature in features:
print(feature['geometry']) # Shapely-compatible geometry
print(feature['properties']) # {'value': ..., 'area': ..., 'perimeter': ...}Convert raster to vector polygons with optional cleaning and smoothing.
Parameters:
input_file(str/Path): Input raster file pathoutput_file(str/Path, optional): Output shapefile or GeoJSON pathband(int): Raster band index (1-indexed, default: 1)remove_slivers(bool): Remove small polygons (default: False)min_area(float, optional): Minimum polygon area. Auto-calculated if Nonesmooth_edges(bool): Apply edge smoothing (default: False)smoothness(float): Smoothing intensity, 1.0–3.0 (default: 1.0)
Returns:
List of (Polygon, properties_dict) tuples
Example:
from raster_to_polygons import raster_to_polygons
polygons = raster_to_polygons(
'satellite.tif',
output_file='output.shp',
remove_slivers=True,
smooth_edges=True
)
print(f"Created {len(polygons)} polygons")Convert raster to GeoJSON-like features.
Returns:
List of GeoJSON Feature dicts with geometry and properties
Example:
from raster_to_polygons import raster_to_features
import json
features = raster_to_features('input.tif')
geojson = {
"type": "FeatureCollection",
"features": features
}
print(json.dumps(geojson))See raster_to_polygons.cleaner module:
remove_slivers()- Filter polygons by area and shape metricsis_valid_polygon()- Validate polygon geometryfill_holes()- Remove interior holes from polygonsdissolve_by_value()- Merge adjacent polygons with same raster value
See raster_to_polygons.smoother module:
smooth_geometries()- Apply Chaikin smoothing to polygonssimplify_geometries()- Reduce coordinate count via Douglas-Peuckerchaikin_smooth()- Direct Chaikin algorithm application
For full API documentation:
# Generate Sphinx HTML docs
pip install sphinx sphinx-rtd-theme
cd docs
make html
open _build/html/index.htmlConvert classified satellite imagery (e.g., NDVI classes) to vector polygons:
from raster_to_polygons import raster_to_polygons
# NDVI classification: 1=low vegetation, 2=medium, 3=high
polygons = raster_to_polygons(
'ndvi_classified.tif',
output_file='vegetation_zones.shp',
remove_slivers=True, # Remove noise pixels
min_area=100.0, # Only zones > 100 m²
smooth_edges=True # Professional boundaries
)
# Analyze results
for geom, props in polygons:
value = props['value']
area = props['area']
print(f"Vegetation class {value}: {area:.1f} m²")Segment drone data to extract building footprints:
from raster_to_polygons import raster_to_polygons, raster_to_features
import json
# Binary classification: 0=background, 1=building
features = raster_to_features(
'drone_orthomosaic.tif',
remove_slivers=True,
min_area=20.0, # Only buildings > 20 m²
smooth_edges=True
)
# Export as GeoJSON for web mapping
geojson = {
"type": "FeatureCollection",
"features": [f for f in features if f['properties']['value'] == 1]
}
with open('buildings.geojson', 'w') as f:
json.dump(geojson, f, indent=2)
print(f"Extracted {len(geojson['features'])} buildings")Process specific bands from multi-band imagery:
from raster_to_polygons import raster_to_polygons
# Extract Band 2 (Red) from Landsat TIFF
polygons = raster_to_polygons(
'landsat_8.tif',
band=2, # Select band 2
output_file='red_zones.shp',
remove_slivers=True
)Processing time and memory usage vary by raster size:
| Raster Size | Typical Time | Memory Usage | Notes |
|---|---|---|---|
| 1 km² (1000x1000 px) | 0.5–2 sec | ~50 MB | Typical drone orthomosaic |
| 10 km² (3162x3162 px) | 5–15 sec | ~200 MB | Medium satellite scene |
| 100 km² (10000x10000 px) | 30–120 sec | ~1 GB | Large satellite scene |
| > 1 GB files | Not recommended | > 4 GB | Consider tiling |
Tips for Large Files:
- Tile rasters before processing (
gdal_translate -co TILED=YES) - Process by band for multi-band files
- Disable smoothing initially (
--smoothadds ~10% overhead) - Use appropriate
--min-areathreshold to reduce polygon count
Tested Platforms:
- ✅ Linux (Ubuntu 20.04+)
- ✅ macOS (10.15+)
- ✅ Windows 10+ (via conda-forge rasterio)
# Install dev dependencies
pip install -e ".[dev]"
# Run all tests with coverage
pytest --cov=raster_to_polygons --cov-report=term-missing
# Run specific test file
pytest tests/test_core.py -v
# Run with detailed output
pytest -vv --tb=shortExpected output: 100% test coverage
pip install sphinx sphinx-rtd-theme
cd docs
make html
open _build/html/index.html# Format code
black raster_to_polygons/ tests/
# Lint
flake8 raster_to_polygons/ tests/
# Type checking
mypy raster_to_polygons/MIT License - See LICENSE file for details
Author: Spatial Workflow
Contributions welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for any new functionality (must maintain 100% coverage)
- Commit with descriptive messages (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Bug Reports: GitHub Issues
- Feature Requests: Discussion in Issues welcome
- Questions: See Spatial Workflow for contact info
- GDAL - Geospatial Data Abstraction Library
- rasterio - Pythonic GDAL bindings
- Shapely - Geometric operations
- PyGEOS - Fast geometry operations (optional)
Made with ❤️ for the GIS community. Visit spatialworkflow.io for more tools.