GeoTIFF и растровые форматы
Урок про GeoTIFF — основной формат для растров: спутниковых снимков, карт высот и индексов вроде NDVI.
GeoTIFF — это обычная картинка формата TIFF, в которую добавлены теги геопривязки: координаты, размер ячейки и система координат.
Растр без геопривязки — это просто картинка: мы знаем яркость каждого пикселя, но не знаем, какому месту на Земле он соответствует. GeoTIFF решает это, дописывая в файл служебные теги: где находится левый верхний угол, какого размера ячейка и в какой проекции. После этого по индексу пикселя можно вычислить его координаты — и наоборот.
Геотрансформ: мост пиксель — координата
Привязку задаёт геотрансформ — шесть чисел. В простейшем случае (север вверху, оси не повёрнуты) это координаты угла $(x_0, y_0)$ и размеры ячейки. Координата пикселя с индексами $(col, row)$ считается так: $x = x_0 + col \cdot w$, $y = y_0 - row \cdot h$, где $w, h$ — ширина и высота ячейки. Минус во второй формуле потому, что номер строки растёт вниз, а координата $y$ (северная) — вверх. Посчитаем на чистом Python:
def pixel_to_coord(col, row, x0, y0, w, h):
x = x0 + col * w
y = y0 - row * h
return x, y
# Левый верхний угол снимка, ячейка 10 м (как Sentinel-2)
x0, y0 = 500000.0, 6200000.0
w = h = 10.0
for col, row in [(0, 0), (5, 0), (0, 3), (5, 3)]:
x, y = pixel_to_coord(col, row, x0, y0, w, h)
print(f"пиксель ({col},{row}) -> easting {x:.0f}, northing {y:.0f}")
Вывод:
пиксель (0,0) -> easting 500000, northing 6200000 пиксель (5,0) -> easting 500050, northing 6200000 пиксель (0,3) -> easting 500000, northing 6199970 пиксель (5,3) -> easting 500050, northing 6199970
Каналы (bands)
Снимок редко бывает одноканальным. Спутник снимает в нескольких диапазонах спектра — каждый диапазон это отдельный канал (band). Обычная фотография — три канала (красный, зелёный, синий). Sentinel-2 снимает 13 каналов, включая ближний инфракрасный (NIR), который не виден глазу, но критичен для анализа растительности. GeoTIFF хранит все каналы в одном файле как стопку матриц одинакового размера.
Каналы снимка (стопка матриц H x W):
band 1: Red [.. .. ..]
band 2: Green [.. .. ..]
band 3: Blue [.. .. ..]
band 4: NIR [.. .. ..] <- невидимый, для NDVI
Как работает под капотом
Большие GeoTIFF хранят данные не сплошняком, а плитками (tiles) и с несколькими уровнями детализации (overviews/пирамиды) — чтобы при отдалении читать грубую версию, а не весь файл. Современный подвид COG (Cloud-Optimized GeoTIFF) дополнительно раскладывает байты так, чтобы из облака можно было выкачать только нужный кусок по HTTP range-запросу. Читают GeoTIFF библиотекой rasterio:
import rasterio
with rasterio.open("sentinel.tif") as src:
print(src.width, src.height) # размер в пикселях
print(src.count) # число каналов
print(src.crs) # система координат
nir = src.read(4) # 4-й канал как массив
red = src.read(3)
Частые ошибки
- Сохранить растр в обычный PNG/JPEG. Тогда теряется геопривязка — выходит «просто картинка».
- Перепутать порядок каналов. У разных спутников NIR может быть в разном по счёту band; читайте метаданные.
- Игнорировать значение «нет данных» (nodata). Пиксели за краем снимка часто помечены спецзначением; включив их в среднее, испортите статистику.
Почему растровые форматы устроены сложнее картинок
На первый взгляд GeoTIFF — просто картинка, но требования к нему жёстче, чем к фотографии из телефона, и это формирует его устройство. Во-первых, значения часто не помещаются в привычные 8 бит на пиксель: высота рельефа бывает отрицательной (впадины ниже уровня моря) и требует знака, спектральная яркость идёт в 16 бит, расчётные индексы — вещественные числа. Поэтому GeoTIFF поддерживает разные типы данных в ячейке, от байта до 32-битного float, и перепутать их при чтении — значит получить мусор. Во-вторых, снимки огромны: один кадр Sentinel-2 это сотни мегабайт, а мозаика на регион — десятки гигабайт, и читать такое целиком ради фрагмента недопустимо.
Отсюда два важных решения формата. Плиточная организация (tiling) хранит растр квадратами, а не строками, чтобы прочитать прямоугольный фрагмент, не выкачивая весь файл. Пирамиды (overviews) держат заранее уменьшенные копии для быстрого показа при отдалении — иначе на мелком масштабе пришлось бы читать все пиксели, чтобы нарисовать пару экранных точек. Развитие этих идей — Cloud-Optimized GeoTIFF, который раскладывает байты так, что облачное хранилище отдаёт нужный кусок по HTTP range-запросу. Благодаря этому современные платформы анализируют петабайты снимков, ни разу не скачивая файлы целиком, — обрабатывая данные прямо там, где они лежат.
Итог
- GeoTIFF = картинка TIFF + теги геопривязки (координаты, ячейка, проекция).
- Геотрансформ переводит индекс пикселя в координату и обратно.
- Каналы (bands) хранят разные диапазоны спектра, включая невидимый NIR.
- COG-вариант позволяет читать кусок снимка прямо из облака.