Capítulo 20. Muestreo de Ráster

Tabla de contenidos

Operador de Muestreo
Accesores de Ráster
Muestreo Raquet / QUADBIN
Serialización de Raquet
Accesores y Comparación de Raquet
Operadores de Restricción y Predicado
Compilación e Instalación
Hoja de Ruta de Producción

La extensión ráster de PostGIS almacena datos de cobertura en cuadrícula (elevación, temperatura, imágenes satelitales, …) en el tipo raster. Cada ráster tiene una o más bandas; una banda contiene un arreglo 2D de valores de píxel, una extensión espacial, un tamaño de píxel y un valor centinela opcional para datos nulos (nodata).

El operador de muestreo de ráster de MobilityDB evalúa una banda de ráster en los instantes de una trayectoria de punto móvil y devuelve un tfloat. Los instantes cuya posición cae fuera de la extensión del ráster o sobre un píxel nodata se descartan silenciosamente. Los operadores de muestreo son de valor doble sea cual sea el tipo de píxel de la banda, de modo que un tipo de píxel pertenece a la superficie de muestreo cuando todo valor que puede contener es exactamente representable en un número de doble precisión. Eso es lo que permite muestrear una banda de cualquier tipo en un único tfloat, y que una columna con teselas de varios tipos de píxel se lea con una sola consulta. Un tipo de píxel también se acepta con el nombre que le da el ráster de PostGIS, de modo que el tipo de banda que informa una llamada a ST_BandPixelType (8BUI, 16BSI, 32BF, …) se pasa a los constructores de teselas tal cual. El ráster de PostGIS no lleva flotantes de 16 bits ni enteros de 64 bits, así que float16, int64 y uint64 toman la grafía que da su gramática, 16BF, 64BSI y 64BUI. Sus tipos 1BB, 2BUI y 4BUI acotan un píxel a menos de un byte mientras que PostGIS almacena cada uno de ellos a un byte por píxel, de modo que tal banda ya son los bytes de una banda de 8 bits sin signo y los constructores la leen como uint8; la cota es lo único que añade el nombre, y una tesela no la lleva. El nombre que informa una tesela es el que la especificación RaQuet da al tipo. Los tipos uint64 e int64 contienen valores fuera de ese dominio: una tesela de cualquiera de ellos se almacena y se vuelve a leer exactamente, mientras que muestrear un píxel cuyo valor ningún número de doble precisión nombra genera un error en lugar de responder con un valor vecino. Esto permite consultas como ¿qué perfil de elevación siguió cada vehículo? o ¿qué viajes entraron en una banda de umbral de temperatura?

Para usar los operadores descritos aquí, MobilityDB debe ser compilado con -DRASTER=ON. En tal compilación, el archivo mobilitydb.control generado declara requires = 'postgis, postgis_raster', por lo que un único CASCADE crea la pila completa:

CREATE EXTENSION mobilitydb CASCADE;
-- NOTICE:  installing required extension "postgis"
-- NOTICE:  installing required extension "postgis_raster"

Operador de Muestreo

  • Muestrear una banda de ráster en cada instante de una trayectoria

    rasterValue(tgeompoint,raster,band integer DEFAULT 1) → tfloat
    

    Evalúa el píxel de la band en cada instante de traj usando muestreo bilineal-vecino más próximo (ST_Value con resample=false). Devuelve un tfloat de conjunto de instantes cuyos valores se redondean a cuatro decimales. Devuelve NULL cuando ningún instante se interseca con el ráster.

    -- Build a 3×3 synthetic elevation raster (SRID 4326, 1° pixels)
    WITH rast AS (
      SELECT ST_SetValues(
        ST_AddBand(
          ST_MakeEmptyRaster(3, 3, 0.0, 3.0, 1.0, -1.0, 0.0, 0.0, 4326),
          '32BF'::text, 0.0::float8, NULL::float8),
        1, 1, 1,
        ARRAY[[10.0::float4, 20.0::float4, 30.0::float4],
              [40.0::float4, 50.0::float4, 60.0::float4],
              [70.0::float4, 80.0::float4, 90.0::float4]]) AS r
    )
    SELECT rasterValue(tgeompoint 'SRID=4326;[POINT(0.5 2.5)@2000-01-01,
      POINT(2.5 2.5)@2000-01-02, POINT(0.5 0.5)@2000-01-03]', r)::text
    FROM rast;
    

    Aplicado a un conjunto de datos de trayectorias con un ráster de elevación del terreno:

    -- Elevation profile per trip (requires a loaded elevation raster)
    SELECT tripid, rasterValue(trip, elev) AS elevation
    FROM trips, elevation_raster;
    
    -- Average elevation per trip
    SELECT tripid, avgValue(rasterValue(trip, elev)) AS mean_elev
    FROM trips, elevation_raster;
    
    -- Trips that crossed terrain above 200 m
    SELECT tripid
    FROM trips, elevation_raster
    WHERE atSpan(rasterValue(trip, elev), floatspan '[200, 9999]') IS NOT NULL;