Shepherd segmentation (Remote Sensing 2019) in pure NumPy/SciPy - runs in Pyodide/WebAssembly and CPython. Bit-exact compat mode vs pyshepseg; algorithm-faithful by default.
Project description
🛰️ shepherd-wasm
Segmentación Shepherd (Shepherd, Bunting & Dymond 2019) en NumPy/SciPy puro — corre en WebAssembly.
Pure NumPy/SciPy implementation of Shepherd segmentation for satellite imagery. Bit-exact
against pyshepseg, numba-free, so it runs in the browser via Pyodide/WebAssembly — and
just as happily in regular CPython.
🎬 Demo en vivo (todo corre en tu navegador): https://abxda.github.io/portable-satelital/lab/index.html?path=Taller_ML_Urbano_WASM.ipynb
¿Por qué existe esto?
La implementación de referencia, pyshepseg, acelera
sus bucles críticos con numba (JIT sobre LLVM). Eso la hace rápida — y también
imposible de ejecutar en WebAssembly: el sandbox WASM prohíbe la generación de código
nativo en tiempo de ejecución, y numba no existe (ni existirá) en Pyodide.
shepherd_pure.py es un port fiel, línea por línea, de pyshepseg 2.0.5 a
NumPy/SciPy vectorizado. Sin numba, sin C, sin compilación: un solo archivo que corre
idéntico en CPython y dentro de una pestaña del navegador.
Fidelidad: bit-exacto, no "parecido"
Validado contra pyshepseg 2.0.5 sobre ventanas reales de una geomediana Sentinel-2
(12 bandas, int16, Aguascalientes, México), compartiendo el mismo objeto KMeans
(kmeansObj) para aislar los pasos reimplementados:
| Ventana | minSegmentSize | ARI | Píxeles idénticos | Segmentos (ref / puro) |
|---|---|---|---|---|
| 256×256 (centro) | 50 | 1.000000 | 100 % | 587 / 587 |
| 512×512 (centro) | 50 | 1.000000 | 100 % | 2 082 / 2 082 |
| 512×512 (borde, con nodata) | 50 | 1.000000 | 100 % | 2 191 / 2 191 |
| 1024×1024 | 100 | 1.000000 | 100 % | 4 700 / 4 700 |
Misma cuenta de píxeles sueltos eliminados, mismos segmentos pequeños fusionados, mismo
maxSpectralDiff automático. La fidelidad incluye los detalles que no aparecen en el
paper: IDs de clump por orden de descubrimiento en barrido raster, tope
MAX_CLUMP_SIZE=10000, la pasada previa de eliminación de píxeles sueltos, y los
desempates "primero encontrado" en orden fila→columna. Reproduce la validación con
validate_shepherd.py.
Rendimiento (sorpresa)
| Tile | pyshepseg (numba, incluye ~4 s de JIT) | shepherd-wasm (CPython) | shepherd-wasm (navegador, Pyodide) |
|---|---|---|---|
| 256² ×12 bandas | 4.5 s | 0.6 s | 0.8 s |
| 512² ×12 | 4.4 s | 1.8 s | — |
| 1024² ×12 | 4.7 s | 17.5 s | — |
En tiles chicos gana al original (se ahorra el costo del JIT); en tiles grandes el
procesamiento por mosaico — el mismo patrón de pyshepseg.tiling — mantiene todo en la
zona dulce.
Instalación
pip install shepherd-wasm
import shepherd_wasm # módulo canónico (import shepherd_pure sigue funcionando como alias)
Uso
import numpy as np
import shepherd_wasm
# img: ndarray (n_bandas, filas, columnas); usa float32 para evitar wraparound
res = shepherd_wasm.doShepherdSegmentation(
img.astype(np.float32),
numClusters=60,
minSegmentSize=50,
maxSpectralDiff='auto',
imgNullVal=nodata, # o None
fixedKMeansInit=True, # determinista (recomendado para docencia)
)
res.segimg # ndarray (filas, columnas) con IDs de segmento; 0 = nulo
res.singlePixelsEliminated, res.smallSegmentsEliminated, res.maxSpectralDiff
Misma firma y semántica que pyshepseg.shepseg.doShepherdSegmentation — es un reemplazo
directo. Dependencias: numpy, scipy, scikit-learn (las tres existen en Pyodide).
En Pyodide/JupyterLite, recuerda que el auto-cargador no ve los imports internos de un
módulo: ejecuta import scipy.ndimage, sklearn.cluster en una celda antes de
import shepherd_pure.
Crédito y licencia
- Algoritmo: Shepherd, J.D.; Bunting, P.; Dymond, J.R. Operational Large-Scale Segmentation of Imagery Based on Iterative Elimination. Remote Sensing 2019, 11(6), 658. DOI 10.3390/rs11060658.
- Implementación de referencia:
pyshepseg© Neil Flood & Sam Gillingham (MIT). Este proyecto es un port derivado y conserva su licencia y crédito. - Port a NumPy puro, validación y empaque WASM: abxda × Claude — Dr. Abel Coronado en colaboración con Claude (Anthropic), 2026.
MIT. Ver LICENSE.
⚠️ Divergencia documentada respecto a pyshepseg: maxClumpSize
pyshepseg introduce en su clump() un tope duro MAX_CLUMP_SIZE = 10000
píxeles (optimización del port a numba, ausente en el paper y en RSGISLib,
la implementación canónica de los mismos autores). Consecuencia: cualquier
objeto homogéneo mayor a 10,000 px — un lago, una presa, una mancha urbana —
queda rebanado en tiras paralelas (la huella del frente del flood fill)
que la eliminación iterativa jamás fusiona, porque cada tira supera
minSegmentSize.
Caso real (Laguna de Yuriria, geomediana Sentinel-2 12 bandas): con el tope, el segmento mayor mide 11,767 px y el lago queda en ~30 tiras; sin el tope, 387,989 px — el lago entero, estructuralmente idéntico al resultado de RSGISLib.
Por eso esta biblioteca diverge deliberadamente:
maxClumpSize |
Comportamiento |
|---|---|
None (default) |
Fiel al algoritmo (paper / RSGISLib): objetos grandes enteros |
10000 |
Modo compatibilidad: reproduce bit a bit a pyshepseg, incluido su artefacto (es lo que usa validate_shepherd.py) |
La validación es por lo tanto de dos niveles: compatibilidad (ARI 1.0
contra pyshepseg con maxClumpSize=10000) y corrección (objetos grandes
íntegros, consistente con RSGISLib).
Project details
Release history Release notifications | RSS feed
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 shepherd_wasm-1.1.0.tar.gz.
File metadata
- Download URL: shepherd_wasm-1.1.0.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7e6106a1401ad0812c2339891dae0106127eac0643feecdc97f0a6bb2b2db435
|
|
| MD5 |
25b63d76ccf96ddeb1c27b19527497d3
|
|
| BLAKE2b-256 |
b6c39963ce6f77895e7797056e7a97b5649689a3de4fa8a7ae4b067c640b9d11
|
Provenance
The following attestation bundles were made for shepherd_wasm-1.1.0.tar.gz:
Publisher:
publish.yml on abxda/shepherd-wasm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shepherd_wasm-1.1.0.tar.gz -
Subject digest:
7e6106a1401ad0812c2339891dae0106127eac0643feecdc97f0a6bb2b2db435 - Sigstore transparency entry: 1783050821
- Sigstore integration time:
-
Permalink:
abxda/shepherd-wasm@cbb6fdc9a7c073d6103868e6c2f6dcd851b362a0 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/abxda
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cbb6fdc9a7c073d6103868e6c2f6dcd851b362a0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file shepherd_wasm-1.1.0-py3-none-any.whl.
File metadata
- Download URL: shepherd_wasm-1.1.0-py3-none-any.whl
- Upload date:
- Size: 12.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
580b1b012160867985bc6446c6e93ff5f0a37bf548a16c9786bed902332bd25c
|
|
| MD5 |
8559084eaf47aff5faae5871c1601e75
|
|
| BLAKE2b-256 |
4238c65f749c7bd3fc0d93de507ff78787b9fb6ee2ba840b0fdcd9d5e88f9cbd
|
Provenance
The following attestation bundles were made for shepherd_wasm-1.1.0-py3-none-any.whl:
Publisher:
publish.yml on abxda/shepherd-wasm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shepherd_wasm-1.1.0-py3-none-any.whl -
Subject digest:
580b1b012160867985bc6446c6e93ff5f0a37bf548a16c9786bed902332bd25c - Sigstore transparency entry: 1783050888
- Sigstore integration time:
-
Permalink:
abxda/shepherd-wasm@cbb6fdc9a7c073d6103868e6c2f6dcd851b362a0 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/abxda
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cbb6fdc9a7c073d6103868e6c2f6dcd851b362a0 -
Trigger Event:
push
-
Statement type: