Загрузка манифеста изображения

Если вам требуется более гибкая загрузка изображений в Google Earth Engine (EE), чем пользовательский интерфейс редактора кода или команда upload инструмента командной строки Earthengine , вы можете сделать это, описав загрузку изображения с помощью файла JSON, известного как «манифест», и используя команду upload image --manifest инструмента командной строки.

См. полный пример в этом блокноте Colab , который демонстрирует загрузку фрагментов изображений как одного ресурса с помощью манифеста.

Одноразовая установка

  1. Загрузка манифеста работает только с файлами, расположенными в Google Cloud Storage . Чтобы начать использовать Google Cloud Storage, создайте проект Google Cloud , если у вас его еще нет. Обратите внимание, что для настройки необходимо указать кредитную карту для выставления счетов. Сама EE на данный момент ни с кого не взимает плату, но передача файлов в Google Cloud Storage перед их загрузкой в ​​EE потребует небольших затрат . Для типичных размеров загружаемых данных (десятки или сотни гигабайт) стоимость будет довольно низкой.
  2. В своем проекте включите Cloud Storage API и создайте корзину .
  3. Установите клиент Python Earth Engine . Он включает в себя инструмент командной строки earthengine , который мы будем использовать для загрузки данных.
  4. Для автоматической загрузки вы можете использовать учетную запись службы Google Cloud, связанную с вашим проектом. Для тестирования вам не нужна сервисная учетная запись, но когда у вас будет время, начните знакомиться с их использованием.

Исходные файлы очень большого размера (100 ГБ и более) могут быть загружены быстрее, если они разбиты на несколько фрагментов.

Идентификаторы и имена активов

Для ресурсов, принадлежащих облачным проектам, используйте следующее соглашение для имен ресурсов: projects/some-project-id/assets/some-asset-id .

Узнайте об именах активов для устаревших проектов и ресурсов, принадлежащих пользователям.

Для старых устаревших проектов имя актива в манифесте должно немного отличаться от идентификатора актива, отображаемого в других местах в Earth Engine. Чтобы загрузить ресурсы, идентификаторы которых начинаются с users/some_user или projects/some_project , к имени ресурса в манифесте перед идентификатором должна быть добавлена ​​строка projects/earthengine-legacy/assets/ . Например, идентификаторы активов EEusers users/username/my_geotiff следует загружать с использованием имени projects/earthengine-legacy/assets/users/username/my_geotiff .

Да, это означает, что идентификаторы, такие как projects/some_projects/some_asset преобразуются в имена, в которых projects упоминаются дважды: projects/earthengine-legacy/assets/projects/some_projects/some_asset . Это сбивает с толку, но необходимо для соответствия стандартам Google Cloud API.

Использование манифестов

Базовый манифест показан в следующем блоке кода. Он загружает файл small.tif из корзины Google Cloud Storage с именем gs://earthengine-test .

{
  "name": "projects/some-project-id/assets/some-asset-id",
  "tilesets": [
    {
      "sources": [
        {
          "uris": [
            "gs://earthengine-test/small.tif"
          ]
        }
      ]
    }
  ]
}

Чтобы использовать его, сохраните его в файл с именем manifest.json и запустите:

earthengine upload image --manifest /path/to/manifest.json

(Файл gs://earthengine-test/small.tif существует и доступен для публичного чтения — вы можете использовать его для тестирования.)

Тайлсеты

Несколько сложная структура манифеста JSON необходима, чтобы обеспечить достаточную гибкость для решения общей проблемы загрузки: как описать все возможные способы объединения пикселей из нескольких исходных файлов в один ресурс. В частности, существует два независимых способа группировки файлов:

  • Мозаика. Иногда несколько файлов представляют собой несколько плиток (например, каждая плитка представляет собой квадрат размером 1x1 градус). Такие файлы должны быть объединены в мозаику (объединены) в один и тот же канал в ресурсе EE.
  • Отдельные полосы. Иногда несколько файлов представляют несколько диапазонов. Такие файлы должны быть объединены в группы в ресурсе EE.

(Возможно, придется использовать оба способа одновременно, но это редкая ситуация.)

Для описания этих параметров в манифестах вводится понятие набора плиток . Один набор тайлов соответствует одному источнику GDAL. По этой причине все источники в одном тайлсете должны иметь одинаковую структуру GDAL (количество и тип каналов, проекцию, преобразование, недостающее значение). Поскольку источник GDAL может иметь несколько диапазонов, один набор тайлов может содержать данные для нескольких диапазонов EE.

Для приема мозаики манифест будет выглядеть так:

{
  "name": "projects/some-project-id/assets/some-asset-id",
  "tilesets": [
    {
      "sources": [
        {
          "uris": [
            "gs://bucket/N30W22.tif"
          ]
        },
        {
          "uris": [
            "gs://bucket/N31W22.tif"
          ]
        }
      ]
    }
  ]
}

Для отдельных бэндов манифест будет выглядеть так (вам также необходимо добавить раздел bands , как описано ниже):

{
  "name": "projects/some-project-id/assets/some-asset-id",
  "bands": ...,
  "tilesets": [
    {
      "id": "tileset_for_band1",
      "sources": [
        {
          "uris": [
            "gs://bucket/band1.tif"
          ]
        }
      ]
    },
    {
      "id": "tileset_for_band2",
      "sources": [
        {
          "uris": [
            "gs://bucket/band2.tif"
          ]
        }
      ]
    }
  ]
}

Обратите внимание, что в случае отдельных полос мы должны для ясности присвоить каждому тайлсету свой идентификатор тайлсета. Идентификатор набора тайлов может быть произвольной строкой — эти строки не сохраняются в загруженном ресурсе. Идентификаторы наборов плиток используются только при загрузке, чтобы отличать сложенные наборы плиток друг от друга.

Группы

Вторая важная концепция — сопоставление исходных файлов с диапазонами активов EE. Это делается с помощью раздела bands манифеста.

Раздел bands можно опустить, в этом случае бэнды создаются сначала из файлов первого набора тайлов, затем из следующего тайлсета и так далее. По умолчанию полосы называются «b1», «b2» и т. д. Чтобы переопределить имена полос по умолчанию, включите в конце раздел «bands», например:

{
  "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id",
  "tilesets": [
    {
      "sources": [
        {
          "uris": [
            "gs://bucket/rgb.tif"
          ]
        }
      ]
    }
  ],
  "bands": [
    {
      "id": "R",
      "tilesetBandIndex": 0
    },
    {
      "id": "G",
      "tilesetBandIndex": 1
    },
    {
      "id": "B",
      "tilesetBandIndex": 2
    }
  ]
}

Количество полос EE должно быть таким же, как общее количество полос во всех наборах плиток.

Если вы не хотите импортировать все каналы из файла, вы можете использовать поле tilesetBandIndex , чтобы указать, какой из каналов GDAL следует импортировать. Первый канал имеет tilesetBandIndex, равный 0.

Пример:

Предположим, что исходный файл имеет четыре полосы: «tmin», «tmin_error», «tmax», «tmax_error». Мы хотим принимать только «tmin» и «tmax». Соответствующие разделы манифеста будут выглядеть следующим образом:

{
  "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id",
  "tilesets": [
    {
      "id": "temperature",
      "sources": [
        {
          "uris": [
            "gs://bucket/temperature.tif"
          ]
        }
      ]
    }
  ],
  "bands": [
    {
      "id": "tmin",
      "tilesetBandIndex": 0,
      "tilesetId": "temperature"
    },
    {
      "id": "tmax",
      "tilesetBandIndex": 2,
      "tilesetId": "temperature"
    }
  ]
}

Маска-ленты

Маскирование полос контролируется компонентом манифеста maskBands . Поддерживаются три возможные конфигурации масок (но полоса маски всегда считается последней полосой в определенном файле).

  1. Маска для всех бэндов данных в одном файле.
  2. Маска для всех бэндов данных, поступающих из всех остальных файлов.
  3. Маска для некоторых диапазонов данных.

1. Наиболее распространенным случаем является одиночный файл GeoTIFF, последний канал которого используется в качестве маски для других каналов. Это работает только для файлов GeoTIFF типа Byte. Используйте следующий манифест:

{
  "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id",
  "tilesets": [
    {
      "id": "data_tileset",
      "sources": [
        {
          "uris": [
            "gs://bucket/data_file.tif"
          ]
        }
      ]
    }
  ],
  "bands": [
    {
      "id": "data_band",
      "tilesetId": "data_tileset"
    },
    {
      "id": "qa_band",
      "tilesetId": "data_tileset"
    }
  ],
  "maskBands": [
    {
      "tilesetId": "data_tileset"
    }
  ]
}

2. Чтобы использовать маску GeoTIFF в качестве маски для всех каналов в другом GeoTIFF, используйте следующий манифест:

{
  "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id",
  "tilesets": [
    {
      "id": "data_tileset",
      "sources": [
        {
          "uris": [
            "gs://bucket/data_file.tif"
          ]
        }
      ]
    },
    {
      "id": "mask_tileset",
      "sources": [
        {
          "uris": [
            "gs://bucket/mask_file.tif"
          ]
        }
      ]
    }
  ],
  "bands": [
    {
      "id": "data_band",
      "tilesetId": "data_tileset"
    },
    {
      "id": "qa_band",
      "tilesetId": "data_tileset"
    }
  ],
  "maskBands": [
    {
      "tilesetId": "mask_tileset"
    }
  ]
}

3. Чтобы использовать GeoTIFF в качестве маски для определенного бэнда в другом файле, используйте следующий манифест (отличие от предыдущего случая в том, что в maskBands установлено поле bandIds ):

{
  "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id",
  "tilesets": [
    {
      "id": "data_tileset",
      "sources": [
        {
          "uris": [
            "gs://bucket/data_file.tif"
          ]
        }
      ]
    },
    {
      "id": "mask_tileset",
      "sources": [
        {
          "uris": [
            "gs://bucket/mask_file.tif"
          ]
        }
      ]
    }
  ],
  "bands": [
    {
      "id": "data_band",
      "tilesetId": "data_tileset"
    },
    {
      "id": "qa_band",
      "tilesetId": "data_tileset"
    }
  ],
  "maskBands": [
    {
      "tilesetId": "mask_tileset",
      "bandIds": ["data_band"]
    }
  ]
}

В последнем примере мы работаем с двумя бэндами из набора тайлов data_tileset , но применяем маску только к одному из бэндов ( data_band ), как указано в поле bandIds единственного предоставленного объекта списка maskBands .

Обратите внимание, что в качестве полосы маски используется только последняя полоса набора тайлов, упомянутая в maskBands .

Политика пирамидирования

Когда Earth Engine создает пирамиды изображений во время приема, ему приходится неоднократно уменьшать сетки размером 2x2 пикселя в один пиксель, каким-то образом преобразуя значение пикселя. По умолчанию значения пикселей усредняются, что является правильным решением в большинстве случаев, когда полоса растра представляет собой более или менее непрерывные данные. Однако есть две ситуации, когда использование значения по умолчанию приведет к неверным результатам, и в этом случае поле pyramidingPolicy в определении канала должно быть установлено (если оно не установлено, по умолчанию предполагается, что его значение равно «MEAN»).

Для классификации растровых изображений (например, для классификации земного покрова) наиболее логичным способом построения пирамиды пикселей является использование большинства из четырех значений для создания следующего. Это делается с помощью политики пирамидирования «MODE»:

{
  "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id",
  "tilesets": [
    {
      "sources": [
        {
          "uris": [
            "gs://bucket/landcover.tif"
          ]
        }
      ]
    }
  ],
  "bands": [
    {
      "id": "landcover",
      "pyramidingPolicy": "MODE"
    }
  ]
}

Для растровых каналов, где ни «СРЕДНЕЕ», ни «РЕЖИМ» не имеют смысла (например, битовые пиксели), следует использовать политику построения пирамид «SAMPLE». «SAMPLE» всегда берет значение верхнего левого пикселя из каждой сетки 2x2. В следующем примере политика построения пирамид «MEAN» назначается полосе, представляющей непрерывную переменную («NDVI»), а политика «SAMPLE» — полосе «QA» данных.

{
  "name": "projects/earthengine-legacy/assets/users/username/some_folder/some_id",
  "tilesets": [
    {
      "sources": [
        {
          "uris": [
            "gs://bucket/ndvi.tif"
          ]
        }
      ]
    }
  ],
  "bands": [
    {
      "id": "NDVI",
      "tilesetBandIndex": 0,
      "pyramidingPolicy": "MEAN"
    },
    {
      "id": "QA",
      "tilesetBandIndex": 1,
      "pyramidingPolicy": "SAMPLE"
    }
  ]
}

Время начала и окончания

Для всех ресурсов должно быть указано время начала и окончания, чтобы предоставить больше контекста данным, особенно если они включены в коллекции. Эти поля не являются обязательными, но мы настоятельно рекомендуем использовать их, когда это возможно.

Время начала и окончания обычно означает время наблюдения, а не время создания исходного файла.

Для простоты время окончания рассматривается как исключительная граница. Например, для активов, охватывающих ровно один день, используйте полночь двух последовательных дней (например, 1980-01-31T00:00:00 и 1980-02-01T00:00:00) в качестве времени начала и окончания. Если у актива нет продолжительности, установите время окончания таким же, как время начала. Представляйте время в манифестах как строки ISO 8601 . Мы рекомендуем предположить, что время окончания является исключительным (например, полночь следующего дня для ежедневных ресурсов), чтобы упростить значения даты.

Пример:

{
  "name": "projects/some-project-id/assets/some-asset-id",
  "tilesets": [
    {
      "sources": [
        {
          "uris": [
            "gs://bucket/img_20190612.tif"
          ]
        }
      ]
    }
  ],
  "startTime": "1980-01-31T00:00:00Z",
  "endTime": "1980-02-01T00:00:00Z"
}

Справочник по структуре манифеста

Следующая структура JSON включает все возможные поля манифеста загрузки изображений. Определения полей можно найти в следующем разделе «Определения полей манифеста».

{
  "name": <string>,
  "tilesets": [
    {
      "dataType": <string>,
      "id": <string>,
      "crs": <string>,
      "sources": [
        {
          "uris": [
            <string>
          ],
          "affineTransform": {
            "scaleX": <double>,
            "shearX": <double>,
            "translateX": <double>,
            "shearY": <double>,
            "scaleY": <double>,
            "translateY": <double>
          }
        }
      ]
    }
  ],
  "bands": [
    {
      "id": <string>,
      "tilesetId": <string>,
      "tilesetBandIndex": <int32>,
      "missingData": {
        "values": [<double>]
      },
      "pyramindingPolicy": <string>
    }
  ],
  "maskBands": [
    {
      "tilesetId": <string>,
      "bandIds": [
        <string>
      ]
    }
  ],
  "footprint": {
    "points": [
      {
        "x": <double>,
        "y": <double>
      }
    ],
    "bandId": <string>
  },
  "missingData": {
     "values": [<double>]
  },
  "pyramidingPolicy": <string>,
  "uriPrefix": <string>,
  "startTime": {
    "seconds": <integer>
  },
  "endTime": {
    "seconds": <integer>
  },
  "properties": {
    <unspecified>
  }
}

Определения полей манифеста

имя

string

Имя создаваемого актива. name имеет формат «projects/*/assets/**» (например, «projects/earthengine-legacy/assets/users/USER/ASSET»).

наборы плиток

list

Список словарей, определяющих свойства наборов плиток. Дополнительные сведения см. в следующих полях элементов словаря tilesets .

наборы плиток[i].dataType

string

Указывает числовой тип данных. По умолчанию используется тип, о котором сообщает GDAL, и в этом случае нет необходимости определять его.

Тип данных Ценить
Не указано "DATA_TYPE_UNSPECIFIED"
8-битное целое число со знаком "ИНТ8"
8-битное целое число без знака "ЮИНТ8"
16-битное целое число со знаком "ИНТ16"
16-битное целое число без знака "ЮИНТ16"
32-битное целое число со знаком "ИНТ32"
32-битное целое число без знака "ЮИНТ32"
32-битное число с плавающей запятой "ПЛАВАНИЕ32"
64-битное число с плавающей запятой "ПЛАВАНИЕ64"

наборы плиток[i].id

string

Идентификатор набора тайлов. Должен быть уникальным среди наборов плиток, указанных в манифесте ресурса. Этот идентификатор отбрасывается на этапе обработки; он используется только для привязки набора плиток к группе. Пустая строка является действительным идентификатором.

наборы плиток[i].crs

string

Система координат пиксельной сетки, заданная в виде стандартного кода, где это возможно (например, код EPSG), и в формате WKT в противном случае.

tilesets[i].sources

list

Список словарей, определяющих свойства файла изображения и его дополнительных файлов. Дополнительные сведения см. в следующих полях элементов словаря sources .

tilesets[i].sources[j].uris

list

Список URI данных для приема. Поддерживаются только URI Google Cloud Storage. Каждый URI должен быть указан в следующем формате: gs://bucket-id/object-id . Основной объект должен быть первым элементом списка, а дополнительные элементы должны быть указаны после него. Каждый URI имеет префикс ImageManifest.uriPrefix , если он установлен.

tilesets[i].sources[j].affineTransform

dictionary

Необязательное аффинное преобразование. Следует указывать только в том случае, если данных из uris (включая любые сопутствующие элементы) недостаточно для размещения пикселей. Предоставляется в виде словаря со следующими ключами: «scaleX», «shearX», «translateX», «shearY», «scaleY», «translateY». См. эту ссылку для получения дополнительной информации.

Примеры ключей и значений:

{
  "scaleX": 0.1,
  "shearX": 0.0,
  "translateX": -180.0,
  "shearY": 0.0,
  "scaleY": -0.1,
  "translateY": 90.0
}

группы

list

Список словарей, определяющих свойства одной полосы, полученной из набора плиток. Обратите внимание, что порядок полос актива такой же, как и порядок bands . Дополнительные сведения см. в следующих полях элементов словаря bands .

полосы[i].id

string

ID (название) группы.

полосы[i].tilesetId

string

Идентификатор набора тайлов, соответствующего полосе.

полосы[i].tilesetBandIndex

int32

Индекс полосы, отсчитываемый от нуля, из набора плиток, соответствующего полосе.

полосы[i].missingData.values

list

Список значений (двойного типа), которые не представляют данных в полосе.

полосы[i].pyramidingPolicy

string

Политика пирамидирования. См. эту ссылку для получения дополнительной информации. Опции включают в себя:

  • «СРЕДНЕЕ» (по умолчанию)
  • "РЕЖИМ"
  • "ОБРАЗЕЦ"

маскаПовязки

list

Список словарей, определяющих свойства одной полосы маски, полученной из набора плиток. Может быть предоставлена ​​не более 1 маскировочной ленты. Дополнительные сведения см. в следующих полях элементов словаря maskBands .

MaskBands[i].tilesetId

string

Идентификатор набора тайлов, соответствующего полосе маски. Последняя полоса набора тайлов всегда используется как полоса маски.

маскаБандс[i].bandIds

list of strings

Список идентификаторов полос, к которым применяется маска. Если оно пусто, полоса маски применяется ко всем полосам в ресурсе. Каждой полосе может соответствовать только одна полоса маски.

след

dictionary

Словарь, определяющий свойства контура всех допустимых пикселей изображения. Если оно пустое, по умолчанию используется все изображение. Дополнительные сведения см. в следующих полях элементов словаря footprint .

след.точки

list

Список точек, определяющих площадь всех допустимых пикселей изображения. Точка определяется словарем с ключами «x» и «y», имеющими значения с плавающей запятой. Список точек должен описывать кольцо, образующее внешнюю часть простого многоугольника, который должен содержать центры всех допустимых пикселей изображения. Это должно быть линейное кольцо: последняя точка должна быть равна первой. Координаты находятся в проекции бэнда, заданного bandId .

Примечание. Используйте нецелочисленные координаты, например центр каждого пикселя, поскольку в footprint включается пиксель, если пиксель (прямоугольник 1x1) пересекает контур. Чтобы избежать случайного выбора соседних пикселей, не используйте целочисленные координаты, поскольку они являются границами между пикселями. Рисование контура вдоль центров пикселей предотвращает включение нежелательных пикселей, которые могут вызвать ошибки, когда предполагаемые пиксели примыкают к границе карты, такой как антимеридиан или полюс.

Например, для изображения 2x2 со всеми четырьмя действительными пикселями возможно следующее кольцо:

[
  {
    "x": 0.5,
    "y": 0.5
  },
  {
    "x": 0.5,
    "y": 1.5
  },
  {
    "x": 1.5,
    "y": 1.5
  },
  {
    "x": 1.5,
    "y": 0.5
  },
  {
    "x": 0.5,
    "y": 0.5
  }
]

footprint.bandId

string

Идентификатор полосы, CRS которой определяет координаты зоны обслуживания. Если пусто, используется первая полоса.

пропущенные данные.значения

list

Список значений (двойного типа), которые не представляют данных во всех каналах изображения. Применяется ко всем бэндам, которые не указывают свои собственные missingData .

Политика пирамидинга

string

Политика пирамидирования. Если не указано, политика «MEAN» применяется по умолчанию. Применяется ко всем группам, которые не указали свои собственные. См. эту ссылку для получения дополнительной информации. Опции включают в себя:

  • «СРЕДНЕЕ» (по умолчанию)
  • "РЕЖИМ"
  • "ОБРАЗЕЦ"

uriPrefix

string

Необязательный префикс, добавляемый ко всем uris определенным в манифесте.

время начала

integer

Временная метка, связанная с активом, если таковая имеется. Обычно это соответствует времени, когда был сделан спутниковый снимок. Для активов, которые соответствуют интервалу времени, например средним значениям за месяц или год, эта временная метка соответствует началу этого интервала. Указывается в секундах и (необязательно) наносекундах с начала эпохи (1970-01-01). Предполагается, что он находится в часовом поясе UTC.

время окончания

integer

Для активов, которые соответствуют интервалу времени, например средним значениям за месяц или год, эта временная метка соответствует концу этого интервала (исключительно). Указывается в секундах и (необязательно) наносекундах с начала эпохи (1970-01-01). Предполагается, что он находится в часовом поясе UTC.

характеристики

dictionary

Произвольный плоский словарь пар ключ-значение. Ключи должны быть строками, а значения могут быть числами или строками. Значения списка пока не поддерживаются для ресурсов, загруженных пользователем.

Ограничения

Размер манифеста JSON

Ограничение размера файла манифеста JSON составляет 10 МБ. Если вам нужно загрузить много файлов, подумайте о том, как уменьшить количество символов, необходимых для описания набора данных. Например, используйте поле uriPrefix , чтобы исключить необходимость указывать путь к корзине Google Cloud для каждого URI в списке uris . Если необходимо дальнейшее уменьшение размера, попробуйте сократить имена файлов.

Формат файла изображения

Каждый файл изображения должен быть изображением TIFF. Если CRS не указан в манифесте, файл должен быть GeoTIFF со встроенным CRS.

Файлы TIFF можно сжимать с помощью DEFLATE, JPEG-XL/JXL, LERC, LERC_DEFLATE, LERC_ZSTD, LZMA, LZW, WEBP или ZSTD.

Рекомендации по оптимизации загрузки больших файлов:

  • Лучший выбор: ZSTD предлагает хороший баланс скорости и сжатия.
  • Избегайте: LZMA может работать очень медленно, несмотря на хорошее сжатие.
  • Несжатые файлы: приведут к увеличению размера файлов и увеличению времени загрузки.
  • Сжатие с потерями (например, JPEG): может изменить значения пикселей. Используйте сжатие без потерь (например, DEFLATE, LZMA, LZW, ZSTD), если вы не осознаете потенциальное влияние на ваши данные.