NDVI: индекс растительности

Урок про NDVI — самый известный спектральный индекс, который по двум каналам спутникового снимка измеряет количество и здоровье растительности.

NDVI (Normalized Difference Vegetation Index) — нормализованный индекс, показывающий плотность зелёной растительности по разнице ближнего инфракрасного и красного каналов.

Здоровая зелёная листва ведёт себя со светом особым образом: она сильно поглощает красный свет (нужен для фотосинтеза) и сильно отражает ближний инфракрасный (NIR, невидимый глазу). На этом контрасте и построен NDVI: чем больше разница между NIR и Red, тем гуще и здоровее растительность. Со спутника так следят за урожаем, засухами, вырубками и состоянием лесов — за гигантскими территориями сразу.

Формула

$\text{NDVI} = \dfrac{NIR - Red}{NIR + Red}$

Деление на сумму (нормализация) приводит значение к диапазону от $-1$ до $+1$, не зависящему от общей яркости снимка. Это и значит «normalized» в названии.

NDVIЧто это
от 0.6 до 0.9густая здоровая растительность (лес, поле)
от 0.2 до 0.5редкая трава, кустарник
около 0голая почва, камень, дорога
меньше 0вода, снег, облака

Расчёт по одной точке

def ndvi(nir, red):
    return (nir - red) / (nir + red)

# Здоровое поле: высокий NIR, низкий Red
print(f"Поле:  {ndvi(0.50, 0.10):.3f}")
# Голая почва: NIR и Red близки
print(f"Почва: {ndvi(0.22, 0.20):.3f}")
# Вода: Red больше NIR -> отрицательный
print(f"Вода:  {ndvi(0.05, 0.12):.3f}")

Вывод:

Поле:  0.667
Почва: 0.048
Вода:  -0.412

Расчёт по растру

На снимке NDVI считают для каждого пикселя — это поэлементная операция над двумя каналами-матрицами. Промоделируем на маленьких растрах и заодно посчитаем долю «зелёных» пикселей:

nir = [[0.50, 0.48, 0.10],
       [0.52, 0.45, 0.08],
       [0.20, 0.22, 0.05]]
red = [[0.10, 0.12, 0.11],
       [0.09, 0.10, 0.10],
       [0.18, 0.19, 0.12]]

rows, cols = len(nir), len(nir[0])
green = 0
for i in range(rows):
    line = []
    for j in range(cols):
        v = (nir[i][j] - red[i][j]) / (nir[i][j] + red[i][j])
        line.append(f"{v:+.2f}")
        if v > 0.3:
            green += 1
    print(" ".join(line))

share = green / (rows * cols)
print(f"Растительность: {share:.0%} площади")

Вывод:

+0.67 +0.60 -0.05
+0.70 +0.64 -0.11
+0.05 +0.07 -0.41
Растительность: 44% площади

Как работает под капотом

Каналы со спутника приходят как целые числа (например 0–255 или 0–10000), их сперва переводят в физическую отражательную способность (reflectance) от 0 до 1 — иначе индекс будет неверным. NDVI — лишь один из семейства индексов: NDWI ловит воду, NDBI — застройку, EVI — улучшенный вегетационный для густых лесов. Все они строятся по одному принципу нормализованной разности каналов. В rasterio это пара строк: прочитать band 4 (NIR) и band 3 (Red), поделить разность на сумму — numpy сделает это сразу по всему массиву.

Частые ошибки

  • Перепутать каналы. NDVI требует именно NIR и Red; у разных спутников их номера band различаются — сверяйтесь с документацией.
  • Считать по сырым целым числам. Без перевода в reflectance индекс смещается; нормализуйте каналы.
  • Делить на ноль. Если $NIR + Red = 0$ (чёрный пиксель), формула падает; такие пиксели маскируют.

Что NDVI рассказывает о планете

За сухой формулой стоит один из самых мощных инструментов наблюдения за Землёй. По временным рядам NDVI агрономы видят фенологию полей: весной индекс растёт по мере всходов, держится на плато в пик вегетации и падает к уборке — и аномалия этой кривой загодя сигналит о засухе или болезни задолго до того, как ущерб станет виден с земли. Лесники по падению NDVI на больших площадях замечают вырубки и гари. Климатологи по многолетним трендам отслеживают озеленение или, наоборот, опустынивание целых регионов. Поскольку Sentinel и Landsat снимают одни и те же места регулярно и бесплатно, NDVI превращается в дешёвый непрерывный «пульс» биосферы планеты.

У индекса есть и ограничения, которые отличают грамотный анализ от наивного. NDVI «насыщается» в густых тропических лесах: при очень высокой биомассе он упирается в потолок около $0{,}9$ и перестаёт различать «много» и «очень много» зелени — для таких случаев придумали улучшенный индекс EVI. Облака и их тени портят пиксели, поэтому снимки фильтруют по облачности и собирают композиты из нескольких дат. А голая яркая почва или вода под тонким слоем растений смещают значение. Поэтому профессионал смотрит не на один снимок, а на серию, и интерпретирует NDVI с поправкой на тип покрова и сезон — индекс это термометр, а не диагноз.

Итог

  • NDVI $= \frac{NIR - Red}{NIR + Red}$, значения от $-1$ до $+1$.
  • Высокий NDVI — густая зелень, около нуля — почва, отрицательный — вода.
  • Считается поэлементно по каналам растра.
  • Каналы переводят в reflectance; NDVI — часть семейства индексов (NDWI, NDBI, EVI).
Проверьте себя
1. На каком физическом эффекте основан NDVI?
AРастения светятся в темноте
BЗдоровая листва поглощает красный свет и сильно отражает ближний инфракрасный
CРастения нагревают воздух
DЗелёный цвет ярче всех
2. Какой диапазон значений у NDVI?
Aот 0 до 255
Bот -1 до +1
Cот 0 до 100
Dлюбой
3. Какое значение NDVI типично для водной поверхности?
AОколо +0.8
BОтрицательное (Red больше NIR)
CРовно 1
DОколо +0.5