💡 OBJETIVOS DE LA ACTIVIDAD:

► Conocer los diversos procedimientos para mejorar el contraste de las imágenes.

► Saber aplicar los procedimientos para realzar las características de brillo y contraste de una imagen, reducir su ruido, o agudizar o intensificar detalles presentes en ella

💡 MATERIALES PARA LA ACTIVIDAD:

► En este apartado se va a utilizar la misma imagen utilizada en el apartado dedicado a la representación gráfica.

script_laboratorio_4_contraste.

INTRODUCCIÓN

Los sensores que portan los satélites están diseñados para recoger la energía o radiancia de una gran variedad de superficies, desde superficies acuáticas con baja radiancia hasta la nieve o la arena, que por el contrario muestran una gran radiancia. Por lo tanto, deben ser capaces de registrar la respuesta todas esas superficies, pero, en la mayoría de las ocasiones, tan sólo registran alguna de ellas. El que los valores de radiancia permanezcan confinados a un rango limitado reduce los contrastes de imagen, y por lo tanto, su calidad visual.

La mejora del contraste de una imagen digital es una técnica que modificar los niveles de grises originales de una imagen. Esto incrementa el contraste entre diferentes elementos de la imagen, lo cual a su vez mejora su calidad. Dentro de los diferentes métodos de mejora de contraste es posible diferenciar aquellos basados en métodos lineales y otros basados en métodos no lineales, cuyas diferentes metodologías serán revisadas en las siguientes líneas.

Las operaciones que componen esta técnica se dividen en operaciones de procesamiento pixel por pixel y operaciones de procesamiento por grupo de pixeles.

PASOS PREVIOS.

library(terra)
## Warning: package 'terra' was built under R version 4.3.3
## terra 1.8.21
library(RStoolbox)
## Warning: package 'RStoolbox' was built under R version 4.3.3
## This is version 1.0.0 of RStoolbox
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.3.3
library(rasterVis)
## Warning: package 'rasterVis' was built under R version 4.3.2
## Loading required package: lattice
## Warning: package 'lattice' was built under R version 4.3.2

A continuación, se realiza una lista de los ficheros que existen en la carpeta datos.

lista <- list.files("D:/G174_2025/LABORATORIO_4_Visualizacion_imagenes/datos/",   
                   pattern = ".*band[1234567]\\.tif$",                                      
                   ignore.case=TRUE,                                            
                   full.names = TRUE)

En tercer lugar, esa lista permite importar los ficheros en forma de un objeto SpatRaster.

imagen_landsat <- rast(lista)
imagen_landsat
## class       : SpatRaster 
## dimensions  : 1545, 1480, 7  (nrow, ncol, nlyr)
## resolution  : 30, 30  (x, y)
## extent      : 549615, 594015, 4613355, 4659705  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 29N (EPSG:32629) 
## sources     : LC82040312015193LGN00_sr_band1.tif  
##               LC82040312015193LGN00_sr_band2.tif  
##               LC82040312015193LGN00_sr_band3.tif  
##               ... and 4 more sources
## names       : LC820~band1, LC820~band2, LC820~band3, LC820~band4, LC820~band5, LC820~band6, ...

Como ya se ha señalado en ocasiones previas, la identificación de las bandas es complicada si se mantienen los nombres de los archivos originales, siendo conveniente su transformación en nombres de más fácil identificación.

names(imagen_landsat) <- gsub(pattern = "LC82040312015193LGN00_sr_",    
                           replace ="",                                         
                           x <- names(imagen_landsat))                          
imagen_landsat
## class       : SpatRaster 
## dimensions  : 1545, 1480, 7  (nrow, ncol, nlyr)
## resolution  : 30, 30  (x, y)
## extent      : 549615, 594015, 4613355, 4659705  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 29N (EPSG:32629) 
## sources     : LC82040312015193LGN00_sr_band1.tif  
##               LC82040312015193LGN00_sr_band2.tif  
##               LC82040312015193LGN00_sr_band3.tif  
##               ... and 4 more sources
## names       : band1, band2, band3, band4, band5, band6, ...

En este caso, sólo se necesitan las bandas 2, 3, 4 y 5 del objeto imagen, que tiene originalmente 7 bandas. Podemos proceder de dos maneras alternativas.

► Eliminando del objeto anterior imagen_landsat las bandas 1, 6 y 7. El objeto sigue siendo un SpatRaster.

imagen_landsat
## class       : SpatRaster 
## dimensions  : 1545, 1480, 7  (nrow, ncol, nlyr)
## resolution  : 30, 30  (x, y)
## extent      : 549615, 594015, 4613355, 4659705  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 29N (EPSG:32629) 
## sources     : LC82040312015193LGN00_sr_band1.tif  
##               LC82040312015193LGN00_sr_band2.tif  
##               LC82040312015193LGN00_sr_band3.tif  
##               ... and 4 more sources
## names       : band1, band2, band3, band4, band5, band6, ...
imagen_contraste <- subset(imagen_landsat, -c(1,6,7))
imagen_contraste
## class       : SpatRaster 
## dimensions  : 1545, 1480, 4  (nrow, ncol, nlyr)
## resolution  : 30, 30  (x, y)
## extent      : 549615, 594015, 4613355, 4659705  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 29N (EPSG:32629) 
## sources     : LC82040312015193LGN00_sr_band2.tif  
##               LC82040312015193LGN00_sr_band3.tif  
##               LC82040312015193LGN00_sr_band4.tif  
##               LC82040312015193LGN00_sr_band5.tif  
## names       : band2, band3, band4, band5

► Una segunda posiblidad es cargar las 4 imágenes directamente de la carpeta donde están almacenadas, uniéndolas posteriormente en un único objeto..

lista <- list.files("D:/G174_2025/LABORATORIO_4_Visualizacion_imagenes/datos/",                                 # Directorio de los datos
                    pattern = ".*band[2345]\\.tif$",            # El signo $ lista todos los ficheros que acaban igual
                    ignore.case=TRUE,                           # Sensible a mayúsculas y minúsculas
                    full.names = TRUE)
imagen_contraste <- rast(lista)

De nuevo, cambiamos los nombres de las bandas para que sean más inteligibles.

names(imagen_contraste) <- paste("B",
                    2:5,
                    sep="")
imagen_contraste
## class       : SpatRaster 
## dimensions  : 1545, 1480, 4  (nrow, ncol, nlyr)
## resolution  : 30, 30  (x, y)
## extent      : 549615, 594015, 4613355, 4659705  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 29N (EPSG:32629) 
## sources     : LC82040312015193LGN00_sr_band2.tif  
##               LC82040312015193LGN00_sr_band3.tif  
##               LC82040312015193LGN00_sr_band4.tif  
##               LC82040312015193LGN00_sr_band5.tif  
## names       : B2, B3, B4, B5

También es posible cambiar las bandas a su denominación original.

names(imagen_contraste) <- c("blue", "green", "red", "nir")
imagen_contraste
## class       : SpatRaster 
## dimensions  : 1545, 1480, 4  (nrow, ncol, nlyr)
## resolution  : 30, 30  (x, y)
## extent      : 549615, 594015, 4613355, 4659705  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 29N (EPSG:32629) 
## sources     : LC82040312015193LGN00_sr_band2.tif  
##               LC82040312015193LGN00_sr_band3.tif  
##               LC82040312015193LGN00_sr_band4.tif  
##               LC82040312015193LGN00_sr_band5.tif  
## names       : blue, green, red, nir

A continuación, se representa gráficamente la distribución de los valores de los píxeles de cada banda usando el siguiente código.

histogram(imagen_contraste, 
          col = "wheat", 
          main = "Histograma de las bandas", 
          xlab = "Valores de los píxeles")

A partir de los histogramas de las bandas del fichero raster se comprueba cómo, efectivamente, los valores de los píxeles suelen estar confinados a rangos muy concretos. A continuación se representa una imagen en falso color para verificar su calidad visual.

ggRGB(imagen_contraste,
      r=4, g=3, b=2, 
      stretch = "none") +
  ggtitle("Imagen sin mejorar") +                                      # Título
  labs(x = "Longitud (m)", y = "Latitud (m)") +                        # Etiquetas de los ejes x e y
        theme(plot.title = element_text(hjust = 0.5, size = 25),       # Título alineado al centro y con tamaño de 25
        axis.title = element_text(size=15)) +                           # Tamaños de las etiquetas ejes x e y 
  theme_minimal()

De acuerdo con la inspección visual de esa imagen, el contraste entre los elementos que lo componen es bajo. Por ello, sería conveniente aplicar algunas de la técnicas de mejora del contraste para mejorar a su vez la calidad visual de la imagen. Estas técnicas reciben el nombre de “estiramiento” (stretching)

TÉCNICAS DE CONTRASTE LINEAL

Mediante las técnicas de mejora linear, los números digitales de las imágenes originales son expandidos linearmente al rango completo de los niveles de gris. Puede ser realizado con R, a través de dos métodos, el contraste entre Máximo-Mínimos, y el contraste con porcentajes.

Contraste lineal entre máximos y mínimos.

Según este método, los valores máximo y mínimo de los píxeles de la imagen original se convierte en los valores máximo y mínimo del rango radiométrico total, y los valores reales se estiran linealmente entre esos valores preasignados.

ggRGB(imagen_contraste, 
      r=4, g=3, b=2, 
      stretch = "lin") +                                      
  ggtitle("Mejora de contraste, Método máx-mín") +                         # Título
  labs(x = "Longitud (m)", y = "Latitud (m)") +                        # Etiquetas de los ejes x e y
        theme(plot.title = element_text(hjust = 0.5, size = 25),       # Título alineado al centro y con tamaño de 25
        axis.title = element_text(size=15)) +                           # Tamaños de las etiquetas ejes x e y 
  theme_minimal()

Contraste lineal según porcentajes.

Este método es similar al anterior, excepto que en este método los valores máximos y mínimos representan un cierto porcentaje de píxeles respecto a la media del histograma. Supóngase que se desea aplicar un estiramiento lineal del 2%; esto significa que el 2% de los valores más bajos y el 2% de los valores más altos del histograma serán omitidos mientras se aplica esta mejora de contraste.

ggRGB(imagen_contraste, 
      r=4, g=3, b=2, 
      stretch = "lin", 
      quantiles = c(0.02,0.98)) +                                      # Porcentaje en forma de cuantiles
  ggtitle("Mejora de contraste, método 2 %") +                         # Título
  labs(x = "Longitud (m)", y = "Latitud (m)") +                        # Etiquetas de los ejes x e y
        theme(plot.title = element_text(hjust = 0.5, size = 25),       # Título alineado al centro y con tamaño de 25
        axis.title = element_text(size=15)) +                           # Tamaños de las etiquetas ejes x e y 
  theme_minimal()

TÉCNICAS DE CONTRASTE NO LINEAL.

Estas técnicas no “estiran” de manera lineal los valores de los píxeles, sino mediante algún tipo de algorítmo no lineal. Existen varios tipos diferentes.

Ecualización del histograma.

En este método, los valores de los píxeles son estirados dependiendo de su frecuencia en la imagen. A los valores de los píxeles que aparecen con más frecuencias se les asignan un rango de valores más amplio que a los que ocurren con menor frecuencia. Este método proporciona una mejora de los detalles de la imagen en aquellas zonas con valores que ocurren frecuentemente. Esta posibilidad está incluida tanto en el paquete raster como en RStoolbox

► Con el paquete terra.

plotRGB(imagen_contraste,
        r=4, g=3, b=2, 
        stretch = "hist",
        main = "Mejora de contraste a través de la ecualizacióndel histograma")

► Con el el paquete “RStoolbox”.

ggRGB(imagen_contraste, 
      r=4, g=3, b=2, 
      stretch = "hist") +  
  ggtitle("Mejora de contraste, método histograma") +                                      # Título
  labs(x = "Longitud (m)", y = "Latitud (m)") +                        # Etiquetas de los ejes x e y
        theme(plot.title = element_text(hjust = 0.5, size = 25),       # Título alineado al centro y con tamaño de 25
        axis.title = element_text(size=15)) +                           # Tamaños de las etiquetas ejes x e y 
  theme_minimal()

Contraste mediante la raíz cuadrada.

Este método calcula la raíz cuadrada del histograma de la imagen original y aplica un estiramiento lineal. Sirve para mejorar la parte más oscura de la imagen. Se utiliza para ello el argumento stretch = "sqrt"en la función ggRGB del paquete RStoolbox.

ggRGB(imagen_contraste, 
      r=4, g=3, b=2, 
      stretch = "sqrt") +  
  ggtitle("Mejora de contraste, método raíz cuadrada") +                                      # Título
  labs(x = "Longitud (m)", y = "Latitud (m)") +                        # Etiquetas de los ejes x e y
        theme(plot.title = element_text(hjust = 0.5, size = 25),       # Título alineado al centro y con tamaño de 25
        axis.title = element_text(size=15)) +                           # Tamaños de las etiquetas ejes x e y 
  theme_minimal()

Contraste logarítmico.

El método de estiramiento logarítmico reescala los valores originales de los píxeles de manera logarítmica, es decir, asigna a los valores más bajos un conjunto más amplio de nuevos valores, mientras que los píxeles originales con valores elevados reciben un rango de valores menor. Este método mejor los detalles de las áreas más oscuras de la imagen. Se utiliza para ello el argumento stretch = "log"en la función ggRGB del paquete RStoolbox.

ggRGB(imagen_contraste, 
      r=4, g=3, b=2, 
      stretch = "log") +  
  ggtitle("Mejora de contraste, método logarítmico") +                                      # Título
  labs(x = "Longitud (m)", y = "Latitud (m)") +                        # Etiquetas de los ejes x e y
        theme(plot.title = element_text(hjust = 0.5, size = 25),       # Título alineado al centro y con tamaño de 25
        axis.title = element_text(size=15)) +                           # Tamaños de las etiquetas ejes x e y 
  theme_minimal()

Contraste gausiano.

En este caso, el histograma de los valores de la imagen original es modificado para que se parezca a un histograma que sigue una distribución “normal” o gaussiAna.Se utiliza para ello el argumento norme = "TRUE"en la función normImage del paquete RStoolbox.

imagen_normalizada <- normImage(imagen_contraste, norm = TRUE)
imagen_normalizada
## class       : SpatRaster 
## dimensions  : 1545, 1480, 4  (nrow, ncol, nlyr)
## resolution  : 30, 30  (x, y)
## extent      : 549615, 594015, 4613355, 4659705  (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 29N (EPSG:32629) 
## source(s)   : memory
## names       :      blue,     green,       red,       nir 
## min values  : -1.972773, -2.565205, -2.141667, -3.997184 
## max values  : 17.135898, 16.460832, 13.083512,  5.169301

Posteriormente, podemos representarlo gráficamente. Téngase en cuenta que el argumento strech =ya no debe utilizarse aquí.

ggRGB(imagen_normalizada, 
      r=4, g=3, b=2) +  
  ggtitle("Mejora de contraste, método gaussiano") +                                      # Título
  labs(x = "Longitud (m)", y = "Latitud (m)") +                        # Etiquetas de los ejes x e y
        theme(plot.title = element_text(hjust = 0.5, size = 25),       # Título alineado al centro y con tamaño de 25
        axis.title = element_text(size=15)) +                           # Tamaños de las etiquetas ejes x e y 
  theme_minimal()

Dado que no se utilizará más los objetos creados hasta aquí, son eliminados del Global Environment para que no interfieran en el resto de la actividad

rm(list=ls())