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).