Wizualizacja zbioru obrazów

Obrazy tworzące ImageCollection mogą być wizualizowane jako animacja lub seria miniatur, zwana „taśmą filmową”. Te metody umożliwiają szybką ocenę zawartości ImageCollection i są skutecznym medium do obserwowania zmian czasoprzestrzennych (ryc. 1).

W poniższych sekcjach znajdziesz opisy sposobów przygotowywania zbioru ImageCollection do wizualizacji, przykładowy kod dla każdej metody wizualizacji zbioru oraz kilka zaawansowanych technik animacji.


Rysunek 1. Animacja pokazująca 3-dniowy rozwój huraganów na Atlantyku we wrześniu 2017 r.

Przygotowanie do odbioru

Filtrowanie, łączenie, sortowanie i stylizowanie obrazów w kolekcji, aby wyświetlać tylko te, które Cię interesują, lub aby podkreślić jakiś efekt. Do funkcji wizualizacji można podać dowolną wartość ImageCollection, ale lepsze wyniki można uzyskać, podając uporządkowaną kolekcję z uwzględnieniem zakresów dat międzyrocznych i rocznych, interwału obserwacji, zasięgu regionalnego, jakości i reprezentacji.

Filtrowanie

Przefiltruj kolekcję obrazów, aby zawierała tylko istotne dane, które służą do realizacji celu wizualizacji. Weź pod uwagę daty, zasięg przestrzenny, jakość i inne właściwości dotyczące danego zbioru danych.

Możesz na przykład filtrować kolekcję danych o odbiciu promieniowania Sentinel-2 według:

pojedynczy zakres dat,

Edytor kodu (JavaScript)

var s2col = ee.ImageCollection('COPERNICUS/S2_SR')
  .filterDate('2018-01-01', '2019-01-01');

seryjny zakres dni roku,

Edytor kodu (JavaScript)

var s2col = ee.ImageCollection('COPERNICUS/S2_SR')
  .filter(ee.Filter.calendarRange(171, 242, 'day_of_year'));

regionie zainteresowania,

Edytor kodu (JavaScript)

var s2col = ee.ImageCollection('COPERNICUS/S2_SR')
  .filterBounds(ee.Geometry.Point(-122.1, 37.2));

lub właściwości obrazu.

Edytor kodu (JavaScript)

var s2col = ee.ImageCollection('COPERNICUS/S2_SR')
  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 50));

stosować wiele filtrów jednocześnie.

Edytor kodu (JavaScript)

var s2col = ee.ImageCollection('COPERNICUS/S2_SR')
  .filterDate('2018-01-01', '2019-01-01')
  .filterBounds(ee.Geometry.Point(-122.1, 37.2))
  .filter('CLOUDY_PIXEL_PERCENTAGE < 50');

Kompilowanie

Utworzenie zbiorczych zakresów dat obejmujących poszczególne lata i całe lata, aby zmniejszyć liczbę obrazów w zbiorze i poprawić ich jakość. Załóżmy na przykład, że chcesz utworzyć wizualizację rocznego NDVI dla Afryki. Jedną z opcji jest filtrowanie 16-dniowej kolekcji NDVI z MODIS, aby uwzględnić wszystkie obserwacje z 2018 r.

Edytor kodu (JavaScript)

var ndviCol = ee.ImageCollection('MODIS/006/MOD13A2')
  .filterDate('2018-01-01', '2019-01-01')
  .select('NDVI');

Interannual composite by filter and reduce

Wizualizacja powyższego zbioru danych pokazuje znaczny szum w zalesionych regionach, w których występuje duże zachmurzenie (ryc. 2a). Lepszą reprezentację można uzyskać, zmniejszając zakresy dat seryjnych według mediany we wszystkich latach w zbiorze MODIS.

Edytor kodu (JavaScript)

// Make a day-of-year sequence from 1 to 365 with a 16-day step.
var doyList = ee.List.sequence(1, 365, 16);

// Import a MODIS NDVI collection.
var ndviCol = ee.ImageCollection('MODIS/006/MOD13A2').select('NDVI');

// Map over the list of days to build a list of image composites.
var ndviCompList = doyList.map(function(startDoy) {
  // Ensure that startDoy is a number.
  startDoy = ee.Number(startDoy);

  // Filter images by date range; starting with the current startDate and
  // ending 15 days later. Reduce the resulting image collection by median.
  return ndviCol
    .filter(ee.Filter.calendarRange(startDoy, startDoy.add(15), 'day_of_year'))
    .reduce(ee.Reducer.median());
});

// Convert the image List to an ImageCollection.
var ndviCompCol = ee.ImageCollection.fromImages(ndviCompList);

Animacja utworzona na podstawie tej kolekcji jest mniej zniekształcona, ponieważ każdy obraz reprezentuje medianę 16-dniowego obrazu złożonego NDVI na podstawie danych z ponad 20 lat (Rysunek 1b). Więcej informacji o tej animacji znajdziesz w tym samouczku.

Rysunek 2a. Roczny NDVI bez kompozytowania międzyrocznego. Rysunek 2b. Roczny NDVI z kompozycją międzyroczną.

Średnia roczna według filtra i redukcji

Poprzedni przykład dotyczy kompozytowania międzyrocznego. Może być też przydatne do tworzenia zestawów obserwacji w ciągu roku. Na przykład dane Landsat są zbierane co 16 dni dla danej sceny na każdy czujnik, ale często część obrazów jest zasłonięta przez chmury. Zamaskowanie chmur i złożenie kilku obrazów z tego samego sezonu może dać bardziej przejrzyste przedstawienie. Rozważ przykład, w którym obrazy Landsat 5 z lipca i sierpnia są łączone przy użyciu mediany dla każdego roku od 1985 r. do 2011 r.

Edytor kodu (JavaScript)

// Assemble a collection of Landsat surface reflectance images for a given
// region and day-of-year range.
var lsCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2')
  .filterBounds(ee.Geometry.Point(-122.9, 43.6))
  .filter(ee.Filter.dayOfYear(182, 243))
  // Add the observation year as a property to each image.
  .map(function(img) {
    return img.set('year', ee.Image(img).date().get('year'));
  });


// Define a function to scale the data and mask unwanted pixels.
function maskL457sr(image) {
  // Bit 0 - Fill
  // Bit 1 - Dilated Cloud
  // Bit 2 - Unused
  // Bit 3 - Cloud
  // Bit 4 - Cloud Shadow
  var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
  var saturationMask = image.select('QA_RADSAT').eq(0);

  // Apply the scaling factors to the appropriate bands.
  var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
  var thermalBand = image.select('ST_B6').multiply(0.00341802).add(149.0);

  // Replace the original bands with the scaled ones and apply the masks.
  return image.addBands(opticalBands, null, true)
      .addBands(thermalBand, null, true)
      .updateMask(qaMask)
      .updateMask(saturationMask);
}

// Define a list of unique observation years from the image collection.
var years = ee.List(lsCol.aggregate_array('year')).distinct().sort();

// Map over the list of years to build a list of annual image composites.
var lsCompList = years.map(function(year) {
  return lsCol
    // Filter image collection by year.
    .filterMetadata('year', 'equals', year)
    // Apply cloud mask.
    .map(maskL457sr)
    // Reduce image collection by median.
    .reduce(ee.Reducer.median())
    // Set composite year as an image property.
    .set('year', year);
});

// Convert the image List to an ImageCollection.
var lsCompCol = ee.ImageCollection.fromImages(lsCompList);

Dane roczne na podstawie funkcji join and reduce

Pamiętaj, że dwie poprzednie metody komponowania mapują List dni i lat, aby stopniowo definiować nowe daty do filtrowania i komponowania. Inną metodą wykonania tej operacji jest zastosowanie złączenia. W tym fragmencie kodu zdefiniowano unikalną kolekcję year, a następnie zastosowano złączenia saveAll, aby zidentyfikować wszystkie obrazy odpowiadające danemu roku. Obrazy należące do danego roku są grupowane w obiekt List, który jest przechowywany jako właściwość reprezentująca dany rok w odrębnej kolekcji roku. Na podstawie tych list są tworzone roczne zbiorcze dane, które powstają przez zredukowanie wartości ImageCollections zdefiniowanych przez te listy w ramach funkcji mapowanej na zbiór distinct year.

Edytor kodu (JavaScript)

// Assemble a collection of Landsat surface reflectance images for a given
// region and day-of-year range.
var lsCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2')
  .filterBounds(ee.Geometry.Point(-122.9, 43.6))
  .filter(ee.Filter.dayOfYear(182, 243))
  // Add the observation year as a property to each image.
  .map(function(img) {
    return img.set('year', ee.Image(img).date().get('year'));
  });

// Make a distinct year collection; one image representative per year.
var distinctYears = lsCol.distinct('year').sort('year');

// Define a join filter; one-to-many join on ‘year’ property.
var filter = ee.Filter.equals({leftField: 'year', rightField: 'year'});

// Define a join.
var join = ee.Join.saveAll('year_match');

// Apply the join; results in 'year_match' property being added to each distinct
// year representative image. The list includes all images in the collection
// belonging to the respective year.
var joinCol = join.apply(distinctYears, lsCol, filter);

// Define a function to scale the data and mask unwanted pixels.
function maskL457sr(image) {
  // Bit 0 - Fill
  // Bit 1 - Dilated Cloud
  // Bit 2 - Unused
  // Bit 3 - Cloud
  // Bit 4 - Cloud Shadow
  var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
  var saturationMask = image.select('QA_RADSAT').eq(0);

  // Apply the scaling factors to the appropriate bands.
  var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
  var thermalBand = image.select('ST_B6').multiply(0.00341802).add(149.0);

  // Replace the original bands with the scaled ones and apply the masks.
  return image.addBands(opticalBands, null, true)
      .addBands(thermalBand, null, true)
      .updateMask(qaMask)
      .updateMask(saturationMask);
}

// Map over the distinct years collection to build a list of annual image
// composites.
var lsCompList = joinCol.map(function(img) {
  // Get the list of images belonging to the given year.
  return ee.ImageCollection.fromImages(img.get('year_match'))
    // Apply cloud mask.
    .map(maskL457sr)
    // Reduce image collection by median.
    .reduce(ee.Reducer.median())
    // Set composite year as an image property.
    .copyProperties(img, ['year']);
});

// Convert the image List to an ImageCollection.
var lsCompCol = ee.ImageCollection(lsCompList);

Dane złożone z użyciem funkcji dodawania i odstawiania w ramach tego samego dnia

Dodatkowym zastosowaniem kompozycji jest tworzenie spójnych przestrzennie mozaikowych obrazów. Załóżmy, że interesujący Cię region obejmuje 2 wiersze Landsat w ramach tej samej ścieżki, a Twoim celem jest wyświetlenie mozaiki zdjęć z 2 orbit Landsat 8 w latach 2017 i 2018. Po przefiltrowaniu zbioru według ścieżki i wiersza operacja złączenia jest używana do tworzenia mozaikowych obrazów Landsat z tego samego obłotu, zdefiniowanego przez datę przechwycenia.

Edytor kodu (JavaScript)

var lsCol = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
  .filterDate('2017-01-01', '2019-01-01')
  .filter('WRS_PATH == 38 && (WRS_ROW == 28 || WRS_ROW == 29)')
  .map(function(img) {
    var date = img.date().format('yyyy-MM-dd');
    return img.set('date', date);
  });

var distinctDates = lsCol.distinct('date').sort('date');
var filter = ee.Filter.equals({leftField: 'date', rightField: 'date'});
var join = ee.Join.saveAll('date_match');
var joinCol = join.apply(distinctDates, lsCol, filter);

var lsColMos = ee.ImageCollection(joinCol.map(function(col) {
  return ee.ImageCollection.fromImages(col.get('date_match')).mosaic();
}));

Sortowanie

Możesz posortować kolekcję według czasu, aby zapewnić prawidłową kolejność chronologiczną, lub według wybranej usługi. Domyślnie seria klatek wizualizacji jest sortowana według naturalnego porządku kolekcji. Układ serii można zmienić za pomocą metody zbioru sort, w której wybrana zostaje właściwość Image do sortowania w kolejności rosnącej lub malejącej. Aby na przykład sortować według czasu obserwacji, użyj właściwości system:time_start.

Edytor kodu (JavaScript)

var s2col = ee.ImageCollection('COPERNICUS/S2_SR')
  .filterBounds(ee.Geometry.Point(-122.1, 37.2))
  .sort('system:time_start');

Może też być tak, że kolejność powinna być określana na podstawie stopnia zachmurzenia, jak w przypadku zdjęć Sentinel-2.

Edytor kodu (JavaScript)

var s2col = ee.ImageCollection('COPERNICUS/S2_SR')
  .filterBounds(ee.Geometry.Point(-122.1, 37.2))
  .sort('CLOUDY_PIXEL_PERCENTAGE');

Kolejność może być też zdefiniowana na podstawie właściwości pochodnej, takiej jak średnia regionalna NDVI. W tym przypadku regionalna wartość NDVI jest dodawana jako właściwość do każdego obrazu w ramach zmapowanej funkcji, a następnie następuje sortowanie według tej nowej właściwości.

Edytor kodu (JavaScript)

// Define an area of interest geometry.
var aoi = ee.Geometry.Point(-122.1, 37.2).buffer(1e4);

// Filter MODIS NDVI image collection by a date range.
var ndviCol = ee.ImageCollection('MODIS/061/MOD13A1')
  .filterDate('2018-01-01', '2019-01-01')
  .select('NDVI')
  // Map over the image collection to calculate regional mean NDVI and add
  // the result to each image as a property.
  .map(function(img) {
    var meanNdvi = img.reduceRegion({
      reducer: ee.Reducer.mean(), geometry: aoi, scale: 500});
    return img.set('meanNdvi', meanNdvi.get('NDVI'));
  })
  // Sort the collection by descending regional mean NDVI.
  .sort('meanNdvi', false);

Wizualizacja obrazu

Wizualizacja obrazu zamienia liczby w kolory. Dane obrazów możesz przedstawiać w metodach wizualizacji zbiorów na 3 sposoby:

  1. Przekaż argumenty wizualizacji bezpośrednio do getVideoThumbURLgetFilmstripThumbURL.
  2. Przed zastosowaniem metody getVideoThumbURLgetFilmstripThumbURL zmapuj metodę visualize na kolekcji obrazów.
  3. Przed zastosowaniem metody getVideoThumbURLgetFilmstripThumbURL zmapuj metodę sldStyle na kolekcji obrazów. Więcej informacji znajdziesz w artykule Styled Layer Descriptor.

Przykłady w tym przewodniku wykorzystują opcje 1 i 2, w których wizualizacja jest osiągana przez mapowanie 3 pasm obrazu wielopasmowego na kanały kolorów czerwonego, zielonego i niebieskiego lub przez stopniowe przypisywanie wartości pojedynczego pasma wzdłuż palety kolorów. Parametry wizualizacji:

Parametry wizualizacji
Parametr Opis Typ
pasm Lista nazw 3 pasm rozdzielona przecinkami, które mają zostać mapowane na RGB lista
min Wartości do mapowania na 0 liczba lub lista 3 liczb, po jednej dla każdego pasma
max Wartości do zmapowania na 255 liczba lub lista 3 liczb, po jednej dla każdego pasma
gain Wartości, przez które należy pomnożyć każdą wartość piksela liczba lub lista 3 liczb, po jednej dla każdego pasma
uprzedzanie Wartości do dodania do każdego DN liczba lub lista 3 liczb, po jednej dla każdego pasma
gamma Współczynniki korekcji gamma liczba lub lista 3 liczb, po jednej dla każdego pasma
palette Lista ciągów znaków kolorów w stylu CSS (tylko w przypadku obrazów jednopasmowych) lista ciągów szesnastkowych rozdzielona przecinkami
przezroczystość Przezroczystość warstwy (0,0 oznacza pełną przezroczystość, a 1,0 – pełną nieprzezroczystość). liczba

Aby wybrać pasma, które chcesz wizualizować, użyj argumentu bands. Podaj listę zawierającą 1 lub 3 nazwy zespołów. W przypadku obrazów wielopasmowych domyślnie wybrane są 3 pierwsze pasma. Kolejność nazw pasm określa przypisanie kolorów. Pierwszy, drugi i trzeci wymieniony pasm jest odpowiednio przypisany do koloru czerwonego, zielonego i niebieskiego.

Skalowanie zakresu danych jest ważnym czynnikiem podczas wizualizacji obrazów. Domyślnie wartości danych zmiennoprzecinkowych z zakresu od 0 do 1 (włącznie) są skalowane do zakresu od 0 do 255 (włącznie). Wartości spoza tego zakresu są ustawiane na 0 lub 255, odpowiednio w zależności od tego, czy są one mniejsze od 0 czy większe od 1. W przypadku danych całkowitych pełna pojemność zdefiniowana przez jego typ jest skalowana w zakresie od 0 do 255 (np. 16-bitowe dane podpisane mają zakres od −32 768 do 32 767, który domyślnie jest skalowany do [0, 255]). Zaakceptowanie domyślnych ustawień może spowodować, że wizualizacje będą miały niewielki lub żaden kontrast między elementami obrazu. Użyj funkcji min i max, aby zwiększyć kontrast i podkreślić określony zakres danych. Jako zasadę możesz przyjąć, że wartości minmax powinny odpowiadać 2. i 98. percentylowi danych w obszarze, który Cię interesuje. Poniżej znajdziesz przykład obliczenia tych wartości w przypadku cyfrowego modelu rzeźby terenu.

Edytor kodu (JavaScript)

// Import SRTM global elevation model.
var demImg = ee.Image('USGS/SRTMGL1_003');

// Define a rectangular area of interest.
var aoi = ee.Geometry.Polygon(
  [[
    [-103.84153083119054, 49.083004219142886],
    [-103.84153083119054, 25.06838270664608],
    [-85.64817145619054, 25.06838270664608],
    [-85.64817145619054, 49.083004219142886]
  ]],
  null, false);

// Calculate the 2nd and 98th percentile elevation values from rescaled (to
// 500m) pixels intersecting the area of interest. A Dictionary is returned.
var percentClip = demImg.reduceRegion({
  reducer: ee.Reducer.percentile([2, 98]),
  geometry: aoi,
  scale: 500,
  maxPixels: 3e7
});

// Print the regional 2nd and 98th percentile elevation values. Get the
// dictionary keys and use them to get the values for each percentile summary.
var keys = percentClip.keys();
print('Set vis min to:', ee.Number(percentClip.get(keys.get(0))).round());
print('Set vis max to:', ee.Number(percentClip.get(keys.get(1))).round());

Parametr palette definiuje kolory, które mają reprezentować 8-bitowy obraz wizualizacji. Dotyczy to tylko reprezentacji jednopasmowych. Podanie go w przypadku obrazu wielopasmowego spowoduje błąd. Jeśli dane są jednopasmowe lub chcesz zobrazować jeden pas z wielkopasmowego obrazu, ustaw parametr forceRgbOutput na true (niepotrzebny, jeśli podano argument palette). Użyj parametrów minmax, aby zdefiniować zakres wartości, które mają być skalowane liniowo od 0 do 255.

Poniżej przedstawiamy przykład mapowania funkcji wizualizacji na zbiorze obrazów jednopasmowych. Zaimportowana zostaje kolekcja MODIS NDVI, ustawiane są argumenty wizualizacji dla metody visualization, a funkcja, która przekształca wartości w reprezentacje obrazów RGB, jest mapowana na kolekcję NDVI.

Edytor kodu (JavaScript)

// Filter MODIS NDVI image collection by a date range.
var ndviCol = ee.ImageCollection('MODIS/061/MOD13A1')
  .filterDate('2018-01-01', '2019-01-01')
  .select('NDVI');

// Define visualization arguments.
var visArgs = {
  min: 0,
  max: 9000,
  palette: [
    'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901',
    '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01',
    '012E01', '011D01', '011301'
  ]
};

// Define a function to convert an image to an RGB visualization image and copy
// properties from the original image to the RGB image.
var visFun = function(img) {
  return img.visualize(visArgs).copyProperties(img, img.propertyNames());
};

// Map over the image collection to convert each image to an RGB visualization
// using the previously defined visualization function.
var ndviColVis = ndviCol.map(visFun);

Oto przykład mapowania funkcji wizualizacji na kolekcji obrazów wielopasmowych:

Edytor kodu (JavaScript)

// Assemble a collection of Sentinel-2 surface reflectance images for a given
// region and date range.
var s2col = ee.ImageCollection('COPERNICUS/S2_SR')
  .filterBounds(ee.Geometry.Point(-96.9037, 48.0395))
  .filterDate('2019-06-01', '2019-10-01');

// Define visualization arguments.
var visArgs = {bands: ['B11', 'B8', 'B3'], min: 300, max: 3500};

// Define a function to convert an image to an RGB visualization image and copy
// properties from the original image to the RGB image.
var visFun = function(img) {
  return img.visualize(visArgs).copyProperties(img, img.propertyNames());
};

// Map over the image collection to convert each image to an RGB visualization
// using the previously defined visualization function.
var s2colVis = s2col.map(visFun);

W tym przypadku nie podano argumentu palette, ponieważ podano 3 pasma, które określają natężenie każdej warstwy RGB. Pamiętaj, że oba przykłady używają parametrów min i max, aby kontrolować, które wartości są rozciągane do granic 8-bitowych danych RGB.

Miniatura filmu

Funkcja getVideoThumbURL() generuje animację ze wszystkich obrazów w ImageCollection, gdzie każdy obraz reprezentuje jedną klatkę. Ogólny proces tworzenia animacji wygląda tak:

  1. Zdefiniuj Geometry, którego granice określają zasięg regionalny animacji.
  2. Określ ImageCollection.
  3. Rozważ wizualizację obrazu: mapuj funkcję wizualizacji obrazu na kolekcji lub dodaj argumenty wizualizacji obrazu do zestawu argumentów animacji.
  4. Zdefiniuj argumenty animacji i wywołaj metodę getVideoThumbURL.

Wynik funkcji getVideoThumbURL to adres URL. Wydrukuj adres URL w konsoli i kliknij go, aby uruchomić serwery Earth Engine, które będą generować animację na bieżąco w nowej karcie przeglądarki. Możesz też wyświetlić animację w konsoli Edytora kodu, wywołując funkcję ui.Thumbnail w zbiorze i odpowiednich argumentach animacji. Po renderowaniu animacji możesz ją pobrać, klikając ją prawym przyciskiem myszy i wybierając odpowiednie opcje w menu kontekstowym.

Ten przykład pokazuje generowanie animacji przedstawiającej globalne temperatury w ciągu 24 godzin. Zwróć uwagę, że ten przykład zawiera argumenty wizualizacji wraz z argumentami animacji, zamiast najpierw mapowania funkcji wizualizacji na ImageCollection. Po uruchomieniu tego skryptu w konsoli edytora kodu powinna pojawić się animacja podobna do tej na rysunku 3.

Edytor kodu (JavaScript)

// Define an area of interest geometry with a global non-polar extent.
var aoi = ee.Geometry.Polygon(
  [[[-179.0, 78.0], [-179.0, -58.0], [179.0, -58.0], [179.0, 78.0]]], null,
  false);

// Import hourly predicted temperature image collection for northern winter
// solstice. Note that predictions extend for 384 hours; limit the collection
// to the first 24 hours.
var tempCol = ee.ImageCollection('NOAA/GFS0P25')
  .filterDate('2018-12-22', '2018-12-23')
  .limit(24)
  .select('temperature_2m_above_ground');

// Define arguments for animation function parameters.
var videoArgs = {
  dimensions: 768,
  region: aoi,
  framesPerSecond: 7,
  crs: 'EPSG:3857',
  min: -40.0,
  max: 35.0,
  palette: ['blue', 'purple', 'cyan', 'green', 'yellow', 'red']
};

// Print the animation to the console as a ui.Thumbnail using the above defined
// arguments. Note that ui.Thumbnail produces an animation when the first input
// is an ee.ImageCollection instead of an ee.Image.
print(ui.Thumbnail(tempCol, videoArgs));

// Alternatively, print a URL that will produce the animation when accessed.
print(tempCol.getVideoThumbURL(videoArgs));


Ilustracja 3. Godzinna temperatura powierzchni podczas zimowego przesilenia letniego na półkuli północnej przedstawiona jako animowany GIF.

Pasek zdjęć

Funkcja getFilmstripThumbUrl generuje pojedynczy obraz statyczny, który reprezentuje konkatenację wszystkich obrazów w ImageCollection w serii północ–południe. Sekwencja klatek filmu powinna być zgodna z naturalną kolejnością w kolekcji.

Wynik funkcji getFilmstripThumbUrl to adres URL. Wydrukuj adres URL w konsoli i kliknij go, aby uruchomić serwery Earth Engine, które na bieżąco będą generować obraz na nowej karcie przeglądarki. Po renderowaniu obraz jest dostępny do pobrania. Aby go pobrać, kliknij go prawym przyciskiem myszy i w menu kontekstowym wybierz odpowiednie opcje.

Ten fragment kodu używa tej samej kolekcji co przykład miniatury filmu powyżej. Po uruchomieniu tego skryptu w konsoli Edytora kodu powinien pojawić się pasek filmowy podobny do tego na rysunku 4.

Edytor kodu (JavaScript)

// Define an area of interest geometry with a global non-polar extent.
var aoi = ee.Geometry.Polygon(
  [[[-179.0, 78.0], [-179.0, -58.0], [179.0, -58.0], [179.0, 78.0]]], null,
  false);

// Import hourly predicted temperature image collection for northern winter
// solstice. Note that predictions extend for 384 hours; limit the collection
// to the first 24 hours.
var tempCol = ee.ImageCollection('NOAA/GFS0P25')
  .filterDate('2018-12-22', '2018-12-23')
  .limit(24)
  .select('temperature_2m_above_ground');

// Define arguments for the getFilmstripThumbURL function parameters.
var filmArgs = {
  dimensions: 128,
  region: aoi,
  crs: 'EPSG:3857',
  min: -40.0,
  max: 35.0,
  palette: ['blue', 'purple', 'cyan', 'green', 'yellow', 'red']
};

// Print a URL that will produce the filmstrip when accessed.
print(tempCol.getFilmstripThumbURL(filmArgs));


Ilustracja 4. Godzinna temperatura powierzchni dla zimowego przesilenia w Północnej Hemisferze Północnej przedstawiona jako pasek filmu w formacie PNG. Pamiętaj, że taśma filmowa została podzielona na 4 sekcje. Wynik funkcji getFilmstripThumbURL to pojedyncza seria obrazów z kolekcji połączonych w sposób poziomy.

Techniki zaawansowane

W kolejnych sekcjach opisujemy, jak za pomocą kadrowania, przezroczystości i kompozycji warstw ulepszać wizualizacje przez dodawanie obramowań wielokątów, podkreślanie interesujących obszarów i porównywanie obrazów w ramach kolekcji.

Pamiętaj, że wszystkie przykłady w tej sekcji używają tej samej wartości podstawowej ImageCollection określonej tutaj:

Edytor kodu (JavaScript)

// Import hourly predicted temperature image collection for northern winter
// solstice. Note that predictions extend for 384 hours; limit the collection
// to the first 24 hours.
var tempCol = ee.ImageCollection('NOAA/GFS0P25')
  .filterDate('2018-12-22', '2018-12-23')
  .limit(24)
  .select('temperature_2m_above_ground');

// Define visualization arguments to control the stretch and color gradient
// of the data.
var visArgs = {
  min: -40.0,
  max: 35.0,
  palette: ['blue', 'purple', 'cyan', 'green', 'yellow', 'red']
};

// Convert each image to an RGB visualization image by mapping the visualize
// function over the image collection using the arguments defined previously.
var tempColVis = tempCol.map(function(img) {
  return img.visualize(visArgs);
});

// Import country features and filter to South American countries.
var southAmCol = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017')
  .filterMetadata('wld_rgn', 'equals', 'South America');

// Define animation region (South America with buffer).
var southAmAoi = ee.Geometry.Rectangle({
  coords: [-103.6, -58.8, -18.4, 17.4], geodesic: false});

Nakładki

Wiele obrazów można nałożyć za pomocą metody blend Image, w której nakładają się piksele z 2 obrazów na podstawie ich masek (przezroczystości).

Nakładka wektorowa

Dodanie do obrazu poligonów granic administracyjnych i innych geometrii może zapewnić cenny kontekst przestrzenny. Zapoznaj się z animowaną mapą globalnej temperatury powierzchni na dany dzień (rysunek 3). Granice między lądem a oceanem są w pewnym stopniu widoczne, ale można je wyraźnie zaznaczyć, dodając nakładkę poligonową krajów.

Dane wektorowe (Features) są nanoszone na obrazy za pomocą metody paint. Funkcje można nakładać na istniejący obraz, ale lepiej jest nakładać je na pusty obraz, nadać mu styl, a potem połączyć wynik z innymi warstwami obrazu. Odrębne traktowanie poszczególnych warstw zbioru wizualizacji daje większą kontrolę nad stylizacją.

W tym przykładzie pokazujemy wypełnianie granic krajów Ameryki Południowej pustą wartością Image i następnie mieszanie uzyskanego wyniku z każdą wartością Image z globalnej kolekcji temperatur dziennych (rys. 5). Nałożone granice krajów odróżniają ląd od wody i stanowią kontekst dla wzorów temperatury.

Edytor kodu (JavaScript)

// Define an empty image to paint features to.
var empty = ee.Image().byte();

// Paint country feature edges to the empty image.
var southAmOutline = empty
  .paint({featureCollection: southAmCol, color: 1, width: 1})
  // Convert to an RGB visualization image; set line color to black.
  .visualize({palette: '000000'});

// Map a blend operation over the temperature collection to overlay the country
// border outline image on all collection images.
var tempColOutline = tempColVis.map(function(img) {
  return img.blend(southAmOutline);
});

// Define animation arguments.
var videoArgs = {
  dimensions: 768,
  region: southAmAoi,
  framesPerSecond: 7,
  crs: 'EPSG:3857'
};

// Display the animation.
print(ui.Thumbnail(tempColOutline, videoArgs));


Rysunek 5. Dodawaj nakładki wektorowe do obrazów w kolekcji, aby nadać im kontekst przestrzenny.

Nakładka graficzna

Aby uzyskać pożądany styl, możesz nałożyć kilka obrazów. Załóżmy, że chcesz podkreślić obszar zainteresowania. Możesz utworzyć cichą kopię wizualizacji obrazu jako warstwy podstawowej, a potem nałożyć na nią wersję obrazu z wyciętymi krawędziami. Na podstawie poprzedniego przykładu poniższy skrypt wygeneruje rysunek 6.

Edytor kodu (JavaScript)

// Define an empty image to paint features to.
var empty = ee.Image().byte();

// Paint country feature edges to the empty image.
var southAmOutline = empty
  .paint({featureCollection: southAmCol, color: 1, width: 1})
  // Convert to an RGB visualization image; set line color to black.
  .visualize({palette: '000000'});

// Map a blend operation over the temperature collection to overlay the country
// border outline image on all collection images.
var tempColOutline = tempColVis.map(function(img) {
  return img.blend(southAmOutline);
});

// Define a partially opaque grey RGB image to dull the underlying image when
// blended as an overlay.
var dullLayer = ee.Image.constant(175).visualize({
  opacity: 0.6, min: 0, max: 255, forceRgbOutput: true});

// Map a two-part blending operation over the country outline temperature
// collection for final styling.
var finalVisCol = tempColOutline.map(function(img) {
  return img
    // Blend the dulling layer with the given country outline temperature image.
    .blend(dullLayer)
    // Blend a clipped copy of the country outline temperature image with the
    // dulled background image.
    .blend(img.clipToCollection(southAmCol));
});

// Define animation arguments.
var videoArgs = {
  dimensions: 768,
  region: southAmAoi,
  framesPerSecond: 7,
  crs: 'EPSG:3857'
};

// Display the animation.
print(ui.Thumbnail(finalVisCol, videoArgs));


Rysunek 6. Podkreśl interesujący Cię obszar, przycinając obraz i nakładając go na stonowaną kopię.

Możesz też mieszać dane obrazu z warstwą podstawową z cieniowaniem wypukłości, aby wskazać ukształtowanie terenu i nadać wizualizacji głębi (ryc. 7).

Edytor kodu (JavaScript)

// Define a hillshade layer from SRTM digital elevation model.
var hillshade = ee.Terrain.hillshade(ee.Image('USGS/SRTMGL1_003')
  // Exaggerate the elevation to increase contrast in hillshade.
  .multiply(100))
  // Clip the DEM by South American boundary to clean boundary between
  // land and ocean.
  .clipToCollection(southAmCol);

// Map a blend operation over the temperature collection to overlay a partially
// opaque temperature layer on the hillshade layer.
var finalVisCol = tempColVis.map(function(img) {
  return hillshade
    .blend(img.clipToCollection(southAmCol).visualize({opacity: 0.6}));
});

// Define animation arguments.
var videoArgs = {
  dimensions: 768,
  region: southAmAoi,
  framesPerSecond: 7,
  crs: 'EPSG:3857'
};

// Display the animation.
print(ui.Thumbnail(finalVisCol, videoArgs));


Rysunek 7. Wyświetlanie terenu przez nałożenie częściowo przezroczystych danych obrazu na warstwę cieniowania wzniesień.

Przejścia

Dostosuj kolekcję obrazów, aby utworzyć animacje, które pokazują różnice między dwoma obrazami w kolekcji za pomocą przejść typu znikanie, migotanie i przesuwanie. W każdym z tych przykładów użyto tej samej wizualizacji podstawowej wygenerowanej przez ten skrypt:

Edytor kodu (JavaScript)

// Define an area of interest geometry with a global non-polar extent.
var aoi = ee.Geometry.Polygon(
  [[[-179.0, 78.0], [-179.0, -58.0], [179.0, -58.0], [179.0, 78.0]]], null,
  false);

// Import hourly predicted temperature image collection.
var temp = ee.ImageCollection('NOAA/GFS0P25')

// Define a northern summer solstice temperature image.
var summerSolTemp = temp
  .filterDate('2018-06-21', '2018-06-22')
  .filterMetadata('forecast_hours', 'equals', 12)
  .first()
  .select('temperature_2m_above_ground');

// Define a northern winter solstice temperature image.
var winterSolTemp = temp
  .filterDate('2018-12-22', '2018-12-23')
  .filterMetadata('forecast_hours', 'equals', 12)
  .first()
  .select('temperature_2m_above_ground');

// Combine the solstice images into a collection.
var tempCol = ee.ImageCollection([
  summerSolTemp.set('season', 'summer'),
  winterSolTemp.set('season', 'winter')
]);

// Import international boundaries feature collection.
var countries = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017');

// Define visualization arguments.
var visArgs = {
  min: -40.0,
  max: 35.0,
  palette: ['blue', 'purple', 'cyan', 'green', 'yellow', 'red']
};

// Convert the image data to RGB visualization images.
// The clip and unmask combination sets ocean pixels to black.
var tempColVis = tempCol.map(function(img) {
  return img
    .visualize(visArgs)
    .clipToCollection(countries)
    .unmask(0)
    .copyProperties(img, img.propertyNames());
});

Flicker

Jeśli w kolekcji są tylko 2 obrazy, jak w tym przypadku, miganie jest domyślnym sposobem wyświetlania animacji kolekcji. Aby przyspieszyć lub spowolnić częstotliwość migotania, zmień argument animacji framesPerSecond. Poniższe argumenty wizualizacji zastosowane do kolekcji powyżej dają rysunek 8.

Edytor kodu (JavaScript)

// Define arguments for animation function parameters.
var videoArgs = {
  dimensions: 768,
  region: aoi,
  framesPerSecond: 2,
  crs: 'EPSG:3857'
};

// Display animation to the Code Editor console.
print(ui.Thumbnail(tempColVis, videoArgs));


Rysunek 8. Przykład migotania temperatury powierzchni o godzinie 12 GMT podczas przesilenia zimowego i letniego.

Zanikanie

Płynne przejście między 2 warstwami uzyskuje się przez jednoczesne zmniejszanie przezroczystości jednej warstwy i zwiększanie przezroczystości drugiej w sekwencji przyrostów przezroczystości od 0 do 1 (rysunek 9).

Edytor kodu (JavaScript)

// Define a sequence of decreasing opacity increments. Note that opacity cannot
// be 0, so near 1 and 0 are used. Near 1 is needed because a compliment is
// calculated in a following step that can result in 0 if 1 is an element of the
// list.
var opacityList = ee.List.sequence({start: 0.99999, end: 0.00001, count: 20});

// Filter the summer and winter solstice images from the collection and set as
// image objects.
var summerImg = tempColVis.filter(ee.Filter.eq('season', 'summer')).first();
var winterImg = tempColVis.filter(ee.Filter.eq('season', 'winter')).first();

// Map over the list of opacity increments to iteratively adjust the opacity of
// the two solstice images. Returns a list of images.
var imgList = opacityList.map(function(opacity) {
  var opacityCompliment = ee.Number(1).subtract(ee.Number(opacity));
  var winterImgFade = winterImg.visualize({opacity: opacity});
  var summerImgFade = summerImg.visualize({opacity: opacityCompliment});
  return summerImgFade.blend(winterImgFade).set('opacity', opacity);
});

// Convert the image list to an image collection; the forward phase.
var fadeForward = ee.ImageCollection.fromImages(imgList);

// Make a copy of the collection that is sorted by ascending opacity to
// represent the reverse phase.
var fadeBackward = fadeForward.sort({property: 'opacity'});

// Merge the forward and reverse phase frame collections.
var fadeCol = fadeForward.merge(fadeBackward);

// Define animation arguments.
var videoArgs = {
  dimensions: 768,
  region: aoi,
  framesPerSecond: 25,
  crs: 'EPSG:3857'
};

// Display the animation.
print(ui.Thumbnail(fadeCol, videoArgs));


Rysunek 9. Przykład zanikania między godziną 12:00 czasu Greenwich w dniu przesilenia letniego i zimowego.

Suwak

Podczas przesuwania suwaka stopniowo wyświetla się i ukrywa warstwa obrazu. Osiąga się to przez stopniowe dostosowywanie przezroczystości nałożonego obrazu w różnych zakresach długości geograficznej (ryc. 10).

Edytor kodu (JavaScript)

// Define a sequence of longitude increments. Start and end are defined by the
// min and max longitude of the feature to be provided to the region parameter
// of the animation arguments dictionary.
var lonSeq = ee.List.sequence({start: -179, end: 179, count: 20});

// Define a longitude image.
var longitude = ee.Image.pixelLonLat().select('longitude');

// Filter the summer and winter solstice images from the collection and set as
// image objects.
var summerImg = tempColVis.filter(ee.Filter.eq('season', 'summer')).first();
var winterImg = tempColVis.filter(ee.Filter.eq('season', 'winter')).first();

// Map over the list of longitude increments to iteratively adjust the mask
// (opacity) of the overlying image layer. Returns a list of images.
var imgList = lonSeq.map(function(lon) {
  lon = ee.Number(lon);
  var mask = longitude.gt(lon);
  return summerImg.blend(winterImg.updateMask(mask)).set('lon', lon);
});

// Convert the image list to an image collection; concealing phase.
var sliderColForward = ee.ImageCollection.fromImages(imgList);

// Make a copy of the collection that is sorted by descending longitude to
// represent the revealing phase.
var sliderColbackward = sliderColForward
  .sort({property: 'lon', ascending: false});

// Merge the forward and backward phase frame collections.
var sliderCol = sliderColForward.merge(sliderColbackward);

// Define animation arguments.
var videoArgs = {
  dimensions: 768,
  region: aoi,
  framesPerSecond: 25,
  crs: 'EPSG:3857'
};

// Display the animation.
print(ui.Thumbnail(sliderCol, videoArgs));


Rysunek 10. Przykład przesunięcia między temperaturą powierzchni o godzinie 12 GMT na czas przesilenia letniego i zimowego.