💡 MATERIALES PARA EL EJERCICIO

escena SENTINEL 2.

script laboratorio 2 SENTINEL 2

DESCARGA DE IMÁGENES SENTINEL 2

La descarga de imágenes de SENTINEL 2 se realiza fundamentalmente a través de la plataforma de Copernicus Data Space (https://dataspace.copernicus.eu/).

Copernicus DataSpace Ecosystem
Copernicus DataSpace Ecosystem

El usuario debe registrarse primero creando una cuencia de usuario, en la que se deberá incluir información personal.

Una vez registrados, se accede a la información a través del Copernicus Browser (https://browser.dataspace.copernicus.eu/)

La selección del área de estudio puede realizarse de dos maneras. Por un lado, puede escribirse el nombre de una localidad concreta

De forma alternativa, se puede desplazar en la imagen y hacer zoom manualmente en su área de interés. Una vez situados sobre la zona de estudio podemos elegir entre

VISUALIZAR: mediante la selección de fechas, cobertura de nubes, satélite y visualice sus datos en diferentes compuestos.

BUSCAR: Esta pestaña está dedicada a encontrar la escena correcta y descargar las imágenes como un archivo comprimido.

En el panel izquierdo se pueden filtrar las imágenes en función de algunas opciones:

Calendario.

Cobertura de nubes.

Configuración: selección de la configuración (agricultura, geología, urbano, etc.).

Plataforma: Sentinel-1, Sentinel-2, Sentinel-3, Sentinel-5P, DEM

Capas : color verdadero, color falso, NDVI, SWIR, clasificación de cobertura del suelo, etc.

En función de los criterios que haya introducido en la visualización, puede seleccionar el producto que desea descargar. Al hacer clic en el registro, podrá ver la extensión de la escena de Sentinel que desea descargar. Para descargar la imagen, seleccionar el botón “Descargar”.

Dado el gran volumen de información que proporcionan las imágenes Sentinel, la velocidad de descarga suele ser lenta.

ESTRUCTURA DEL ARCHIVO DE IMÁGENES DE SENTINEL 2

El producto descargado es un archivo comprimido en formato ZIP, en este caso S2A_MSIL2A_20210727T105621_N0500_R094_T30TVK_20230221T092710.SAFE.zip. SAFE es el acrónimo de Standard Archive Format for Europe. Sentinel 2 emplea una nomenclatura específica para identificar el tipo de producto, el satélite empleado o las fechas de barrido.

El nombre de cualquier fichero Sentinel muestra la siguiente denominación: MS2_MSILLL_YYYYMMDD, dónde:

MS2: identifica la misión de Sentinel 2, pudiendo encontrar S2A (para Sentinel 2A) o S2B (para Sentinel 2B)

MSI: indica el instrumento de operación (MultiSpectral instrument)

LLL: indica el nivel de procesado del producto pudiendo encontrar los niveles L0, L1C, L1B o L2A

YYYY: designa el momento temporal UTC (año) en el que fue tomada la imagen

MM: designa el momento temporal UTC (mes) en el que fue tomada la imagen

DD: designa el momento temporal UTC (día) en el que fue tomada la imagen

Al descomprimir el ZIP, la carpeta creada comprende una estructura de subcarpetas con imágenes y metadatos organizados de manera estándar.

📂 Carpeta GRANULE/

Contiene a su vez varias subcarpetas

IMG_DATA/ → Contiene las bandas en formato JP2 (JPEG 2000) divididas en **“granules” (fragmentos de 100x100 km) con proyección UTM/WGS84 y organizadas por resoluciones:

10m: B2 (Azul), B3 (Verde), B4 (Rojo), B8 (NIR) 20m: B5, B6, B7, B8A, B11, B12 60m: B1, B9, B10 (QA60 - Nubes)

AUX_DATA/ → Datos auxiliares (por ejemplo, el boletín International Earth Rotation & Reference Systems (IERS)).

QI_DATA/ → Máscaras de calidad (QA60, Scene Classification SCL, etc.).

MTD_TL.xml → Metadatos del tile.

📂 Carpeta DATASTRIP/ : contiene datos relacionados con la adquisición y procesamiento.

📂 Carpeta HTML/

📂 INSPIRE.xml y manifest.safe: archivos para compatibilidad con sistemas de información geográfica.

Además, ofrece adicionalmente:

🎯 Resumen

PROCESAMIENTO BÁSICO DE GRANULES DE SENTINEL 2 CON R

Creación de carpetas y descompresión de los datos

El paso previo para acceder a las imágenes Sentinel-2 es descomprimir el fichero en formato .zip.


En anteriores ejercicios se ha creado una carpeta en el disco D:/ denominada G174_2025 (sugerencia). A continuación, se podría preguntar si existe una carpeta denominada D:/G174_2025/lab_2/ejercicio_sentinel/ en el directorio /G174_2025/; si no la encuentra, la creará.

Esta última carpeta se establecerá como carpeta de trabajo por defecto.

Existen dos posibilidades para descargar los scripts y los datos que se utilizarán en el curso. Hay que señalar que, en ambos casos, los ficheros originales están comprimidos en formato .zip. Por lo tanto:

Descargar los datos desde la página web.

► Para descargar los datos sin pasar por la página web se pueden utilizar la siguiente función:

download.file("https://personales.unican.es/rasillad/docencia/G174/LABORATORIO_1/S2A_MSIL2A_20210727T105621_N0500_R094_T30TVK_20230221T092710.SAFE.zip",   # Qué fichero descargar
              "D:/G174_2025/lab_2/ejercicio_sentinel/S2A_MSIL2A_20210727T105621_N0500_R094_T30TVK_20230221T092710.SAFE.zip",    # A dónde y con qué nombre
              method = "auto")                                                                                    

► Una vez ubicado en la carpeta correcta, el fichero se puede descomprimir

unzip("D:/G174_2025/lab_2/ejercicio_sentinel/S2A_MSIL2A_20210727T105621_N0500_R094_T30TVK_20230221T092710.SAFE.zip",    # Qué fichero descomprimir
      exdir = "D:/G174_2025/lab_2/ejercicio_sentinel/")                                                                 # En qué carpeta ubicarlo

Se puede comprobar esta relación de listando todos los ficheros del directorio de trabajo.

list.files("D:/G174_2025/lab_2/ejercicio_sentinel/")

Para explorar y revisar el contenido de las carpetas se listarán todos los archivos con la función `list.files() con los siguientes argumentos.

► path: ruta en la que se encuentran los archivos (la carpeta)

► pattern: extensión de los archivos a buscar (el uso del símbolo $ especifica que la extensión .jp2 está al final del texto).

► recursive: deben buscarse los ficheros dentro de todas las carpetas.

► full.names: retorna nombre copleto y ruta de acceso.

jps <- list.files(path = "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/", 
                  pattern = ".jp2$", 
                  recursive = TRUE, 
                  full.names = TRUE)

Para revisar el contenido vamos a extraer los nombres de los archivos :

basename(jps)
##  [1] "T30TVK_20210727T105621_AOT_10m.jp2" "T30TVK_20210727T105621_B02_10m.jp2"
##  [3] "T30TVK_20210727T105621_B03_10m.jp2" "T30TVK_20210727T105621_B04_10m.jp2"
##  [5] "T30TVK_20210727T105621_B08_10m.jp2" "T30TVK_20210727T105621_TCI_10m.jp2"
##  [7] "T30TVK_20210727T105621_WVP_10m.jp2" "T30TVK_20210727T105621_AOT_20m.jp2"
##  [9] "T30TVK_20210727T105621_B01_20m.jp2" "T30TVK_20210727T105621_B02_20m.jp2"
## [11] "T30TVK_20210727T105621_B03_20m.jp2" "T30TVK_20210727T105621_B04_20m.jp2"
## [13] "T30TVK_20210727T105621_B05_20m.jp2" "T30TVK_20210727T105621_B06_20m.jp2"
## [15] "T30TVK_20210727T105621_B07_20m.jp2" "T30TVK_20210727T105621_B11_20m.jp2"
## [17] "T30TVK_20210727T105621_B12_20m.jp2" "T30TVK_20210727T105621_B8A_20m.jp2"
## [19] "T30TVK_20210727T105621_SCL_20m.jp2" "T30TVK_20210727T105621_TCI_20m.jp2"
## [21] "T30TVK_20210727T105621_WVP_20m.jp2" "T30TVK_20210727T105621_AOT_60m.jp2"
## [23] "T30TVK_20210727T105621_B01_60m.jp2" "T30TVK_20210727T105621_B02_60m.jp2"
## [25] "T30TVK_20210727T105621_B03_60m.jp2" "T30TVK_20210727T105621_B04_60m.jp2"
## [27] "T30TVK_20210727T105621_B05_60m.jp2" "T30TVK_20210727T105621_B06_60m.jp2"
## [29] "T30TVK_20210727T105621_B07_60m.jp2" "T30TVK_20210727T105621_B09_60m.jp2"
## [31] "T30TVK_20210727T105621_B11_60m.jp2" "T30TVK_20210727T105621_B12_60m.jp2"
## [33] "T30TVK_20210727T105621_B8A_60m.jp2" "T30TVK_20210727T105621_SCL_60m.jp2"
## [35] "T30TVK_20210727T105621_TCI_60m.jp2" "T30TVK_20210727T105621_WVP_60m.jp2"
## [37] "MSK_CLASSI_B00.jp2"                 "MSK_CLDPRB_20m.jp2"                
## [39] "MSK_CLDPRB_60m.jp2"                 "MSK_DETFOO_B01.jp2"                
## [41] "MSK_DETFOO_B02.jp2"                 "MSK_DETFOO_B03.jp2"                
## [43] "MSK_DETFOO_B04.jp2"                 "MSK_DETFOO_B05.jp2"                
## [45] "MSK_DETFOO_B06.jp2"                 "MSK_DETFOO_B07.jp2"                
## [47] "MSK_DETFOO_B08.jp2"                 "MSK_DETFOO_B09.jp2"                
## [49] "MSK_DETFOO_B10.jp2"                 "MSK_DETFOO_B11.jp2"                
## [51] "MSK_DETFOO_B12.jp2"                 "MSK_DETFOO_B8A.jp2"                
## [53] "MSK_QUALIT_B01.jp2"                 "MSK_QUALIT_B02.jp2"                
## [55] "MSK_QUALIT_B03.jp2"                 "MSK_QUALIT_B04.jp2"                
## [57] "MSK_QUALIT_B05.jp2"                 "MSK_QUALIT_B06.jp2"                
## [59] "MSK_QUALIT_B07.jp2"                 "MSK_QUALIT_B08.jp2"                
## [61] "MSK_QUALIT_B09.jp2"                 "MSK_QUALIT_B10.jp2"                
## [63] "MSK_QUALIT_B11.jp2"                 "MSK_QUALIT_B12.jp2"                
## [65] "MSK_QUALIT_B8A.jp2"                 "MSK_SNWPRB_20m.jp2"                
## [67] "MSK_SNWPRB_60m.jp2"                 "T30TVK_20210727T105621_PVI.jp2"

Nos encontramos con un total de 67 archivos .jp2, tanto correspondientes a las bandas espectrales como a los restantes productos. Obsérvese que la resolución espacial de las imágenes se identifica con los sufijos 10m, 20m y 60m.

Imágenes a 10m

Vamos a extraer solo los nombres que contienen el sufijo 10m del objeto jps mediante la función str_detect(string, pattern). Esta devuelve un vector lógico (TRUE o FALSE) de la misma longitud que el objeto jps, que contiene los textos a chequear, y cuyo valor TRUE indica que ha encontrado el patrón de caracteres “_10m”.

Primero, se activará el paquete stringr.

library(stringr)
## Warning: package 'stringr' was built under R version 4.3.2

Se genera el objeto que contiene las imágenes con una resolución de 10 m

id <- str_detect(string = jps, 
                 pattern = "_10m")
id 
##  [1]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE
## [13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [37] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

Y usando el vector lógico se crea un subconjunto con los elementos buscados:

sen2_10m_img <- jps[id]
sen2_10m_img
## [1] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R10m/T30TVK_20210727T105621_AOT_10m.jp2"
## [2] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R10m/T30TVK_20210727T105621_B02_10m.jp2"
## [3] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R10m/T30TVK_20210727T105621_B03_10m.jp2"
## [4] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R10m/T30TVK_20210727T105621_B04_10m.jp2"
## [5] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R10m/T30TVK_20210727T105621_B08_10m.jp2"
## [6] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R10m/T30TVK_20210727T105621_TCI_10m.jp2"
## [7] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R10m/T30TVK_20210727T105621_WVP_10m.jp2"

La imagen del tipo TCI debe ser excluida del objeto SpatRaster, añadiendo un signo negativo - a su número de orden (en este caso 6). A continuación se crea este objeto con la función terra::rast() y se renombran las capas

library(terra)
## Warning: package 'terra' was built under R version 4.3.3
## terra 1.8.5
sen2_10m <- rast(sen2_10m_img[-6])
names(sen2_10m) <- c("AOT","B2","B3","B4","B8","WVP")
sen2_10m
## class       : SpatRaster 
## dimensions  : 10980, 10980, 6  (nrow, ncol, nlyr)
## resolution  : 10, 10  (x, y)
## extent      : 399960, 509760, 4390200, 4500000  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 30N (EPSG:32630) 
## sources     : T30TVK_20210727T105621_AOT_10m.jp2  
##               T30TVK_20210727T105621_B02_10m.jp2  
##               T30TVK_20210727T105621_B03_10m.jp2  
##               ... and 3 more sources
## names       : AOT, B2, B3, B4, B8, WVP

Para convertir los valores o niveles digitale almacenados en las imágeness, que tienen una resolución radiométrica de 16 bits, a reflectancia superficial o BOA se debe aplicar la fórmula siguiente:

\(SR =\frac{ND}{10000}\)

Por ejemplo, si queremos transformar las bandas 2 a 4 (B2, B3 y B4)

sen2_10m_sr <- sen2_10m[[2:4]] /10000

Finalmente, este objeto será grabado como fichero *.tif.

writeRaster(sen2_10m_sr,
            "D:/G174_2025/lab_2/resultados/sen2_10m_sr.tif", 
            filetype = "GTiff", 
            overwrite=T)

Imágenes a 20 m

Repetimos los pasos para las imágenes con resolución de 20 m, debemos también ajustar los nombres de las bandas.

id <- str_detect(string = jps, pattern = "_20m")
id 
##  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
## [13]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE
## [25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [37] FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [61] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE
sen2_20m_img <- jps[id]
sen2_20m_img
##  [1] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_AOT_20m.jp2"
##  [2] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_B01_20m.jp2"
##  [3] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_B02_20m.jp2"
##  [4] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_B03_20m.jp2"
##  [5] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_B04_20m.jp2"
##  [6] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_B05_20m.jp2"
##  [7] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_B06_20m.jp2"
##  [8] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_B07_20m.jp2"
##  [9] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_B11_20m.jp2"
## [10] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_B12_20m.jp2"
## [11] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_B8A_20m.jp2"
## [12] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_SCL_20m.jp2"
## [13] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_TCI_20m.jp2"
## [14] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R20m/T30TVK_20210727T105621_WVP_20m.jp2"
## [15] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/QI_DATA/MSK_CLDPRB_20m.jp2"                      
## [16] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/QI_DATA/MSK_SNWPRB_20m.jp2"
sen2_20m <- rast(sen2_20m_img[-13])
names(sen2_20m) <- c("AOT", "B01", "B02.jp2", "B03", "B04", "B05", "B06", "B07", "B11", "B12", "B8A", "SCL", "WVP", "MSK_CLDPRB", "MSK_SNWPRB")
sen2_20m
## class       : SpatRaster 
## dimensions  : 5490, 5490, 15  (nrow, ncol, nlyr)
## resolution  : 20, 20  (x, y)
## extent      : 399960, 509760, 4390200, 4500000  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 30N (EPSG:32630) 
## sources     : T30TVK_20210727T105621_AOT_20m.jp2  
##               T30TVK_20210727T105621_B01_20m.jp2  
##               T30TVK_20210727T105621_B02_20m.jp2  
##               ... and 12 more sources
## names       : AOT, B01, B02.jp2, B03, B04, B05, ...

Finalmente, se graba la imagen multibanda.

writeRaster(sen2_20m,
            "D:/G174_2025/lab_2/resultados/sen2_20m.tif", 
            filetype = "GTiff", 
            overwrite=T)

Imágenes de 60 m

id <- str_detect(jps, "_60m")
id
##  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE
## [25]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [37] FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [61] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE
sen2_60m_img <- jps[id]
sen2_60m_img
##  [1] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_AOT_60m.jp2"
##  [2] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B01_60m.jp2"
##  [3] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B02_60m.jp2"
##  [4] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B03_60m.jp2"
##  [5] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B04_60m.jp2"
##  [6] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B05_60m.jp2"
##  [7] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B06_60m.jp2"
##  [8] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B07_60m.jp2"
##  [9] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B09_60m.jp2"
## [10] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B11_60m.jp2"
## [11] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B12_60m.jp2"
## [12] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_B8A_60m.jp2"
## [13] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_SCL_60m.jp2"
## [14] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_TCI_60m.jp2"
## [15] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/IMG_DATA/R60m/T30TVK_20210727T105621_WVP_60m.jp2"
## [16] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/QI_DATA/MSK_CLDPRB_60m.jp2"                      
## [17] "D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/GRANULE/L2A_T30TVK_A031837_20210727T110448/QI_DATA/MSK_SNWPRB_60m.jp2"
sen2_60m <- rast(sen2_60m_img[-14])

names(sen2_60m) <- c("AOT", "B01", "B02", "B03", "B04", "B05", "B06", "B07", "B09", "B11", "B12", "B8A", "SCL", "WVP", "MSK_CLDPRB", "MSK_SNWPRB")   

Finalmente, se graba la imagen multibanda.

writeRaster(sen2_60m,
            "D:/G174_2025/lab_2/resultados/sen2_60m.tif", 
            filetype = "GTiff", 
            overwrite=T)

Productos Adicionales Especiales

Los granulos de Sentinel contienen además una serie de imágenes adicionales que conviene conocer y procesar.

TCI

La imagen de color verdadero o TCI es una composición RGB en el mismo formato .jp2. Ha sido excluida al no ser posible su impresión directa con la función terra::plot(). Para hacerlo se vuelve a recurrir al paquete magick y la función magick::image_read() para representar gráficamente la imagen en color verdadero (resolución 60 m) que aparece en el puesto 14 de la relación sen2_60m_img.

library(magick)
## Warning: package 'magick' was built under R version 4.3.3
## Linking to ImageMagick 6.9.12.98
## Enabled features: cairo, freetype, fftw, ghostscript, heic, lcms, pango, raw, rsvg, webp
## Disabled features: fontconfig, x11
tci_60m <- image_read(sen2_60m_img[14])
tci_60m

Esta utilidad representa la imagen en el panel Viewer a escala verdadera, acompañado de dos barras para deslizar y explorar la imagen.

AOT

El Espesor Óptico del Aerosol (AOT), también conocida como profundidad óptica del aerosol o espesor óptico (τ) es el grado en que los aerosoles impiden la transmisión de luz. Desde el punto de vista cuantitativo se define como el coeficiente de extinción integrado sobre una columna vertical de sección transversal unitaria.

Por su parte, el coeficiente de extinción es el agotamiento fraccional de la radiancia por unidad de longitud del camino (también llamado atenuación, especialmente en referencia a las frecuencias de radar).

El grosor óptico a lo largo de la dirección vertical también se denomina grosor óptico normal (en comparación con el grosor óptico a lo largo de la trayectoria inclinada).

El conocimiento del AOT tiene utilidad en diferentes campos:

  1. Corrección atmosférica de elementos sensados.

  2. Monitoreo de fuentes y sumideros de aerosoles.

  3. Seguimiento de erupciones volcánicas e incendios forestales.

  4. Modelo de transferencia radiativa.

  5. Calidad del aire.

  6. Salud y Medio Ambiente.

  7. Cambio climático.

En el caso de las imágenes con una resolución de 60m la banda AOT ocupa la posición 3ª en la lista de bandas. Para la conversión su conversión a una magnitud real se escala por 1/1000.

aot_60m <- rast(sen2_60m_img[1])/1000
aot_60m
## class       : SpatRaster 
## dimensions  : 1830, 1830, 1  (nrow, ncol, nlyr)
## resolution  : 60, 60  (x, y)
## extent      : 399960, 509760, 4390200, 4500000  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 30N (EPSG:32630) 
## source(s)   : memory
## varname     : T30TVK_20210727T105621_AOT_60m 
## name        : T30TVK_20210727T105621_AOT_60m 
## min value   :                          0.046 
## max value   :                          0.123

WVP

La capa denominada WVP o Columna de Vapor de Agua, se expresa en cm y se debe escalar usando el mismo factor anterior 1/1000. En el caso de la resolución a 10m

wvp_10m <- rast(sen2_10m_img[7])/1000
## |---------|---------|---------|---------|=========================================                                          
plot(wvp_10m)

SCL

El producto Clasificación de Escena o SCL se compone de 11 categorías:

Estas categorías deben tratarse como factores. Primero se convierten en un objeto SpatRaster estándar:

scl_60m <- rast(sen2_60m_img[13])

Podemos solicitar una información básica

print(scl_60m)
## class       : SpatRaster 
## dimensions  : 1830, 1830, 1  (nrow, ncol, nlyr)
## resolution  : 60, 60  (x, y)
## extent      : 399960, 509760, 4390200, 4500000  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 30N (EPSG:32630) 
## source      : T30TVK_20210727T105621_SCL_60m.jp2 
## name        : T30TVK_20210727T105621_SCL_60m

Y mediante la función terra::as.factor() se convierte en un ráster categórico. Usando la función terra::levels() se accede a los valores presentes en el modelo. La función terra::is.factor() comprueba el formato del objeto.

fac <- as.factor(scl_60m)
levels(fac)
## [[1]]
##   ID T30TVK_20210727T105621_SCL_60m
## 1  2                              2
## 2  3                              3
## 3  4                              4
## 4  5                              5
## 5  6                              6
## 6  7                              7
## 7  8                              8
## 8  9                              9
## 9 10                             10
is.factor(fac)
## [1] TRUE

La función levels() también se usa para asignar nombres a las categorías de usos de suelo.

levels(fac) <- c("área obscura","Sombra Nubes", "Vegetación", "Suelo Desnudo", "Agua","Nube baja","Nube Media", "Nube Alta","Cirros")
## Warning: [set.cats] setting categories like this is deprecated; use a
## two-column data.frame instead

A continuación se crea un nuevo objeto ráster de naturaleza categórica con las nuevas categorías.

facto <- as.factor(fac)
is.factor(facto)
## [1] TRUE

Su imagen es la siguiente

plot(facto, 
     main = "Máscara de Clasificación (SCL)")

Y la distribución de usos de suelo por categorías es la siguiente

freq(facto)
##   layer value   count
## 1     1     2    1501
## 2     1     3   59910
## 3     1     4  185948
## 4     1     5 3005556
## 5     1     6    4747
## 6     1     7    4441
## 7     1     8   44915
## 8     1     9   41602
## 9     1    10     280

Máscaras de Probabilidad

Las máscaras de Probabilidad de nubes y nieve clasifican cada píxel de la escena con un valor porcentual que define la probabilidad de que aparezca alguno de esos fenómenos meteorológicos. El valor 0 equivale a la ausencia de nubes o de nieve, mientras que 255 equivale a un valor saturado.

msk_cld <- rast(sen2_60m_img[16])
plot(msk_cld)

msk_snw <- rast(sen2_60m_img[17])
plot(msk_snw)

Lectura de metadatos

Las imágenes Sentinel-2 vienen con un archivo de metadatos en formato XML (MTD_MSIL2A.xml o MTD_MSIL1C.xml). Puedes leerlo con xml2:

library(xml2)
## Warning: package 'xml2' was built under R version 4.3.2

Leer el archivo XML de metadatos e imprimirlo en pantalla

xml_file <- read_xml("D:/G174_2025/LABORATORIO_2_Imagenes_satelite/datos/ejercicio_sentinel/MTD_MSIL2A.xml")
print(xml_file)
## {xml_document}
## <Level-2A_User_Product schemaLocation="https://psd-14.sentinel2.eo.esa.int/PSD/User_Product_Level-2A.xsd" xmlns:n1="https://psd-14.sentinel2.eo.esa.int/PSD/User_Product_Level-2A.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
## [1] <n1:General_Info>\n  <Product_Info>\n    <PRODUCT_START_TIME>2021-07-27T1 ...
## [2] <n1:Geometric_Info>\n  <Product_Footprint>\n    <Product_Footprint>\n     ...
## [3] <n1:Auxiliary_Data_Info>\n  <GIPP_List>\n    <GIPP_FILENAME type="GIP_ATM ...
## [4] <n1:Quality_Indicators_Info>\n  <Cloud_Coverage_Assessment>2.610655</Clou ...

Extraer información específica (por ejemplo, fecha de adquisición)

fecha <- xml_text(xml_find_first(xml_file, "//SENSING_TIME"))
print(fecha)
## [1] NA