Los humedales están formados por diferentes tipos de componentes como químicos, físicos y biológicos (suelos, agua, fauna, florea y nutrientes), los cuales en conjunto trabajan como un mecanismo de preservación del ecosistema y ofrecen bienes y servicios a la comunidad. Los beneficios que ofrecen estos ecositemas se dividen en:
Figura 1 :Valor total de la importancia de los humedales.
Fuente: Lineamientos para valorar los beneficios derivados de los servicios de los ecosistemas de humedales (Secretaría de la Convención de Ramsar, 2007)
Los humedales fueron reconocidos por la Convención de Ramsar, en 1971, como “las extensiones de marismas, pantanos y turberas, o superficies cubiertas de aguas, sean éstas de régimen natural o artificial, permanentes o temporales, estancadas o corrientes, dulces, salobres o saladas, incluidas las extensiones de agua marina cuya profundidad en marea baja no exceda de seis metros” (Ramsar, 2006).
Análisis Multitemporal:
A través de los años se ha venido creando la necesidad de estudiar los ecosistemas que ofrecen beneficios ecológicos y económicos para la sociedad, para darles un adecuado manejo sustentable, los cuales no eran fáciles de realizar en grandes extensiones, por ser un trabajo dispendioso ir al área de estudio, se vio la necesidad de crear herramientas que permitiesen analizar grandes extensiones de terreno de una manera más económica y efectiva. Al pasar los años instrumentos muy útiles como satélites que toman fotos cada cierto tiempo han ido apareciendo y con ello, la facilidad de observar de una mejor manera el área total a estudiar, sin embargo, el análisis de esas imágenes era dificultosa para el ojo humano, por lo que herramientas de software (Sistema de información geográfica SIG) fueron implementadas para esta tarea, herramientas a las cuales el público tiene acceso en la actualidad, softwares como lo son ArcGis, QGIS, SAGA GIS, GRASS GIS entre otros, son usadas con frecuencia; Una alternativa para analizar los componentes de las imágenes lo ofrece el software libre R, quien permite examinar dichos componentes de una manera más fácil y rápida por medio de simples líneas de códigos. Con este trabajo se quiere dar a conocer de qué manera estos códigos nos pueden ser útiles para el análisis de cambios de coberturas a través de los años del Humedal Juan Amarillo ubicado en la ciudad de Bogotá - Colombia, en los años 2014, 2015, 2016 y 2018 mediante imágenes satelitales y usando índices de vegetación (NDVI) gracias a funciones de clasificación no supervisada como K-means y CLARA.
El humedal Juan Amarillo o Laguna de Tibabuyes, está ubicado al noroccidente del distrito capital, perteneciente al área inundable de los ríos Bogotá y Juan Amarillo (también llamado Salitre); junto al humedal estos ríos conforman parte de la estructura principal del sistema hidríco de la ciudad. El humedal hace parte de dos localidades, el extremo norte está ubicado en Suba y la parte sur se localiza en Engativá. Con 220 hectáreas aproximadamente, se constituye como el humedal más grande que existe en la actualidad en Bogotá (Instituto de Estudio Urbanos - Link.).
El humedal Juan Amarillo a través del artículo 1 del Acuerdo 19 de 1994 fue declarado como Reserva Ambiental Natural y a través del artículo 95 del Decreto 190 de 2004 el nombre de Parque Ecológico Distrital Humedal (PEDH) fue declarado. Se encuentra dividido en tres tercios o fragmentos: tercio alto, medio y bajo; con diversidad de flora y fauna (Secretaría Distrital de Ambiente - Humedales Bogotá - Link.).
Figura 1. Humedal Juan Amarillo
Fuente: Elaboración propia
General: Analizar registros históricos bibliográficos de la variación temporal del humedal Juan Amarillo y comparar resultados con análisis de imágenes satelitales procesadas con Arcgis y R, para los años 2014, 2015, 2016 y 2018.
Con base en reportes de literatura se conformó la base de datos que posee información de los años 2014 a 2019 (un registro por año), de las siguientes variables:
Los registros para cada variable fueron obtenidos de repositorios de acceso abierto. Las temperaturas promedio, mínimos y máximos anuales, fueron consultadas de la estación metereológica El Dorado, por estar cercana al humedal.
Se tomaron 4 imágenes del satelite Landsat 8, una para cada año evaluado (2014, 2015, 2016 y 2018) en un mes específico, se intentó encontrar información de imágenes satelitales para los años 2017 y 2019, pero no fue posible ya que las plataformas de descarga solo contaban con la disponibilidad de algunas imágenes con alto porcentaje de nubosidad que cubrian de manera parcial el área de estudio.
| Día | Mes | Año |
|---|---|---|
| 1 | Enero | 2014 |
| 4 | Enero | 2015 |
| 10 | Marzo | 2016 |
| 17 | Marzo | 2018 |
Las imágenes fueron escogidas basado en la calidad de las mismas y por disposición en el sitio web EARTH OBSERVING SYSTEM - EOS, el cual suministra herramientas fáciles de usar para la obtención de imágenes sateliteles con intereses diversos (coberturas vegetales, cuerpos de agua, agricultura, minería, etc.). EOS Posibilita la capacidad de obtener imágenes de alta calidad con bajos niveles de nubosidad. Para cada año se obtuvieron imágenes del satelite Landsat 8, de la estación LGN e identificación del sensor OLI TIRS; todos estos datos están presentes en el archivo metadados (ej: LC08_L1TP_008057_20140101_20170427_01_T1_MTL.txt) de cada imágen descargada. Las bandas utilizadas fueron las siguientes:
Figura 2. Bandas Landsat8
Se calculó el Índice de Vegetación de Diferencia Normalizada (NDVI), que permite estimar la cantidad, calidad y desarrollo de la vegetación. Este índice oscila entre -1 y 1, valores superiores a 0.4 pueden ser considerados como vegetación. La ecuación para obtener el NDVI es la siguiente: (EARTH OBSERVING SYSTEM - EOS.)
\[NDVI = \frac{Infrarrojo\ cercano\ -\ Rojo}{Infrarrojo\ cercano\ +\ Rojo} = \frac{Banda5\ -\ Banda4}{Banda5\ +\ Banda4}\]
Inicialmete las imágenes fueron procesadas con el software Arcgis para unión de bandas, digitalización y delimitación del área del humedal. Posteriormente, la imagen procesada para cada año se exporta en formato .tif (Tagged Image File) para ser importada a R.
Haciendo uso de múltiples bibliotecas de R se llevaron a cabo procesos de depuración, integración y visualización de datos espaciales (raster y shp). Se importaron todas la imágenes en el R, se visualizaron y se utilizó el algoritmo k-means (método de Lloyd) para clusterización de pixeles (clasificación no supervisada) y el agoritmo CLARA (Clustering Large Applications) La siguiente tabla muestra algunas de las bibliotecas usadas en el desarrollo de este trabajo.
library(readxl)
datos <- read_xlsx("datos_fin.xlsx")
datos
| Fecha | Area_Ha | poblacion | tem_pro | tem_min | tem_max | dias_lluvia | dias_tormen |
|---|---|---|---|---|---|---|---|
| 2014 | 247.5573 | 7776845 | 13.8 | 8.9 | 19.6 | 214 | 81 |
| 2015 | 250.0564 | 7878783 | 14.1 | 9.0 | 20.0 | 183 | 48 |
| 2016 | 167.1542 | 7980001 | 14.3 | 9.0 | 20.1 | 209 | 67 |
| 2017 | 212.9809 | 8080734 | 13.9 | 8.9 | 20.1 | 197 | 68 |
| 2018 | 225.2469 | 8181047 | 13.9 | 8.9 | 19.8 | 206 | 72 |
| 2019 | 217.7680 | 8281030 | 14.4 | 7.9 | 21.9 | 111 | 46 |
El área del Humedal Juan Amarillo para el año 2012 es de 222,76 hectáreas (Fajardo López, 2012 - LINK), se puede observar que las áreas halladas con ArcGis varían entre 167.15 Ha y 250.05 Ha, cálculos que está sujetos a errores humanos ya que la delimitación de las mismas se realizaron de forma manual. Temperaturas promedio varían de 13.8 °C a 14.4 °C con unas temperaturas mínimas de 7.9 °C y unas máximas de 21.9 °C
library(dplyr)
library(ggplot2)
library(RColorBrewer)
library(ggpubr)
library(tidyr)
ggarrange(
datos %>%
ggplot(data = ., aes(x = Fecha, y = Area_Ha)) +
geom_point(size = 3, pch = 19) +
geom_line() +
ylim(0, 260) +
labs(x = "Año", y = "Área (Ha)",
title = "Variación temporal del área") +
theme_bw() ,
datos %>%
ggplot(data = ., aes(x = Fecha, y = poblacion/1e+06)) +
geom_point(size = 3, pch = 19) +
geom_line() +
geom_text(aes(label = round(poblacion/1e+06, digits = 4)), nudge_y = 45000/1e+06) +
labs(x = "Año", y = "Personas (millones)",
title = "Población Bogotá") +
theme_bw(),
datos %>%
select(Fecha, tem_pro, tem_min, tem_max) %>%
gather(key = "medida", value = "temp", -Fecha) %>%
ggplot(data = ., aes(x = Fecha, y = temp, color = medida)) +
geom_point(size = 3) +
geom_line() +
scale_color_brewer(palette = "Set1") +
labs(x = "Año", y = "°C",
title = "T. máximas, mínimas y promedio",
subtitle = "Estación El Dorado", color = "") +
theme_bw() +
theme(legend.position = "bottom"),
datos %>%
select(Fecha, dias_lluvia, dias_tormen) %>%
gather(key = "medida", value = "dias", -Fecha) %>%
ggplot(data = ., aes(x = Fecha, y = dias, color = medida)) +
geom_point(size = 3) +
geom_line() +
scale_color_brewer(palette = "Set1") +
labs(x = "Año", y = "°C",
title = "Días de lluvia y tormenta",
subtitle = "Estación El Dorado", color = "") +
theme_bw() +
theme(legend.position = "bottom"),
ncol = 2, nrow = 2
)
Como ya se mencionó, el cálculo del área se realizó de forma manual, por lo tanto, puede presentar algunos sesgos en comparación con la literatura consultada, de igual forma, se puede apreciar que el área el humedal va disminuyendo a medida que pasan los años, fenómeno que se viene presentando de manera significativa desde los años 50 (Camargo, 2016). Se puede apreciar un aumento significativo de la población según bases de datos tomadas del DANE (Departamento Administrativo Nacional de Estadística) con relación a los años, valores que concuerdan con el Análisis demográfico y proyecciones poblacionales de Bogotá realizado en marzo del año 2018 por la secretaría distrital de planeación LINK Temperaturas máximas y mínimas no presentan una variación significativa, a excepción el año 2019, esto se puede presentar gracias a que aún no se posee los datos de los mese restantes, por lo que el promedio puede variar un poco más con respecto a los otros años. El comportamiento entre los días de lluvias y tormentas puede presentar muchas variaciones para cada año, ya que la fuente no posee los datos para todos los días
g1 <- datos %>%
ggplot(data = ., aes(x = poblacion/1e+06, y = Area_Ha)) +
geom_point(size = 4) +
geom_smooth(method = "lm", se = FALSE, color = "blue", size = 1.5) +
labs(x = "Personas (millones)", y = "Área (ha)",
subtitle = "Población vs Área") +
theme_bw()
g2 <- datos %>%
ggplot(data = ., aes(x = tem_pro, y = Area_Ha)) +
geom_point(size = 4) +
geom_smooth(method = "lm", se = FALSE, color = "blue", size = 1.5) +
labs(x = "°C", y = "Área (ha)",
subtitle = "Temperatura promedio vs Área") +
theme_bw()
g3 <- datos %>%
ggplot(data = ., aes(x = tem_min, y = Area_Ha)) +
geom_point(size = 4) +
geom_smooth(method = "lm", se = FALSE, color = "blue", size = 1.5) +
labs(x = "°C", y = "Área (ha)",
subtitle = "Temperatura mínima vs Área") +
theme_bw()
g4 <- datos %>%
ggplot(data = ., aes(x = tem_max, y = Area_Ha)) +
geom_point(size = 4) +
geom_smooth(method = "lm", se = FALSE, color = "blue", size = 1.5) +
labs(x = "°C", y = "Área (ha)",
subtitle = "Temperatura máxima vs Área") +
theme_bw()
g5 <- datos %>%
ggplot(data = ., aes(x = dias_lluvia, y = Area_Ha)) +
geom_point(size = 4) +
geom_smooth(method = "lm", se = FALSE, color = "blue", size = 1.5) +
labs(x = "Días", y = "Área (ha)",
subtitle = "Días con lluvia vs Área") +
theme_bw()
g6 <- datos %>%
ggplot(data = ., aes(x = dias_tormen, y = Area_Ha)) +
geom_point(size = 4) +
geom_smooth(method = "lm", se = FALSE, color = "blue", size = 1.5) +
labs(x = "Días", y = "Área (ha)",
subtitle = "Días con tormenta vs Área") +
theme_bw()
ggarrange(g1, g2, g3, g4, g5, g6, ncol = 3, nrow = 2)
Las anteiores gráficas están sujetas a un tamaño de muestra de 6 (los seis años analizados: 2014, 2015, 2016,2017,2018, 2019) las cúales pueden mostrar relaciones similares a la realidad aumentando el tamaño de la muestra.
modelo <- lm(Area_Ha ~ tem_pro, data = datos)
summary(modelo)
##
## Call:
## lm(formula = Area_Ha ~ tem_pro, data = datos)
##
## Residuals:
## 1 2 3 4 5 6
## 10.043 32.103 -37.759 -18.013 -5.747 19.375
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1137.31 744.97 1.527 0.202
## tem_pro -65.20 52.95 -1.231 0.286
##
## Residual standard error: 28.68 on 4 degrees of freedom
## Multiple R-squared: 0.2749, Adjusted R-squared: 0.09357
## F-statistic: 1.516 on 1 and 4 DF, p-value: 0.2856
El modelo, aunque no es signifivativo (p=0.2856) permite inferir que por cada grado que aumenta la temperatura anualmente, el humedal disminuye aproximadamente 65.20 hectáreas. Esta relación es netamente matemática (no se presenta en la vida real) por lo tanto, esta sujeta a validaciones con un tamaño de muestra superior.
El modelo ajustado se puede expresar de la siguiente manera:
\[área = 1137.31 -\ 65.20*temperatura\]
# Cargando bibliotecas
library(sp)
library(raster)
library(landsat8)
library(tidyverse)
# Función brick() multibanda
# Función raster() una banda
tif_nat14 <- brick(x = "FINAL/imagenes/2014/inflarojo_verdadero/color_verdadero2014.tif")
plot(tif_nat14)
tif_inf14 <- brick(x = "FINAL/imagenes/2014/inflarojo_verdadero/infrarrojo2014.tif")
plot(tif_inf14)
# Lectura de .shp
shape_ja <- shapefile("FINAL/Humedal_2014_01_01.shp")
plot(shape_ja)
La lectura del formato .TIF muestra las bandas que componen cada imagen por separado, lo cual facilita la observación de cada una.
# Cuatro gráficos en uno
par(mfrow = c(2, 2))
# Una banda
plot(tif_nat14[[1]],
main = "Banda 4")
plot(tif_nat14[[1]],
main = "Banda 4\nDos colores",
col = terrain.colors((2)))
plot(tif_nat14[[1]],
main = "Banda 4\nCuatro colores",
col = terrain.colors((4)))
plot(tif_nat14[[1]],
main = "Banda 4\nSeis colores",
col = terrain.colors((6)))
A medida que se va aumentando el número de colores en cada banda, se puede apreciar una diferenciación más clara de cada color, lo que permite la observación de direntes cobertura vegetales.
# 3 gráficos en uno
par(mfrow = c(2, 2))
# Todas las bandas
plot(tif_nat14[[1]],
main = "Banda 4")
plot(tif_nat14[[2]],
main = "Banda 3")
plot(tif_nat14[[3]],
main = "Banda 2")
Se puede apreciar la lectura de las bandas que se combinan para dar paso al el color natural de la imagen, la cúal involucra tres bandas visibles (2,3,4), a cada banda se le asigna su verdadero color y cuando se combinan, genera una imágen con el color real de la escena. LINK
# Cuatro gráficos en uno
par(mfrow = c(2, 2))
# Una banda
plot(tif_inf14[[1]],
main = "Banda 5")
plot(tif_inf14[[1]],
main = "Banda 5\nDos colores",
col = terrain.colors((2)))
plot(tif_inf14[[1]],
main = "Banda 5\nCuatro colores",
col = terrain.colors((4)))
plot(tif_inf14[[1]],
main = "Banda 5\nSeis colores",
col = terrain.colors((6)))
A medida que se van sumando colores a la banda, se puede apreciar de una manera más clara la diferenciación entre coberturas vegetales, se puede además ver que se puede apreciar mejor la diferencia entre coberturas en el área urbana cuando se hace el paso de cuatro colores a seis colores.
# 3 gráficos en uno
par(mfrow = c(2, 2))
# Todas las bandas
plot(tif_inf14[[1]],
main = "Banda 5")
plot(tif_inf14[[2]],
main = "Banda 4")
plot(tif_inf14[[3]],
main = "Banda 3")
Al asignarle el color rojo a la banda 4 (infrarroja cercana) esta banda va a tener ciertas similitudes con la combinación RGB 4,3,2 . Sin embargo, al dar más peso a la región infrarroja (bandas 4 y 5) se ve realzada la diferencia de humedad en suelos y vegetales. Generalmente cuanto mayor es la humedad del suelo más oscuro aparecerá éste. LINK
par(mfrow = c(1, 3))
# tres gráficos en uno
hist(tif_nat14[[1]],
xlab = "Frecuencia", ylab = "Nivel Digital (ND)",
main = "Distribución de ND\nBanda 4")
hist(tif_nat14[[2]],
xlab = "Frecuencia", ylab = "Nivel Digital (ND)",
main = "Distribución de ND\nBanda 3")
hist(tif_nat14[[3]],
xlab = "Frecuencia", ylab = "Nivel Digital (ND)",
main = "Distribución de ND\nBanda 2")
Cada ND (Nivel digital) representa un área de la tierra en un lugar específico. El valor de ND asignado al píxel esta en función de la luz reflejada o emitida de la porción de la superficie terrestre LINK,en el histograma de la banda dos, algunos son valores negativos, aunque son pocos, pueden indicar daños en la imagen o en los pixeles, el histograma de los niveles digitales puede resultar muy útil a la hora de visualzar valores extremos.
par(mfrow = c(1, 3))
# tres gráficos en uno
hist(tif_inf14[[1]],
xlab = "Frecuencia", ylab = "Nivel Digital (ND)",
main = "Distribución de ND\nBanda 5")
hist(tif_inf14[[2]],
xlab = "Frecuencia", ylab = "Nivel Digital (ND)",
main = "Distribución de ND\nBanda 4")
hist(tif_inf14[[3]],
xlab = "Frecuencia", ylab = "Nivel Digital (ND)",
main = "Distribución de ND\nBanda 3")
# Conversión de coordenadas para poder realizar corte
shape_ja2 <- spTransform(shape_ja, CRS = crs(tif_nat14))
# Bandas a cortar
bandas_nat14 <- crop(tif_nat14, extent(shape_ja2))
corte_nat14 <- mask(bandas_nat14, shape_ja2)
# Gráfico
names(corte_nat14) <- paste("Banda", c(5, 3, 2), sep="")
plot(corte_nat14)
Se leyó el shape de área creado en ArcGis y se le introdujo las mismas coordenadas de la imagen para posteriormente recortarla y extraerla por máscara (procesos que se lleva a cabo en ArcGis con la función Extract by mask), cada banda se muestra por separado.
# Bandas a cortar
bandas_inf14 <- crop(tif_inf14, extent(shape_ja2))
corte_inf14 <- mask(bandas_inf14, shape_ja2)
# Gráfico
names(corte_inf14) <- paste("Banda", c(5, 4, 3), sep="")
plot(corte_inf14)
plotRGB(tif_nat14, r=4, g=3, b=2, stretch="lin", main="RGB composición (b4,b3,b2) de Landsat-8")
plotRGB(corte_nat14, r=4, g=3, b=2, stretch="lin", main="RGB composición (b4,b3,b2) de Landsat-8")
plotRGB(tif_inf14, r=5, g=4, b=3, stretch="lin", main="RGB composición (b8,b4,b2) de Landsat-8")
plotRGB(corte_inf14, r=5, g=4, b=3, stretch="lin", main="RGB composición (b8,b4,b2) de Landsat-8")
Se realizó la combinación de bandas para dar paso a las imágenes de infrarrojo y color natural, se procede a recortar el shape del área del humedal y se extrae por máscara.
ndvi <- (tif_inf14[[1]] - tif_inf14[[2]])/(tif_inf14[[1]] + tif_inf14[[2]])
summary(ndvi)
## layer
## Min. -0.9926199
## 1st Qu. 0.1374676
## Median 0.2707559
## 3rd Qu. 0.5568026
## Max. 1.2758621
## NA's 1206.0000000
hist(ndvi)
El histograma de los niveles digitales del NDVI muestra claramente que los valores se encuentran dede -1 a 1, tal como se encuentra en la literatura, estos valores son los que permiten hacer la interpretación de este índice.
plot(ndvi, col = rev(terrain.colors(30)), main = 'NDVI desde landast8')
El intervalo de valores posibles oscila entre -1 y 1. Los valores negativos están asociados a zonas de agua y nieve. Valores positivos próximos a 0 representan zonas rocosas y desnudas que pueden adquirir algo de vegetación hasta llegar a valores próximos a 0.3. A partir de este valor encontramos presencia de vegetación densa. Cuanto mayor sea el valor más frondosa será la vegetación hasta adquirir valores próximos a 1. (Gisandbeers, 2016)[http://www.gisandbeers.com/calculo-del-indice-ndvi/] Se puede apreciar con claridad los cuerpos de agua que presentan un color rosado, el color verde denota vegetación y el amarillo área urbana. El histograma de los Niveles digitales muestra que hay un valor por encima de 1, por lo cúal se procede a la depuración de este valor
Quitando valores menores a -1 y mayores a 1 (valores erroneos).
veg1 <- calc(ndvi, function(x){x[x < -1] <- NA; return(x)})
veg1 <- calc(veg1, function(x){x[x > 1] <- NA; return(x)})
plot(veg1, main = 'Coberturas', col = rev(terrain.colors(8)))
Con la obteción de la gráfica de los niveles digitales, se pudo observar que había un valor mayor 1, se procedió a depurar los valores extremos para garantizar que los valor coincidan con los valores encontrados en la literaruta para el NDVI de -1 a 1
Quitando valores menores a 0.4 para mostrar vegetación.
veg2 <- calc(ndvi, function(x){x[x < 0.4] <- NA; return(x)})
veg2 <- calc(veg2, function(x){x[x > 1] <- NA; return(x)})
plot(veg2, main = 'Cobertura vegetal\nNDVI > 0.4')
Cuerpos de agua parecen estar entre -0.14 y -1.
cuts <- seq(minValue(veg1), maxValue(veg1), length.out=8)
cuts = round(cuts, digits = 2)
col.regions = brewer.pal(length(cuts)+2, "RdYlGn")
spplot(as(ndvi, 'SpatialGridDataFrame'),
at=cuts, col.regions=col.regions,colorkey=list(labels=list(at=cuts),at=cuts),
pretty=TRUE,scales=list(draw=T), main = "Cuerpos de agua\nNDVI entre -0.14 y -1")
Todo el proceso anterior se lleva a cabo con los años 2015,2016 y 2018
Los valores negativos indican la presencia de agua (color rosado y rojo), valores cercanos al 1 indican vegetación saludable (color verde y verde claro) y valores cercanos a cero indican áreas urbanizadas.
NDVI para el área de estudio:
Agrupa las observaciones en K clusters distintos, donde el número K lo determina el analista antes de ejecutar del algoritmo. K-means clustering encuentra los K mejores clusters, entendiendo como mejor cluster aquel cuya varianza interna (intra-cluster variation) sea lo más pequeña posible. Se trata por lo tanto de un problema de optimización, en el que se reparten las observaciones en K clusters de forma que la suma de las varianzas internas de todos ellos sea lo menor posible. Amat Rodrigo, 2017
Clasificación con k-means - 5 grupos:
El número de segmentos es igual a 5.
# Semilla para garantizar replicabilidad en el resultado
set.seed(1000)
# Obteniendo valores del ndvi para algoritmo kmeans
tablavalores <- getValues(ndvi)
# Algoritmo kmeans con 5 grupos
km <-kmeans(na.omit(tablavalores), centers = 5, iter.max = 500, nstart = 3)
rNA <- setValues(raster(ndvi), 0)#crear un raster en blanco con valores por defecto 0
for(i in 1:nlayers(ndvi)){ rNA[is.na(ndvi[[i]])] <- 1}# asignar valor de 1 a valores NA del raster
rNA <- getValues(rNA)#convertir rNA en un vector de valores
tablavalores <- as.data.frame(tablavalores)#convertir tablavalores en un data frame
tablavalores$clase[rNA==0] <- km$cluster #Si rNA es 0, asignar el valor del cluster k-mean
tablavalores$clase[rNA==1] <- NA#Si rNA es 1, asignar NA
clases <- raster(ndvi)
clases <- setValues(clases, tablavalores$clase)#asignar los valores del raster clases a partir de tablavalores$clase
colors<-c("black", "blue", "white","red","green")
plot(clases, legend=TRUE, col=colors)
En la imagen el azul parece indicar las carreteras, el color verde la vegetacíón y el color rojo las áreas urbanas. Aunque no es la mejor clasificación permite apreciar algunos segmentos.
Clasificación con k-means - 6 grupos:
El número de segmentos es igual a 6.
# Semilla para garantizar replicabilidad en el resultado
set.seed(1000)
# Algoritmo kmeans con 5 grupos
km6 <-kmeans(na.omit(tablavalores), centers = 6, iter.max = 500, nstart = 3)
rNA <- setValues(raster(ndvi), 0)#crear un raster en blanco con valores por defecto 0
for(i in 1:nlayers(ndvi)){ rNA[is.na(ndvi[[i]])] <- 1}# asignar valor de 1 a valores NA del raster
rNA <- getValues(rNA)#convertir rNA en un vector de valores
tablavalores <- as.data.frame(tablavalores)#convertir tablavalores en un data frame
tablavalores$clase[rNA==0] <- km6$cluster #Si rNA es 0, asignar el valor del cluster k-mean
tablavalores$clase[rNA==1] <- NA#Si rNA es 1, asignar NA
clases <- raster(ndvi)
clases <- setValues(clases, tablavalores$clase)#asignar los valores del raster clases a partir de tablavalores$clase
colors<-c("orangered", "blue", "black","green","red", "magenta4")
plot(clases, legend=TRUE, col=colors)
Los seis grupos se pueden resumir para conocer sus valores (centroides) promedio:
km6$centers
## tablavalores clase
## 1 0.39720287 1
## 2 0.54481958 2
## 3 0.23015482 3
## 4 0.79987596 5
## 5 0.64666709 2
## 6 0.09766934 4
Clasificación con k-means - 7 grupos:
El número de segmentos es igual a 7.
# Semilla para garantizar replicabilidad en el resultado
set.seed(1000)
# Algoritmo kmeans con 5 grupos
km7 <-kmeans(na.omit(tablavalores), centers = 7, iter.max = 500, nstart = 3)
rNA <- setValues(raster(ndvi), 0)#crear un raster en blanco con valores por defecto 0
for(i in 1:nlayers(ndvi)){ rNA[is.na(ndvi[[i]])] <- 1}# asignar valor de 1 a valores NA del raster
rNA <- getValues(rNA)#convertir rNA en un vector de valores
tablavalores <- as.data.frame(tablavalores)#convertir tablavalores en un data frame
tablavalores$clase[rNA==0] <- km7$cluster #Si rNA es 0, asignar el valor del cluster k-mean
tablavalores$clase[rNA==1] <- NA#Si rNA es 1, asignar NA
clases <- raster(ndvi)
clases <- setValues(clases, tablavalores$clase)#asignar los valores del raster clases a partir de tablavalores$clase
colors<-c("orangered", "blue", "black","green","red", "magenta4", "yellow")
plot(clases, legend=TRUE, col=colors)
as.data.frame(km7$centers)
| tablavalores | clase |
|---|---|
| 0.7998760 | 4 |
| 0.2719272 | 3 |
| 0.0976693 | 6 |
| 0.3972029 | 1 |
| 0.6466671 | 5 |
| 0.1976722 | 3 |
| 0.5448196 | 2 |
Clasificación con k-means - 8 grupos:
El número de segmentos es igual a 8.
# Semilla para garantizar replicabilidad en el resultado
set.seed(1000)
# Algoritmo kmeans con 5 grupos
km8 <-kmeans(na.omit(tablavalores), centers = 8, iter.max = 500, nstart = 3)
rNA <- setValues(raster(ndvi), 0)#crear un raster en blanco con valores por defecto 0
for(i in 1:nlayers(ndvi)){ rNA[is.na(ndvi[[i]])] <- 1}# asignar valor de 1 a valores NA del raster
rNA <- getValues(rNA)#convertir rNA en un vector de valores
tablavalores <- as.data.frame(tablavalores)#convertir tablavalores en un data frame
tablavalores$clase[rNA==0] <- km8$cluster #Si rNA es 0, asignar el valor del cluster k-mean
tablavalores$clase[rNA==1] <- NA#Si rNA es 1, asignar NA
clases <- raster(ndvi)
clases <- setValues(clases, tablavalores$clase)#asignar los valores del raster clases a partir de tablavalores$clase
colors<-c("white", "blue", "black","forestgreen","red", "magenta4", "yellow", "cyan")
plot(clases, legend=TRUE, col=colors)
Resumen de los 8 grupos:
as.data.frame(km8$centers)
| tablavalores | clase |
|---|---|
| 0.1277669 | 3.00000 |
| 0.1976722 | 6.00000 |
| 0.2719272 | 2.00000 |
| 0.7998760 | 1.00000 |
| 0.4707574 | 4.29485 |
| 0.0635455 | 3.00000 |
| 0.5448196 | 7.00000 |
| -0.2997597 | 3.00000 |
CLARA selecciona una muestra aleatoria de un tamaño determinado y le aplica el algoritmo de PAM (K-medoids) para encontrar los clusters óptimos acorde a esa muestra. Utilizando esos medoids se agrupan las observaciones de todo el set de datos. La calidad de los medoids resultantes se cuantifica con la suma total de las distancias entre cada observación del set de datos y su correspondiente medoid (suma total de distancias intra-clusters). AmatRodrigo,2017
En la clasificación del algoritmo CLARA con 6 grupos, aún no se puede apreciar bien la diferencia entre el cuerpo de agua y algunas áreas urbanas, por lo tanto una clasificación con 8 grupos como en el algoritmo K-means se podría apreciar mejor el cuerpo de agua.
El Humedal Juan Amarillo es el más grande que sobrevive en la ciudad de Bogotá, en la antiguedad hacía parte de una laguna que cubría toda la sabana, era un sitio importante de reunión de la cultura muisca, quienes a su al rededor hacian numerosos rituales al dios Chibchacun para favorecer sus cosechas (Alcaldía Local de Suba. “Indagación indígena y afrocolombiana”), se ha visto sometido a procesos antrópicos importantes uno de ellos es la construcción de barrios como Lisboa, Los Pórticos, Atenas de Suba, Quintas de Santa Bárbara, Villa Cristina, Luis Carlos Galán, Sidauto, Santa Teresa y Corinto de Suba que han afectado la conectividad del ecosistema fragmentandolo hasta llegar al punto de volverlo solo una laguna que para el año 2016 cuenta con un espejo de agua de 21.39 ha lo cual demuestra que el área se ha reducido en un 85.98% desde la década de los 50 en la cual su territorio era de 102.47 ha con una zona de amortiguamiento de 50.09 ha, la construcción del jarillón en 1969 ayudó a que se desecara el humedal [(Cruz Solano, Motta Morales & García Ubaque,2007)][http://repository.udistrital.edu.co/bitstream/11349/5345/1/CruzSolanoDianaPaola2017.pdf], el área de los años 2014,2015,2016 y 2018 usadas para este trabajo se calcularon de forma manual en el Arcgis por lo que pueden presentar variaciones con respecto a la literatura consultada.
El cambio del espejo de agua se pudo observar solamente en la laguna altificial que se encuentra en el tercio alto del humedal, fuermentemente afectada por la invasión de buchón, tanto así que para el año 2017 se hizo la remoción de 37 toneladas de dicha planta, el tercio medio y bajo presenta una cobertura vegetal que dificulta la visualización del espejo de agua, solo es posible identificarla visitando el área de estudio, pero en la literatura se ha encontrado plantas como el papiro (Cyperus papyrus), enea (Typha), elechos y lentejas de agua (Lemna) [(Cajal, n.d.)][https://www.lifeder.com/humedal-juan-amarillo-tibabuyes/] se podría hacer el estudio del cambio de área en los tercios medio y bajo analizando las profundidades que presenta el humedal a lo largo de los años
En el tercio medio y bajo del humedal se ubican especies en peligro de extinción como la tingua bogotana (Rallus semiplumbeus), musgo de pantano, hasta hace poco tiempo se registraba el cucarachero de pantano (Cistothorus apolinari) y otras especies que no están en peligro pero que son importantes para el equilibrio del ecositema como monjitas (Chrysomus icterocephalus), curies (Cavia porcellus), comadrejas (Mustela nivalis), zarigueyas, entre otros (Bernal,2016), por lo que es importante su recuperación y conservación.
La clasificación y posterior segmentación de una imagen es importante para identificar los componentes de la misma, y que los datos de vital importancia queden bien distinguidos, para este trabajo se realizó la comparacin de los algoritmos K-means y CLARA. PAM (Partitioning Around Medoids) usa k-means para identificar agrupamientos,trabaja bien en bases de datos pequeñas, pero es lento en grandes. Esto originó el desarrollo de CLARA (Clustering Large Applications) crea múltiples muestras de los datos y entonces aplica PAM a la muestra (Minería de datos espaciales, capítulo 2),sin embargo tambien se mostró efectivo a la hora de hacer la clasificación de las coberturas vegetales,con K-means se obtubo como resultado una buena clasificación para los cuerpos de agua cuando éste tenía 8 grupos. Los algoritmos de Machine learning de análisis no supervisado se posicionan como herramientas importantes para el procesamiento de imágenes satelitales, los cuales están en continua evolución.
# Imprimiento información de tif_nat14
tif_nat14
## class : RasterBrick
## dimensions : 268, 463, 124084, 3 (nrow, ncol, ncell, nlayers)
## resolution : 30, 30 (x, y)
## extent : 593235, 607125, 518865, 526905 (xmin, xmax, ymin, ymax)
## crs : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
## source : C:/Users/USER/Documents/GEOMATICA_APLICADA2/RESULTADOS/FINAL/imagenes/2014/inflarojo_verdadero/color_verdadero2014.tif
## names : color_verdadero2014.1, color_verdadero2014.2, color_verdadero2014.3
## min values : -253, -232, -2000
## max values : 6848, 6896, 5781
# Nùmero de capas
nlayers(tif_nat14)
## [1] 3
# Coordenadas de referencia tif_nat14
crs(tif_nat14)
## CRS arguments:
## +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84
## +towgs84=0,0,0
# Coordenadas de referencia shape_ja
crs(shape_ja)
## CRS arguments:
## +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666
## +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +units=m +no_defs
# Conversión a tipo dataframe desde el paquete raster
df_2014 <- raster::as.data.frame(tif_inf14, xy = TRUE)
# Eliminando datos NA
df_2014 <- na.omit(df_2014)
# Cambiando nombres
names(df_2014) <- c("x", "y", "value")
# Raster
df_2014 %>%
ggplot(data =., aes(x = x, y = y, fill = value)) +
geom_raster() +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3")
# Raster
df_2014 %>%
ggplot(data =., aes(x = x, y = y, fill = value)) +
geom_raster() +
scale_fill_viridis_c() +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3",
subtitle = "Infrarojo")
# Raster
df_2014 %>%
ggplot(data =., aes(x = x, y = y, fill = value)) +
geom_raster() +
scale_fill_viridis_c(option = "plasma") +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3",
subtitle = "Infrarojo")
# Raster
df_2014 %>%
ggplot(data =., aes(x = x, y = y, alpha = value)) +
geom_raster() +
scale_alpha(range = c(0.15, 0.65), guide = "none") +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3",
subtitle = "Infrarojo - Grises 1")
# Raster
df_2014 %>%
ggplot(data =., aes(x = x, y = y, alpha = value, fill = value)) +
geom_raster() +
scale_fill_viridis_c() +
scale_alpha(range = c(0.7, 1), guide = "none") +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3",
subtitle = "Infrarojo")
# Conversión a tipo dataframe desde el paquete raster
corte_2014 <- raster::as.data.frame(corte_inf14, xy = TRUE)
# Eliminando datos NA
corte_2014 <- na.omit(corte_2014)
# Cambiando nombres
names(corte_2014) <- c("x", "y", "value")
# Raster
corte_2014 %>%
ggplot(data =., aes(x = x, y = y, fill = value)) +
geom_raster() +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3")
# Raster
corte_2014 %>%
ggplot(data =., aes(x = x, y = y, fill = value)) +
geom_raster() +
scale_fill_viridis_c() +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3",
subtitle = "Infrarojo")
# Raster
corte_2014 %>%
ggplot(data =., aes(x = x, y = y, fill = value)) +
geom_raster() +
scale_fill_viridis_c(option = "plasma") +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3",
subtitle = "Infrarojo")
# Raster
corte_2014 %>%
ggplot(data =., aes(x = x, y = y, alpha = value)) +
geom_raster() +
scale_alpha(range = c(0.15, 0.65), guide = "none") +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3",
subtitle = "Infrarojo - Grises 1")
# Raster
corte_2014 %>%
ggplot(data =., aes(x = x, y = y, alpha = value, fill = value)) +
geom_raster() +
scale_fill_viridis_c() +
scale_alpha(range = c(0.7, 1), guide = "none") +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3",
subtitle = "Infrarojo")
# Conversión a tipo dataframe desde el paquete raster
clase_df <- raster::as.data.frame(clases, xy = TRUE)
# Eliminando datos NA
clase_df <- na.omit(clase_df)
# Cambiando nombres
names(clase_df) <- c("x", "y", "value")
# Raster
clase_df %>%
ggplot(data =., aes(x = x, y = y, fill = value)) +
geom_raster() +
theme_bw() +
labs(fill = "", title = "Banda 5, 4 y 3")
writeRaster(clases, filename="kmeans_clase8.tif", format="GTiff", overwrite=TRUE)
spplot(as(clases, 'SpatialGridDataFrame'), col.regions=col.regions,
pretty=TRUE,scales=list(draw=T), main = "Cuerpos de agua\nNDVI entre -0.4 y -1")
El algoritmo K-means es útil para hacer clasificación no supervisada y usa la media de cada grupo que genera, por lo que es más impreciso que el algoritmo CLARA que es más útil para volúmenes de datos grandes , también epero entre mas segmentos se usa, más
. Con este trabajo se quiere dar a conocer de qué manera estos códigos nos pueden ser útiles para el análisis de cambios de coberturas a través de los años del Humedal Juan Amarillo ubicado en la ciudad de Bogotá - Colombia, en los años 2014, 2015, 2016 y 2018 por medio de imágenes satelitales y usando índices de vegetación (NDVI) gracias a funciones de clasificación no supervisada como K-means y CLARA.