Segmentación de datos espaciales: conceptos y aplicación
Segmentar no es lo mismo que clasificar. La segmentación agrupa píxeles en objetos coherentes antes de asignarles una etiqueta, produciendo resultados más limpios y analizables. Esta guía cubre los conceptos, los algoritmos y su aplicación en QGIS y PostGIS.
¿Qué es segmentar y por qué importa?
En análisis raster tradicional, cada píxel se clasifica de forma independiente. Esto produce resultados con «sal y pimienta»: píxeles aislados mal clasificados en medio de una región homogénea. La segmentación resuelve esto agrupando primero los píxeles en segmentos — regiones contiguas y espectralmente similares — y luego trabajando con esos objetos.
La diferencia es conceptual: en lugar de clasificar «este píxel es bosque», clasificas «este objeto de 2.3 ha con NDVI medio 0.72 y forma compacta es bosque denso». Los objetos resultantes son vectorizables, tienen atributos estadísticos (media, desviación, forma) y son mucho más útiles para análisis territorial.
Segmentación de imagen vs. segmentación de datos tabulares
El término segmentación aparece en dos contextos distintos en datos espaciales:
- Segmentación de imagen raster — agrupa píxeles por similitud espectral y contigüidad espacial. El resultado son polígonos. Herramientas: Orfeo Toolbox, GDAL, rasterio + scikit-image.
- Segmentación de datos vectoriales / tabulares — agrupa entidades (puntos, polígonos, registros) por atributos o proximidad espacial. El resultado son clústeres. Herramientas: PostGIS, K-Means geoespacial, DBSCAN con coordenadas.
Algoritmos comunes
- MeanShift — agrupa píxeles por densidad en el espacio espectral-espacial. Robusto, no requiere definir número de clústeres, pero lento en imágenes grandes. Implementado en Orfeo Toolbox.
- SLIC (Simple Linear Iterative Clustering) — genera superpíxeles compactos de tamaño aproximado definido por el usuario. Muy rápido. Disponible en scikit-image.
- Felzenszwalb — segmentación basada en grafos, captura bien bordes irregulares. scikit-image.
- Watershed — segmentación morfológica, útil para separar objetos que se tocan (edificios, parcelas).
Segmentación en QGIS con Orfeo Toolbox
Orfeo Toolbox (OTB) es la suite de teledetección de CNES, integrable como proveedor de algoritmos en QGIS.
- Instala OTB desde otb.orfeo-toolbox.org y configura el proveedor en QGIS → Opciones → Proveedores → OTB.
- Ve a Procesos → Caja de herramientas → OTB → Segmentation → Segmentation (otb).
- Selecciona la imagen de entrada y el algoritmo (meanshift).
- Ajusta los parámetros: Spatial radius (radio espacial, px), Range radius (tolerancia espectral), Min region size (tamaño mínimo de segmento).
- El resultado es un raster de etiquetas donde cada valor entero identifica un segmento.
Segmentación con Python (rasterio + scikit-image)
import numpy as np
import rasterio
from rasterio.features import shapes
from skimage.segmentation import slic
from skimage.color import label2rgb
import geopandas as gpd
from shapely.geometry import shape
# Cargar imagen multibanda
with rasterio.open("imagen_sentinel.tif") as src:
imagen = src.read() # (bandas, filas, cols)
transform = src.transform
crs = src.crs
# Reordenar a (filas, cols, bandas) para scikit-image
img = np.moveaxis(imagen[:3], 0, -1).astype(float)
# Normalizar 0-1
img = (img - img.min()) / (img.max() - img.min())
# Segmentación SLIC
# n_segments: número aproximado de superpíxeles
# compactness: balance forma/espectro (mayor = más compacto)
segmentos = slic(img, n_segments=500, compactness=10, sigma=1, start_label=1)
print(f"Segmentos generados: {segmentos.max()}")
# Calcular estadísticas por segmento (media de cada banda)
from skimage.measure import regionprops_table
import pandas as pd
stats = regionprops_table(
segmentos,
intensity_image=img[:, :, 0], # banda 1 (Rojo)
properties=["label", "area", "mean_intensity", "bbox"]
)
df_stats = pd.DataFrame(stats)
print(df_stats.head())
# Vectorizar segmentos a polígonos GeoPackage
mask = segmentos.astype(np.int32)
poligonos = []
for geom, valor in shapes(mask, transform=transform):
poligonos.append({"geometry": shape(geom), "seg_id": int(valor)})
gdf = gpd.GeoDataFrame(poligonos, crs=crs)
# Unir estadísticas
gdf = gdf.merge(df_stats.rename(columns={"label": "seg_id"}), on="seg_id", how="left")
# Guardar
gdf.to_file("segmentos.gpkg", driver="GPKG")
print(f"Guardados {len(gdf)} segmentos")
Segmentación vectorial con PostGIS
Para datos vectoriales (puntos de muestreo, parcelas, registros catastrales), PostGIS permite clusterizar por proximidad espacial con ST_ClusterDBSCAN o ST_ClusterKMeans:
-- Agrupar parcelas en clusters por proximidad (DBSCAN)
-- eps: distancia máxima en metros, minpoints: mínimo de vecinos
SELECT
id_parcela,
ST_ClusterDBSCAN(geom, eps := 100, minpoints := 5)
OVER () AS cluster_id,
geom
FROM parcelas
WHERE municipio = 'Sevilla';
-- Calcular área total y centroide por cluster
SELECT
cluster_id,
COUNT(*) AS n_parcelas,
SUM(ST_Area(geom)) AS area_total_m2,
ST_Centroid(ST_Collect(geom)) AS centroide
FROM (
SELECT id_parcela, geom,
ST_ClusterDBSCAN(geom, 100, 5) OVER () AS cluster_id
FROM parcelas
WHERE municipio = 'Sevilla'
) t
WHERE cluster_id IS NOT NULL
GROUP BY cluster_id
ORDER BY area_total_m2 DESC;
Cuándo usar cada enfoque
- Orfeo Toolbox en QGIS — imágenes grandes, flujo visual, sin programación. Ideal para producción cartográfica.
- scikit-image + rasterio — integración en pipelines Python, control total de parámetros, procesamiento en lote automatizado.
- PostGIS ST_ClusterDBSCAN — datos vectoriales o tabulares con coordenadas, análisis territorial sobre registros existentes en base de datos.