-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path10-coleccionimagenes.Rmd
656 lines (521 loc) · 36.4 KB
/
10-coleccionimagenes.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
\newpage
# ee.ImageCollection
\index{ee.ImageCollection}
Las colecciones de imágenes (`r colorize2("ee.ImageCollection")`) son objetos de GEE que contienen un conjunto de imágenes. La mayoría de los acervos de imágenes disponibles en GEE van a ser definidos como este tipo de objetos. Para el manejo de varias imágenes se recomienda utilizar esta estructura, en lugar de listas u otro tipo de objetos. La mayoría de las colecciones de imágenes disponibles en GEE incluyen acervos de imágenes gratuitas como Landsat 1-5 y 7-9, MODIS, Sentinel 1-3 y 5, ASTER, entre otras (Gorelick _et al_., 2017; Radočaj _et al_., 2020). Al final de este capítulo se presentan ejercicios integradores de varios de los procedimientos revisados en este capítulo.
Por ejemplo, para cargar la colección de reflectancia de la superficie de imágenes Sentinel-2 se usaría el siguiente código:
`r colorize("Ejercicio 28")`
```{js, echo = T}
// Cargar la colección de Sentinel-2 reflectancia de la superficie
var S2 = ee.ImageCollection('COPERNICUS/S2_SR');
```
Como información adicional para este capítulo se definirá una geometría de un área de interés.
```{js, echo = T}
// Definición de un área de interés
var roi = ee.Geometry.Polygon(
[[[-101.80582759131487, 20.274503120947937],
[-101.80582759131487, 19.35462236718103],
[-100.61930415381487, 19.35462236718103],
[-100.61930415381487, 20.274503120947937]]], null, false);
```
## Información y metadatos
\index{propertyNames}
Las colecciones de imágenes contienen los metadatos e información de todas las imágenes que incluyen, lo cual permite filtrar las imágenes y utilizar únicamente las que cumplen con ciertos criterios. Es importante recalcar que los metadatos y propiedades de una colección de imágenes no corresponden a las propiedades de las imágenes que la componen. Para consultar las propiedades de una colección de imágenes se usa el método `r colorize2(".propertyNames")` (`r colorize("Fig.")` \@ref(fig:f101)).
\newpage
`r colorize("Ejercicio 28.1")`
```{js, echo = T}
// Obtener las propiedades de la colección de imágenes
var S2Prop = S2.propertyNames();
```
```{r f101, echo = F, out.width="80%", fig.cap="Salida de la consola indicando las propiedades de la colección de imágenes de Sentinel-2 2A."}
knitr::include_graphics("Img/s2properties.png")
```
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
No se puede escribir o cambiar los objetos que se encuentran directamente hospedados en GEE. Por ejemplo, si se quiere mapear (`r colorize2(".map")`) una función que sobreescriba alguna característica de las colecciones de imágenes en GEE, se debe hacer una copia de estas para que se pueda sobreescribir la propiedad de interés.
:::
::::
## Creación de colecciones de imágenes
\index{fromImages}
En ciertas ocasiones, el usuario puede estar interesado en crear nuevas colecciones de imágenes a partir de imágenes generadas dentro del mismo GEE. En este caso, se utiliza el método `r colorize2("ee.ImageCollection.fromImages")`, indicando como argumentos la lista de las imágenes a partir de la que se quiere crear dicha colección (`r colorize("Fig.")` \@ref(fig:f102)).
`r colorize("Ejercicio 28.2")`
```{js, echo = T}
// Filtrar colección de Sentinel-2 por fechas
var im1 = S2.filterDate('2019-01-01','2019-05-01')
// Aplicar filtro espacial
.filterBounds(roi)
// Obtener la primera imagen
.first();
// Crear otra imagen de igual manera que la imagen anterior, pero con
// fechas distintas
var im2 = S2.filterDate('2020-01-01','2020-05-01')
.filterBounds(roi)
.first();
// Crear colección a partir de dos imágenes
var imColl = ee.ImageCollection.fromImages([im1, im2]);
```
```{r f102, echo = F, out.width="80%", fig.cap="Salida de la consola indicando el contenido de las dos imágenes obtenidas mediante un filtrado temporal distinto, así como la combinación de ambas en una colección de imágenes."}
knitr::include_graphics("Img/imcolnew.png")
```
## Visualización de colecciones de imágenes
\index{Map.addLayer}
Así como curre con los vectores y las colecciones de vectores, las colecciones de imágenes se pueden visualizar en la pantalla de mapa mediante la función `r colorize2("Map.addLayer")`. Usualmente, al agregar una colección de imágenes a la pantalla de mapa se van a mostrar los elementos con fecha de registro más reciente. Por ejemplo, en este caso muestra la imagen más reciente por cada escena dentro de la colección (`r colorize("Fig.")` \@ref(fig:f103)).
`r colorize("Ejercicio 28.3")`
```{js, echo = T}
// Filtrar colección de Sentinel-2 utilizando fechas
var imCol3 = S2.filterDate('2019-01-01','2019-05-01')
// Aplicar filtro espacial
.filterBounds(roi);
// Agregar colección de imágenes a la pantalla de mapa
Map.addLayer(imCol3, {bands: ['B4','B3','B2'], min:200, max: 2000},
'S2 Mich');
```
```{r f103, echo = F, out.width="80%", fig.cap="Visualización de la colección de imágenes de Sentinel-2 2A."}
knitr::include_graphics("Img/visS2Mich.png")
```
## Métodos comunes
### Filtración de colecciones de imágenes {-}
\index{filter}
\index{filterDate}
Las colecciones de imágenes se pueden filtrar a partir de los metadatos de las imágenes que contienen. De tal manera, se puede filtrar por: superposición con algún polígono de interés, fecha de registro, metadatos de las escenas (path, row, porcentaje de nubosidad), entre otras. Para filtrar una colección de imágenes se van a utilizar los objetos `r colorize2("ee.Filter")`. Existen diversos tipos de filtros, algunos ya se encuentran precargados, pero otros se pueden definir manualmente. Por ejemplo, para filtrar por fecha se puede utilizar `r colorize2(".filterDate")` (`r colorize("Fig.")` \@ref(fig:f104)):
\newpage
`r colorize("Ejercicio 28.4")`
```{js, echo = T}
// Filtrar colección de imágenes por fecha
var imCol4 = S2.filterDate('2019-01-01','2019-05-01');
```
Por otro lado, mediante `r colorize2(".filterBounds")` se puede filtrar espacialmente con un polígono.:
```{js, echo = T}
// Filtrar colección de acuerdo a sobreponga con polígono de región de
// interés
imCol4 = imCol4.filterBounds(roi);
```
\index{filterMetadata}
Si se desea filtrar por alguna característica de los metadatos de las imágenes se puede hacer mediante `r colorize2(".filter")` y después definiendo el filtro del metadato con `r colorize2("ee.Filter")`. Otra forma de realizar este proceso es mediante `r colorize2(".filterMetadata")`. Las siguientes dos líneas son equivalentes ya que obtienen el mismo resultado.
```{js, echo = T}
// Obtener el nombre de las propiedades de una imagen de la colección de
// imágenes
var imProperties = im1.propertyNames();
// Filtrar a partir de las propiedades de las imágenes
imCol4 = imCol4.filter(ee.Filter.lt('CLOUD_COVERAGE_ASSESSMENT', 50));
imCol4 = imCol4.filterMetadata('CLOUD_COVERAGE_ASSESSMENT','less_than', 50);
```
```{r f104, echo = F, out.width="80%", fig.cap="Salida de la consola indicando los resultados de la colección de imágenes después de realizar diferentes tipos de filtros."}
knitr::include_graphics("Img/filtroEspacialTemporal.png")
```
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
Recuerde que para filtrar una colección de imágenes utilizando metadatos se debe filtrar de acuerdo a las propiedades de las imágenes, no de la colección.
:::
::::
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
Para trabajar con una colección de imágenes se sugiere que primero se apliquen los filtros espaciales y temporales (`r colorize2(".filter")`), así como la selección de las bandas a utilizar (`r colorize2(".select")`), antes de realizar operaciones sobre todas las imágenes de la colección (`r colorize2(".map")`).
:::
::::
\index{and}
\index{or}
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
Para combinar varios filtros se utiliza `r colorize2("ee.Filter.and")` o `r colorize2("ee.Filter.or")` dependiendo de si se desea que se cumplan todas las condiciones indicadas (`r colorize2("and")`) o alguna de ellas (`r colorize2("or")`).
:::
::::
### Selección de bandas {-}
\index{select}
Al igual que con las imágenes, se puede utilizar el método `r colorize2(".select")` para seleccionar un conjunto de bandas de todas las imágenes que se encuentran en la colección. De igual manera que como ocurre con las imágenes individuales, para seleccionar una única banda solo se requiere indicar el nombre de esta, mientras que si se desea seleccionar varias bandas, estas deben indicarse dentro de una lista. Por ejemplo (`r colorize("Fig.")` \@ref(fig:f105)):
`r colorize("Ejercicio 28.5")`
```{js, echo = T}
// Obtener el nombre de las bandas de una imagen de una colección de
// imágenes
var imBandNames = im1.bandNames();
// Seleccionar ciertas bandas de todas las imágenes que conforman la
// colección
var imCol5 = imCol4.select(['B4','B3','B2']);
```
```{r f105, echo = F, out.width="80%", fig.cap="Salida de la consola indicando los nombres de las bandas de las imágenes Sentinel-2, así como de la selección únicamente de las bandas 4, 3 y 2."}
knitr::include_graphics("Img/imBandNames1.png")
```
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
Recuerde que para seleccionar ciertas bandas en una colección de imágenes, estas corresponden a bandas de las imágenes, no de la colección. Esto es útil para revisar los nombres de las bandas.
:::
::::
### Ordenación de una colección {-}
\index{sort}
El método `r colorize2(".sort")` permite ordenar una colección de imágenes por alguna propiedad de estas. Por defecto, las colecciones de imágenes están ordenadas cronológicamente. Sin embargo, se puede cambiar este orden para que las presente por alguna característica de las imágenes, por ejemplo, por orden de menor a mayor cobertura de nubes. Por defecto, el método `r colorize2(".sort")` ordena la colección de imágenes de forma ascendente, de acuerdo al valor de la característica indicada. Si se desea ordenar de manera descendente, esto se puede indicar utilizando el argumento `ascending: false`. En el siguiente ejemplo, primero se ordena la colección en orden ascendente y en el segundo, descendente.
`r colorize("Ejercicio 28.6")`
```{js, echo = T}
// Cambiar el orden de la colección en función de la propiedad de las
// imágenes de cobertura de nubes en sentido descendente
imCol5 = imCol5.sort({property: 'CLOUD_COVERAGE_ASSESSMENT',
ascending: false});
```
```{r f106, echo = F, out.width="80%", fig.cap="Visualización de la primera imagen de la colección."}
knitr::include_graphics("Img/imcol5sortcloud.png")
```
### Obtención de la primera imagen {-}
\index{first}
En algunas ocasiones resulta útil obtener la primera imagen de una colección de imágenes para ver si se llevó a cabo el procedimiento deseado sobre la colección. Para ello, se utiliza el método `r colorize2(".first")`, que devuelve la primera imagen que se encuentra en la colección y permite visualizarla en la pantalla de mapa para analizarla más a detalle. Al utilizar el método `r colorize2(".first")` sobre una colección de imágenes (`r colorize2("ee.ImageCollection")`) el resultado corresponderá a una imagen (`r colorize2("ee.Image")`; `r colorize("Fig. ")` \@ref(fig:f107)).
`r colorize("Ejercicio 28.7")`
```{js, echo = T}
// Obtener la primera imagen de una colección
var primera = imCol3.first()
```
```{r f107, echo = F, out.width="80%", fig.cap="Salida de la consola indicando la primera imagen de la colección."}
knitr::include_graphics("Img/primerIm.png")
```
### Extracción de listas con atributos de imágenes {-}
\index{aggregate}
Para obtener una lista con los atributos de las imágenes que conforman una colección de imágenes se utiliza el método `r colorize2(".aggregate")`. Este método tiene varias formas de obtener y resumir los atributos de los vectores que conforman una colección: extraer una propiedad de los vectores (`r colorize2(".aggregate\\_array")`), extraer y calcular la media por propiedad (`r colorize2(".aggregate")``r colorize2("\\_mean")`), extraer y calcular un histograma (`r colorize2(".aggregate\\_histogram")`) o extraer y obtener estadísticas descriptivas de las propiedades (`r colorize2(".aggregate\\_stats")`). Por ejemplo, una lista con la propiedad 'CLOUD_COVERAGE_ASSESSMENT' de todas las imágenes contenidas en una colección de imágenes se puede obtener de la siguiente manera (`r colorize("Fig.")` \@ref(fig:f108)):
`r colorize("Ejercicio 28.8")`
```{js, echo = T}
// Obtener una lista de con los valores de la propiedad de cobertura de
// nubes de todas las imágenes de la colección
var listMetadatos = imCol5.aggregate_array('CLOUD_COVERAGE_ASSESSMENT');
```
```{r f108, echo = F, out.width="80%", fig.cap="Salida de la consola indicando la lista de propiedades de las imágenes."}
knitr::include_graphics("Img/cloudCoverList.png")
```
### Conteo de observaciones por píxel {-}
\index{count}
Para conocer el número de valores sin enmascarar por píxel en la colección de imágenes se utiliza el método `r colorize2(".count")`. El resultado de este procedimiento consta de una imagen con las mismas bandas que las imágenes a partir de las cuales se calculó el número de observaciones por píxel (`r colorize("Fig.")` \@ref(fig:f109)).
```{js, echo = T}
// Obtener el número de observaciones válidas para un píxel dentro de una
// colección de imágenes
var conteoImgs = imCol5.count();
```
```{r f109, echo = F, out.width="80%", fig.cap="Visualización de la imagen del conteo de observaciones."}
knitr::include_graphics("Img/conteoim.png")
```
### Conocer el tamaño de la colección {-}
\index{size}
Para conocer el tamaño de la colección en número de imágenes incluidas se utiliza el método `r colorize2(".size")`.
```{js, echo = T}
// Obtener el número de observaciones válidas para un píxel dentro de una
// colección de imágenes
var numImgs = imCol5.size();
```
### Unión de más de una colección {-}
\index{merge}
Para unir una colección de imágenes con otra, se utiliza el método `r colorize2(".merge")`. Un caso típico de tal operación sería unir dos colecciones de Landsat, por ejemplo, Landsat 7 y 8.
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
Las colecciones Landsat 7 y 8 no tienen las mismas bandas, ni los nombres de las bandas corresponden entre sí. Por ejemplo, la banda 1 de Landsat 7 corresponde al espectro del azul (*blue*), mientras que en Landsat 8, la banda 1 corresponde al azul de costa (*coastal blue*). En este caso, conviene primero filtrar y renombrar las bandas a unir para asegurarse de que el nombre de las bandas a unir en una colección corresponda con el de la otra.
:::
::::
La unión de una colección de Sentinel-2 se podría hacer de la siguiente manera (`r colorize("Fig.")` \@ref(fig:f1010)):
`r colorize("Ejercicio 28.9")`
```{js, echo = T}
// Aplicar un filtro por fechas a la colección de Sentinel-2
var imCol6 = S2.filterDate('2019-01-01','2019-05-01')
// Aplicar filtro espacial
.filterBounds(roi);
// Hacer lo mismo que en el caso anterior, pero cambiando las fechas
var imCol7 = S2.filterDate('2020-06-01','2020-11-01')
.filterBounds(roi);
// Unir las dos colecciones de imágenes en una sola
var imCol8 = imCol6.merge(imCol7);
```
```{r f1010, echo = F, out.width="80%", fig.cap="Salida de la consola indicando el número de elementos en cada colección, así como el número de elementos en la colección combinada."}
knitr::include_graphics("Img/merge2colecciones.png")
```
### Ejecución de una función sobre todas las imágenes de una colección {-}
\index{map}
Para realizar alguna operación sobre todas las imágenes de una `r colorize2("ee.ImageCollection")` se utiliza el método `r colorize2(".map")`. Esto va a aplicar el procedimiento o función que se defina en el interior de ella, a cada imagen dentro de la colección. Por ejemplo, si quisiéramos agregar una banda con un índice de vegetación a todas las imágenes, se podría hacer de la siguiente manera (`r colorize("Fig.")` \@ref(fig:f1011)):
`r colorize("Ejercicio 28.10")`
```{js, echo = T}
// Definir una función que calcule el ndvi de una imagen
var ndviCalc = function(image){
// Calcular el ndvi utilizando las bandas del NIR, B8 y R, B4
var ndvi = image.normalizedDifference(['B8','B4']);
// Regresar la imagen con la nueva banda de ndvi
return image.addBands(ndvi);
};
// Aplicar la función sobre todas las imágenes de una colección
var imCol9 = imCol4.map(ndviCalc);
```
```{r f1011, echo = F, out.width="80%", fig.cap="Salida de la consola con la información de la colección de imágenes con la banda NDVI agregada a cada imagen."}
knitr::include_graphics("Img/imcol9.png")
```
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
Nótese que el método `r colorize2(".map")` es distinto de la función `r colorize2("Map")` que permite agregar objetos a la pantalla de mapa. Recuerde que JavaScript es un lenguaje sensible a mayúsculas y minúsculas.
:::
::::
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
GEE recomienda el uso de `r colorize2(".map")` para realizar operaciones de tipo ciclo, en lugar de otras funciones de ciclo (por ejemplo, `r colorize2("for")`).
:::
::::
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
El método `r colorize2(".map")` requiere del uso de funciones del lado del servidor, así que se recomienda evitar el uso de funciones del lado del cliente como `r colorize2("print")`, `r colorize2("Map")`, `r colorize2("Export")` y `r colorize2("Chart")`.
:::
::::
### Reducción de una colección de imágenes {-}
\index{reduce}
\index{ee.Reducer}
Los reductores permiten crear un compuesto (una sola imagen) a partir de una colección de imágenes. Por ello, el resultado obtenido tras una reducción sobre una colección de imágenes (`r colorize2("ee.ImageCollection")`) será una imagen (`r colorize2("ee.Image")`). Los reductores son muy útiles para hacer mosaicos multitemporales u obtener información de la colección de imágenes. Para reducir una colección de imágenes se utilizará el método `r colorize2(".reduce")`, indicando la operación matemática a utilizar mediante un objeto tipo `r colorize2("ee.Reducer")`. De tal manera, se puede indicar si el resultado corresponderá a la media; `r colorize2("ee.Reducer.mean")`, mediana; `r colorize2("ee.Reducer.median")`, moda; `r colorize2("ee.Reducer.mode")`, mínimo, `r colorize2("ee.Reducer.min")`, máximo; `r colorize2("ee.Reducer.max")` o inclusive la media de un intervalo determinado de observaciones, `r colorize2("ee.Reducer.intervalMean")`. Otra forma de realizar estas mismas reducciones es utilizando directamente los métodos de `r colorize2(".min")`, `r colorize2(".max")`, `r colorize2(".mean")`, `r colorize2(".mode")`, `r colorize2(".median")`. Las siguientes dos líneas realizan exactamente el mismo proceso (`r colorize("Fig.")` \@ref(fig:f1012)):
`r colorize("Ejercicio 28.11")`
```{js, echo = T}
// Calcular el valor promedio de reflectancia para cada una de las bandas
// de las imágenes que conforman la colección
var imRedMean = imCol9.mean();
// Realizar lo mismo, pero utilizando explícitamente la definición del
// reductor
var imRedMean2 = imCol9.reduce(ee.Reducer.mean());
```
```{r f1012, echo = F, out.width="80%", fig.cap="Visualización de la imagen de la reflectancia promedio (compuesto RGB)."}
knitr::include_graphics("Img/imredmean.png")
```
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
Al aplicar una reducción a una colección de imágenes mediante el método `r colorize2(".reduce")`, el nombre de las bandas será el mismo que el de las bandas de cada imagen con un sufijo que indica la operación matemática utilizada para hacer la reducción. Por ejemplo, al utilizar `r colorize2("ee.Reducer.mean")` sobre una colección de imágenes cuyas bandas se llaman 'B1' y 'B2', las bandas de la imagen producto de la reducción se llamarán 'B1_mean' y 'B2_mean'.
:::
::::
### Creación de compuestos y mosaicos {-}
\index{qualityMosaic}
\index{mosaic}
Si se desea hacer mosaicos a partir de varias imágenes se puede realizar en GEE mediante dos métodos: `r colorize2(".mosaic")` y `r colorize2(".qualityMosaic")`. La principal diferencia entre estos dos procesos radica en que la primera simplemente pega las imágenes de acuerdo al orden que tienen en la colección (es decir, la última hasta arriba). Por el contrario, el método de `r colorize2(".qualityMosaic")` permite priorizar el píxel que quedará en el mosaico final a partir del valor más alto de alguna banda. Esto puede ser útil para realizar, por ejemplo, un mosaico del píxel con mayor valor de NDVI. En el caso de `r colorize2(".qualityMosaic")` hay que indicar la banda que se utilizará como la banda de calidad para crear el mosaico (`r colorize("Fig.")` \@ref(fig:f1013)).
`r colorize("Ejercicio 28.12")`
```{js, echo = T}
// Crear un mosaico de las imágenes contenidas en una colección.
// Generalmente en áreas de sobreposición se tomarán los valores de las
// imágenes más recientes
var imRedMosaic = imCol9.mosaic();
// Crear un mosaico utilizando como banda de calidad 'nd' que en este caso
//corresponde al ndvi
// Este método permite obtener mosaicos, por ejemplo, del valor del píxel
//de mayor verdor o mayor valor de ndvi
var imRedQualMosaic = imCol9.qualityMosaic('nd');
```
```{r f1013, echo = F, out.width="80%", fig.cap="Visualización de la imagen de la reflectancia promedio con el método de mosaico de calidad (compuesto RGB)."}
knitr::include_graphics("Img/imredmeanQM.png")
```
#### Ejercicio B: Filtro de colección de imágenes y visualización {-}
Este ejercicio integra elementos de los ejercicios 28.4, 28.5, 28.6 y 28.7, de modo que sea posible remitirse a estos ejercicios si se tienen dudas.
En un solo paso, aplicando múltiples filtros, se puede filtrar la colección de reflectancia de la superficie de imágenes de Landsat 8 de mayor calidad (*tier 1*) por fecha, porcentaje de cobertura de nubes de las imágenes, así como por su *path* y *row*. Para ello, primero se indica la ruta de la colección que se desea utilizar. Para encontrar esta ruta se puede buscar la colección de interés en la barra de búsqueda (**Search**), después se le da clic y del lado izquierdo aparecerá la ruta de la colección. Por otro lado, en esta misma ventana, en la pestaña de **Bands** se pueden consultar las bandas y los nombres de las bandas que contiene cada imagen. Por su parte, en la pestaña de **Image properties** se pueden consultar los metadatos que contienen las imágenes de esta colección (`r colorize("Fig.")` \@ref(fig:f1014)).
```{r f1014, echo = F, out.width="95%", fig.cap="Consulta de propiedades de las imágenes contenidas en una colección de imágenes."}
knitr::include_graphics("Img/Ruta_coleccion.png")
```
Una vez que se conoce la ruta de la colección de interés, se llama dicha colección y se especifican los filtros. En este caso, primero se filtra por fecha, en formato AAAA-MM-DD (año, mes, día), seguido de filtros de los metadatos de las imágenes:
* 'CLOUD_COVER_LAND'.
* 'WRS_PATH'.
* 'WRS_ROW'.
Para realizar este filtro se debe escribir exactamente igual el nombre de las propiedades (por ejemplo, 'CLOUD_COVER_LAND') y en la definición del filtro se debe explicitar si se desea utilizar los valores que sean iguales (`r colorize2(".eq")`), distintos (`r colorize2(".neq")`), mayores (`r colorize2(".gt")`), menores (`r colorize2(".lt")`), mayores o igual (`r colorize2(".gte")`) o menores o igual (`r colorize2(".lte")`).
\index{filterDate}
\index{filter}
\index{ee.Filter.lte}
\index{ee.Filter.eq}
```{js, echo = T}
// Filtrado de la colección
var L8imgCol = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
.filterDate('2015-01-01','2016-01-01')
.filter(ee.Filter.lte('CLOUD_COVER_LAND',50))
.filter(ee.Filter.eq('WRS_PATH',28))
.filter(ee.Filter.eq('WRS_ROW',46));
```
Para explorar algunas características de la colección de imágenes filtradas podemos escribir el siguiente comando y ver sus características en la consola.
```{js, echo = T}
print(L8imgCol);
```
Una vez pasado el comando anterior, en la consola se puede consultar cuántas imágenes cumplieron con los filtros indicados. En este ejemplo, la colección filtrada incluye 17 imágenes. Después, se pueden consultar las características de las imágenes. Para ello, en la consola se le da:
* Un clic a la colección en la consola.
* Luego un clic a **features**.
* Después un clic a cualquier imagen (`Image`).
* Por último a **Properties**. Ahí se pueden ver los metadatos de cada imagen, y por lo tanto, los campos de información que se pueden utilizar para filtrar una colección de imágenes. Esta información es la misma que se puede obtener en la barra de búsqueda (`r colorize("Fig.")` \@ref(fig:f1015)).
```{r f1015, echo = F, out.width="95%", fig.cap="Ejemplo de una consulta de información de la colección de imágenes en la consola."}
knitr::include_graphics("Img/CamposImgCol.png")
```
A continuación se ordena la colección de manera ascendente de acuerdo a la propiedad de 'CLOUD_COVER_LAND'. Se selecciona la primera imagen, es decir, la de menor cobertura de nubes. Nótese que en este paso, al definir la variable `L8imgFirst`, ya únicamente seleccionamos una sola imagen, por lo tanto, este va a ser un objeto `r colorize2("ee.Image")`.
\index{first}
```{js, echo = T}
// Ordenar imágenes y obtener la primera
L8imgCol = L8imgCol.sort('CLOUD_COVER_LAND');
var L8imgFirst = L8imgCol.first();
print(L8imgFirst);
```
Además, se puede agregar esta imagen a la ventana de mapas para visualizar su información (`r colorize("Fig.")` \@ref(fig:f1016)). Esto se puede realizar de dos maneras: 1) agregando la información sin pasar más argumentos, o 2) indicando las bandas y el orden que se desea cargar, así como los valores mínimos y máximos del histograma y un nombre para la capa.
```{js, echo = T}
// Agregar a la pantalla de mapa
Map.addLayer(L8imgFirst);
Map.addLayer(L8imgFirst,{bands: ['B4','B3','B2'], min: 95, max: 1288},
'RGB menos nubes L8');
```
```{r f1016, echo = F, out.width="95%", fig.cap="Visualización de la primera imagen de la colección de imágenes."}
knitr::include_graphics("Img/RGBIm.png")
```
#### Ejercicio C: Enmascaramiento de nubes, cálculo de índices y reducción {-}
Este ejercicio integra elementos de los ejercicios 28.8 y 28.9, de modo que puede remitirse a estos ejercicios si necesita de una mayor aclaración.
Utilizando la colección que ya se filtró en el ejercicio anterior se hará un mapeo y una reducción. En este ejercicio se obtendrá el NDVI promedio entre 2015 y 2016. Para ello, lo primero que hay que hacer es aplicar la máscara de nubes que viene en la misma colección de imágenes de Landsat 8. Al aplicar esta máscara se eliminarán los píxeles cuya información provenga de nubes o sombras. Después, se definirá una función para calcular el NDVI de cada imagen contenida en la colección de imágenes, utilizando el método `r colorize2(".normalizedDifference")` e indicando las bandas del infrarrojo cercano (NIR) y rojo (R). También, se utilizará el método `r colorize2(".rename")` para cambiar el nombre dado por defecto a la nueva banda calculada. Posteriormente, se agrega esta banda a la imagen con el método `r colorize2(".addBands")` y se utiliza el método `r colorize2(".map")` para aplicarla a cada una de las imágenes.
En este procedimiento, primero se tiene que definir la función para enmascarar las nubes. Para ello, se indican los bits que corresponden a nubes y a sombras, es decir, los bits 5 y 3, respectivamente. Después se selecciona la banda que contiene la información de la máscara de nubes, la cual en Landsat 8 se llama 'pixel_qa'. Se selecciona esta banda y se confirma que en los dos bits antes mencionados el valor sea igual a cero, es decir, que sea un píxel clasificado como despejado. En este procedimiento se indica que la consulta de los valores se debe hacer por bits (`r colorize2(".bitwiseAnd")`) y que las dos evaluaciones deben de ser cero (`r colorize2(".and")`). Posteriormente, se define una máscara en función de esos valores y se actualiza la máscara (`r colorize2(".updateMask")`).
\index{function}
\index{bitwiseAnd}
\index{and}
\index{updateMask}
```{js, echo = T}
// Crear función para enmascarar nubes
function maskL8sr(image) {
var cloudShadowBitMask = (1 << 3);
var cloudsBitMask = (1 << 5);
var qa = image.select('pixel_qa');
var mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0)
.and(qa.bitwiseAnd(cloudsBitMask).eq(0));
return image.updateMask(mask);
}
```
Se define la función para calcular el NDVI de todas las imágenes.
\index{normalizedDifference}
\index{rename}
\index{addBands}
```{js, echo = T}
// Crear función para calcular NDVI
var ndviCalc = function(image){
var ndvi = image.normalizedDifference(['B5','B4']);
ndvi = ndvi.rename('ndvi');
return image.addBands(ndvi);
};
```
Para obtener una muestra de cómo se ve la primera imagen con y sin la máscara de nubes, primero se agregará la imagen con nubes a la pantalla de mapa (`r colorize("Fig.")` \@ref(fig:f1017)).
\index{first}
```{js, echo = T}
// Agregar la primera imagen a la pantalla de mapa
Map.addLayer(L8imgCol.first(),
{bands:['B4','B3','B2'], min: 0, max: 1300},
'Imagen con nubes');
```
```{r f1017, echo = F, out.width="95%", fig.cap="Ejemplo de una imagen con nubes."}
knitr::include_graphics("Img/imNubes.png")
```
A continuación se aplican las dos funciones utilizando `r colorize2(".map")` y se sobreescribe el objeto `L8imgCol`.
\index{map}
```{js, echo = T}
// Aplicar las dos funciones a la colección
L8imgCol = L8imgCol
.map(maskL8sr)
.map(ndviCalc);
print(L8imgCol);
```
Se muestra la primera imagen sin nubes (`r colorize("Fig.")` \@ref(fig:f1018)).
\index{first}
```{js, echo = T}
// Visualizar la primera imagen
Map.addLayer(L8imgCol.first(),
{bands:['B4','B3','B2'], min: 0, max: 1300},
'Imagen sin nubes');
```
```{r f1018, echo = F, out.width="95%", fig.cap="Ejemplo de una imagen donde se enmascararon las nubes."}
knitr::include_graphics("Img/imSinNubes.png")
```
En la consola se puede observar que todas las imágenes ahora contienen una nueva banda llamada 'ndvi' (`r colorize("Fig.")` \@ref(fig:f1019)).
```{r f1019, echo = F, out.width="95%", fig.cap="Consulta de información en la consola para verificar que la colección de imágenes contiene la banda NDVI."}
knitr::include_graphics("Img/imConNDVI.png")
```
Posteriormente, se reduce la colección de imágenes para formar una sola imagen que represente el valor promedio de NDVI en el periodo de la colección (2015-2016), usando el método `r colorize2(".reduce")`. También se calculará la desviación estándar de los valores de NDVI. Estas dos imágenes se guardarán en dos nuevos objetos.
\index{reduce}
\index{ee.Reducer.mean}
\index{ee.Reducer.stdDev}
```{js, echo = T}
// Seleccionar la banda ndvi y hacer dos reducciones
L8imgCol = L8imgCol.select('ndvi');
var L8imgMean = L8imgCol.reduce(ee.Reducer.mean());
var L8imgSD = L8imgCol.reduce(ee.Reducer.stdDev());
```
A continuación, agregamos los dos resultados a la pantalla de mapa y visualizamos el compuesto de media (`r colorize("Fig.")` \@ref(fig:f1020)).
\index{Map.addLayer}
```{js, echo = T}
// Visualizar las imágenes
Map.addLayer(L8imgMean, {min:-0.14, max:0.15}, 'NDVI mean 2015 - 2016');
Map.addLayer(L8imgSD, {min:0, max:0.13}, 'NDVI SD 2015 - 2016');
```
```{r f1020, echo = F, out.width="95%", fig.cap="Visualización de la imagen de NDVI promedio."}
knitr::include_graphics("Img/imNDVI.png")
```
Se puede conocer el número de observaciones sin enmascarar por píxel utilizando el método `r colorize2("count")`. Debido a que ya se enmascararon las nubes en todas las imágenes de la colección, esta imagen contendrá el número de observaciones sin nube por píxel. Esta información nos permite conocer a partir de cuántas observaciones por píxel se calcularon las imágenes anteriores, es decir, las imágenes con el promedio y desviación estándar de NDVI.
\index{count}
```{js, echo = T}
// Obtener la imagen del número de observaciones por píxel sin enmascarar
var numObsPixel = L8imgCol.count();
Map.addLayer(numObsPixel,
{min: 1, max: 17},
'Número de observaciones sin enmascarar por píxel');
```
La imagen con el número de observaciones por píxel sin enmascarar se ve así (`r colorize("Fig.")` \@ref(fig:f1021)):
```{r f1021, echo = F, out.width="95%", fig.cap="Visualización de la imagen con el número de observaciones sin enmascarar por píxel."}
knitr::include_graphics("Img/imCount.png")
```
:::: {.bluebox2 data-latex=""}
::: {.awesomeblock data-latex="{5pt}{\faLightbulb}{darkblue}"}
Se pueden prender y apagar las capas de la pantalla de mapa utilizando el menú que se despliega al posicionar el puntero sobre el letrero de layers y prendiendo y apagando las capas con las palomitas a la izquierda de cada capa.
:::
::::
El último paso será cortar la imagen a una extensión de interés. En este caso primero se define un área de interés mediante coordenadas:
```{js echo = T}
// Cargar el polígono del área de interés
var geometry = ee.Geometry.Polygon(
[[[-101.82737418916153, 19.836437094032178],
[-101.82737418916153, 19.368119068204525],
[-101.15171500947403, 19.368119068204525],
[-101.15171500947403, 19.836437094032178]]], null, false);
```
para después cortar las dos imágenes y mostrarlas en la pantalla de mapa (`r colorize("Fig.")` \@ref(fig:f1022)).
\index{clip}
```{js echo = T}
// Cortar la imágenes
L8imgMean = L8imgMean.clip(geometry);
L8imgSD = L8imgSD.clip(geometry);
// Visualizarlas
Map.addLayer(L8imgMean, {min:0.2, max:0.8}, 'NDVI mean 2015 - 2016 clip');
Map.addLayer(L8imgSD, {min:0, max:0.3}, 'NDVI SD 2015 - 2016 clip');
```
```{r f1022, echo = F, out.width="95%", fig.cap="Visualización de los compuestos de media y desviación estándar cortados."}
knitr::include_graphics("Img/meansdclip.png")
```
#### Ejercicio D: Cálculo de diferencia de dos imágenes y exportación de resultado {-}
Se utilizarán las funciones previamente definidas para generar un mosaico igual al ya generado, pero ahora con fechas de 2016-01-01 al 2017-01-01. Primero se filtra la colección de imágenes y se mapean las funciones para enmascarar las nubes y agregar el NDVI a las imágenes.
```{js, echo = T}
// Filtrado en tiempo 2
var L8imgColT2 = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
.filterDate('2016-01-01','2017-01-01')
.filter(ee.Filter.lte('CLOUD_COVER_LAND',50))
.filter(ee.Filter.eq('WRS_PATH',28))
.filter(ee.Filter.eq('WRS_ROW',46));
L8imgColT2 = L8imgColT2
.map(maskL8sr)
.map(ndviCalc);
```
Después, se seleccionan únicamente las bandas de NDVI y se reduce la colección de imágenes para generar una imagen del valor promedio de NDVI. Posteriormente, se recorta la imagen a la extensión del polígono del área de interés. A esta imagen se le restarán los valores de la imagen del 2015-01-01 al 2016-01-01. De esta manera, los valores más negativos representarán valores más bajos de NDVI en el año 2 respecto al año 1.
\index{select}
```{js, echo = T}
// Seleccionar NDVI y reducción
L8imgColT2 = L8imgColT2.select('ndvi');
var L8imgMeanT2 = L8imgColT2.reduce(ee.Reducer.mean());
// Cortar imagen a área de interés
L8imgMeanT2 = L8imgMeanT2.clip(geometry);
// Restar media T1 a T2
var imgDiff = L8imgMeanT2.subtract(L8imgMean);
```
Posteriormente se agrega el resultado a la pantalla de mapa (`r colorize("Fig.")` \@ref(fig:f1023)).
```{js, echo = T}
// Visualizar imagen resultante
Map.addLayer(imgDiff,{min:-0.3, max: 0.1,
palette:['FF0000', 'FFFF00', '008000'] },
'Diferencia NDVI 2015 vs 2016');
```
```{r f1023, echo = F, out.width="95%", fig.cap="Imagen de la diferencia de NDVI entre dos años."}
knitr::include_graphics("Img/imDifNDVI.png")
```
Por último, para exportar el resultado se ingresan varios parámetros a la función, que incluyen: la imagen a exportar, el nombre para guardar el archivo, la escala de la imagen (tamaño de píxel en metros), formato a utilizar y si se desea guardar dentro de una carpeta del **Google Drive**. Estos argumentos, al igual que otras funciones en GEE, se pasan dentro de un diccionario.
\index{Export.image.toDrive}
```{js echo = T}
// Exportar imagen a Google Drive
Export.image.toDrive({
image: imgDiff,
description: 'DiferenciaNDVI_2016-2017',
scale: 30,
maxPixels: 1e12,
fileFormat: 'GeoTIFF',
folder: 'DiferenciaNDVIL8',
region: roi,
crs: 'EPSG:4326
});
```