Паншарпенинг при помощи R: различия между версиями
Нет описания правки |
|||
(не показано 14 промежуточных версий 1 участника) | |||
Строка 1: | Строка 1: | ||
{{Статья| | {{Статья|Опубликована|pansharp-r}} | ||
{{Аннотация|В данной статье рассказывается о том как произвести паншарпенинг в программной среде R. | {{Аннотация|В данной статье рассказывается о том как произвести паншарпенинг в программной среде R. | ||
Строка 21: | Строка 21: | ||
==Реализация== | ==Реализация== | ||
Для работы с растрами, имеющими географическую привязку в ''R'' есть замечательный пакет [http://cran.r-project.org/web/packages/raster/index.html ''raster'']. На основании функций, доступных в этом пакете мы и разработаем наш скрипт. В использовании он будет чрезвычайно прост: | Для работы с растрами, имеющими географическую, привязку в ''R'' есть замечательный пакет [http://cran.r-project.org/web/packages/raster/index.html ''raster'']. На основании функций, доступных в этом пакете мы и разработаем наш скрипт. В использовании он будет чрезвычайно прост: | ||
<syntaxhighlight lang="rsplus"> | <syntaxhighlight lang="rsplus"> | ||
library(raster) | library(raster) | ||
Строка 29: | Строка 29: | ||
pansharp <- processingPansharp(pan, multi) # производим паншарпенинг (эту функцию мы создадим) | pansharp <- processingPansharp(pan, multi) # производим паншарпенинг (эту функцию мы создадим) | ||
output_path <- 'путь_и_имя_файла_без_расширения' # зададим путь для сохранения результата | output_path <- 'путь_и_имя_файла_без_расширения' # зададим путь для сохранения результата | ||
saveResult(pansharp, output_path) # сохраним результат | saveResult(pansharp, output_path) # сохраним результат, используя минимум параметров при помощи функции-обёртки | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Строка 36: | Строка 36: | ||
pansharpFun <- function(raster){ | pansharpFun <- function(raster){ | ||
' Эта функция производит паншарпенинг ' | ' Эта функция производит паншарпенинг ' | ||
# @param raster - объект | # @param raster - объект класса Raster с тремя каналами: 1)с низким разрешением, 2) с высоким разрешением, 3) низкочастотная компонента растра с высоким разрешением | ||
# @return pansharpened_raster - подвергшийся паншарпенингу объект | # @return pansharpened_raster - подвергшийся паншарпенингу объект класса Raster | ||
# pansharp = Lowres * Highres / LPF[Highres] | # pansharp = Lowres * Highres / LPF[Highres] | ||
Строка 44: | Строка 44: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Вторая функция будет | Вторая функция будет выделять низкочастотную составляющую растра с высоким разрешением. | ||
<syntaxhighlight lang="rsplus"> | <syntaxhighlight lang="rsplus"> | ||
extractLPF <- function(pan, multi, filter = 'auto', fun = mean) { | extractLPF <- function(pan, multi, filter = 'auto', fun = mean) { | ||
' Возвращает низкочастотную компоненту растра с высоким разрешением | ' Возвращает низкочастотную компоненту растра с высоким разрешением | ||
с использованием скользящего окна, соответствующего размеру пикселя растра с низким разрешением ' | с использованием скользящего окна, соответствующего размеру пикселя растра с низким разрешением ' | ||
# @param pan - растр с высоким разрешением, объект | # @param pan - растр с высоким разрешением, объект класса Raster | ||
# @param multi - растр с низким разрешением, который в последствии будет подвергнут паншарпенингу, объект | # @param multi - растр с низким разрешением, который в последствии будет подвергнут паншарпенингу, объект класса Raster | ||
# @param filter - скользящее окно, объект | # @param filter - скользящее окно, объект класса матрица | ||
# @param fun - функция, которая производит вычисления на скользящем окне (параметр функции focal() ) | # @param fun - функция, которая производит вычисления на скользящем окне (параметр функции focal() ) | ||
# @return LPF - низкочатотная компонента растра с высоким разрешением, объект | # @return LPF - низкочатотная компонента растра с высоким разрешением, объект класса Raster | ||
# Расчитаем размер скользящего окна, если его параметры не заданы | # Расчитаем размер скользящего окна, если его параметры не заданы | ||
Строка 83: | Строка 83: | ||
processingPansharp <- function(pan, multi, filter = 'auto', fun = mean){ | processingPansharp <- function(pan, multi, filter = 'auto', fun = mean){ | ||
' Улучшает разрешение мультиспектрального растра за счёт панхроматического растра ' | ' Улучшает разрешение мультиспектрального растра за счёт панхроматического растра ' | ||
# @param pan - растр с высоким разрешением, объект | # @param pan - растр с высоким разрешением, объект класса Raster | ||
# @param multi - растр с низким разрешением, чьё разрешение необходимо улучшить, объект | # @param multi - растр с низким разрешением, чьё разрешение необходимо улучшить, объект класса Raster | ||
# @param filter - скользящее окно, объект | # @param filter - скользящее окно, объект класса матрица | ||
# @param fun - функция, которая производит вычисления на скользящем окне (параметр функции focal() ) | # @param fun - функция, которая производит вычисления на скользящем окне (параметр функции focal() ) | ||
# @return pansharp - растер 'multi' с улучшенным разрешением, объект | # @return pansharp - растер 'multi' с улучшенным разрешением, объект класса Raster | ||
LPF <- extractLPF(pan, multi, filter, fun) | LPF <- extractLPF(pan, multi, filter, fun) | ||
Строка 110: | Строка 110: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Ну, и наконец, последняя функция, носящая чисто утилитарный характер (позволяет использовать минимум параметров при сохранении растров) - обёртка к функции сохранения растра из пакета 'raster'. Идея состоит в том, что мы почти всегда будем хотеть сохранить результат в формате GeoTIFF, и при этом иметь целочисленный тип данных. Дело в том, что в большинстве случаев значения пикселей мультиспектрального растра - целые числа, а после паншарпенинга они становятся числами с плавающей запятой. Десятичные значения пикселя не несут никакой полезной информации, а занимают лишние сотни мегабайт дискового пространства. Использование целых чисел в качестве типа данных растра экономит более 0,5 Гб дискового пространства при паншарпенинге сцен WorldView-2. | |||
<syntaxhighlight lang="rsplus"> | |||
saveResult <- function(raster, path, format = 'GTiff', datatype = 'INT2S'){ | |||
' Сохраняет растр по указанному пути ' | |||
# @param raster - растр, который должен быть сохранён, объект класса Raser | |||
# @param path - путь к файлу (без расширения) - string | |||
# @param format - формат сохраняемого растра в соответствии с требованиями функции writeRaster() - string | |||
# @param datatype - тип данных сохраняемого растра в соответствии с требованиями функции to writeRaster() - string | |||
writeRaster(raster, | |||
path, | |||
format = format, | |||
datatype = datatype, | |||
overwrite = T) | |||
} | |||
</syntaxhighlight> | |||
==Результаты и обсуждение== | ==Результаты и обсуждение== | ||
Посмотрим на результат работы скрипта. | |||
[[Файл:Initial panchrome.png|thumb|center|x700px|Пахроматический растр с пространственным разрешением 0,5 м]] | [[Файл:Initial panchrome.png|thumb|center|x700px|Пахроматический растр с пространственным разрешением 0,5 м]] | ||
[[Файл:Initial multi.png|thumb|center|x700px|Мультиспектральный растр с пространственным разрешением 2,0 м]] | [[Файл:Initial multi.png|thumb|center|x700px|Мультиспектральный растр с пространственным разрешением 2,0 м]] | ||
[[Файл:R pansharp result.png|thumb|center|x700px|Мультиспектральный растр после паншарпенинга в R]] | [[Файл:R pansharp result.png|thumb|center|x700px|Мультиспектральный растр после паншарпенинга в R]] | ||
Результат можно сравнить с результатом паншарпенинга в Orfeo TollBox: | Результат можно сравнить с [http://%D0%9F%D0%B0%D0%BD%D1%88%D0%B0%D1%80%D0%BF%D0%B5%D0%BD%D0%B8%D0%BD%D0%B3_%D0%B2_QGIS_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_Orfeo_ToolBox результатом паншарпенинга в Orfeo TollBox]: | ||
[[Файл:OTB pansharp result.png|thumb|center|x700px|Мультиспектральный растр после паншарпенинга при помощи OTB]] | [[Файл:OTB pansharp result.png|thumb|center|x700px|Мультиспектральный растр после паншарпенинга при помощи OTB]] | ||
К сожалению, в raster не реализована многопоточность, поэтому производительность операций по обработке больших растров оставляет желать лучшего. | Мы видим, что картинка, производимая нашим алгоритмом выглядит как-будто она обработана фильтром, увеличивающим резкость. Кроме того, на ней легче различить оттенки, чем на той, которая является результатом работы ''OTB''. Если копать глубже, то выяснится, что ''OTB'' сохранил диапазон значений исходного (очевидно, происходит нормализация данных на одном из этапов обработки), тогда как после использования нашего скрипта диапазон значений пикселей мультиспектрального снимка изменился кардинально, см. рисунки ниже. После паншарпенинга в R очень большое количество пикселей получили значения более 1000. Это означает, что растр после паншарпенинга в ''OTB'' потенциально может быть использован для последующей радиометрической калибровки, а после паншарпенинга нашим скриптом - нет. Однако указанные различия в результатах работы нашего скрипта и ''OTB'' следует считать не недостатками, а особенностями, которые следует учитывать в работе. | ||
[[Файл:Histogram multi original.png|thumb|center|x500px|Гистограмма оригинального мультиспектрального растра]] | |||
[[Файл:Histogram pansharp r.png|thumb|center|x500px|Гистограмма мультиспектрального растра после паншарпенинга в R]] | |||
[[Файл:Histogram pansharp OTB.png|thumb|center|x500px|Гистограмма мультиспектрального растра послепаншарпенинга в OTB]] | |||
К очевидным же недостаткам использования ''R'' относится низкая скорость обработки изображений. К сожалению, в 'raster' не реализована многопоточность, поэтому производительность операций по обработке больших растров оставляет желать лучшего. | |||
==Заключение== | ==Заключение== | ||
В данной статье было продемонстрировано создание элементарного скрипта для паншарпенинга в ''R''. Отталкиваясь от приведённых здесь функций вы можете создавать собственные алгоритмы паншарпенинга или реализовывать чужие. К преимуществам использования R для паншарпенинга следует отнести широкий простор для кастомизации и творчества, а к недостаткам - низкую производительность, вызванную отсутствием многопоточности. | |||
==Ссылки по теме== | |||
[http://wiki.gis-lab.info/w/%D0%9F%D0%B0%D0%BD%D1%88%D0%B0%D1%80%D0%BF%D0%B5%D0%BD%D0%B8%D0%BD%D0%B3_%D0%B2_QGIS_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_Orfeo_ToolBox Паншарпенинг в QGIS с использованием Orfeo ToolBox] | |||
[http://gis-lab.info/qa/pan-sharpening-erdas.html Паншарпенинг в ERDAS] | |||
[http://gis-lab.info/qa/grass7-landsat8-processing.html#.D0.9F.D0.B0.D0.BD.D1.88.D0.B0.D1.80.D0.BF.D0.B5.D0.BD.D0.B8.D0.BD.D0.B3 Обработка и интерпретация данных Landsat 8 (OLI) средствами GRASS GIS 7 [раздел Паншарпенинг в GRASS]] | |||
[http://gis-lab.info/qa/sextante-qgis.html Геопроцессинг с SEXTANTE для QGIS] |
Текущая версия от 07:11, 3 июня 2015
по адресу http://gis-lab.info/qa/pansharp-r.html
В данной статье рассказывается о том как произвести паншарпенинг в программной среде R. [via Misanthrope's Thoughts]
Введение
Одной из наиболее рапространённых задач при работе со спутниковыми снимками является паншарпенинг. С этой задачёй успешно справляются и проприетарные и открытые программы для работы с ДДЗЗ. Но в некоторых случаях вам может захотеться иметь больший контроль над проводиммыми операциями или, быть может использовать алгоритм, ещё не реализованный ни в одном ПО. В таком случае на помощь придёт один из языков программирования, например, R.
В данной статье будет продемонстрирована реализация наиболее простого алгоритма паншарпенига - модуляции высоких частот.
Немного теории
На удивление сложно найти определение для слова "паншарпенинг". Попробуем сформулировать его своими словами, взяв за основу описание из книги Шовергердт Р.А. Дистанционное зондирование. Модели и методы обработки изображений - М.: Техносфера, 2010. (с. 416):
Паншарпенинг (от анг. Panchromatic sharpening) - это процесс объединения изображений в пространственной области основная задача которого заключается в передаче высокочастотного содержания изображения с высоким разрешением (обычно панхроматического) изображению с низким разрешением (обычно мультиспектральному).
Одним из наиболее простых алгоритмов паншарпенинга является модуляция высоких частот. В этом алгоритме для получения улучшенного изображения в канале PXS панхроматический снимок PAN попиксельно умножается на изображение с низким разрешением XS, после чего полученный результат нормируется на низкочастотную компоненту панхроматического снимка PANsmooth (панхроматический снимок, обработанный сглаживающим фильтром с окном, соответствующим размеру пикселя изображения с низким разрешением):
где i и j - индексы пикселей.
Реализация
Для работы с растрами, имеющими географическую, привязку в R есть замечательный пакет raster. На основании функций, доступных в этом пакете мы и разработаем наш скрипт. В использовании он будет чрезвычайно прост:
library(raster)
pan <- raster('pan.tif') # загружаем панхроматический растр
multi <- brick('multi.tif') # загружаем мультиспектральный растр
pansharp <- processingPansharp(pan, multi) # производим паншарпенинг (эту функцию мы создадим)
output_path <- 'путь_и_имя_файла_без_расширения' # зададим путь для сохранения результата
saveResult(pansharp, output_path) # сохраним результат, используя минимум параметров при помощи функции-обёртки
Начнём создавать необходимые функции. Первая функция - самая простая. Она всего-лишь реализовывает формулу, представленную выше.
pansharpFun <- function(raster){
' Эта функция производит паншарпенинг '
# @param raster - объект класса Raster с тремя каналами: 1)с низким разрешением, 2) с высоким разрешением, 3) низкочастотная компонента растра с высоким разрешением
# @return pansharpened_raster - подвергшийся паншарпенингу объект класса Raster
# pansharp = Lowres * Highres / LPF[Highres]
pansharpened_raster <- (raster[,1] * raster[,2]) / raster[,3]
}
Вторая функция будет выделять низкочастотную составляющую растра с высоким разрешением.
extractLPF <- function(pan, multi, filter = 'auto', fun = mean) {
' Возвращает низкочастотную компоненту растра с высоким разрешением
с использованием скользящего окна, соответствующего размеру пикселя растра с низким разрешением '
# @param pan - растр с высоким разрешением, объект класса Raster
# @param multi - растр с низким разрешением, который в последствии будет подвергнут паншарпенингу, объект класса Raster
# @param filter - скользящее окно, объект класса матрица
# @param fun - функция, которая производит вычисления на скользящем окне (параметр функции focal() )
# @return LPF - низкочатотная компонента растра с высоким разрешением, объект класса Raster
# Расчитаем размер скользящего окна, если его параметры не заданы
if (filter == 'auto') {
pan_res <- res(pan) # (x, y) пространственное разрешение растра с высоким разрешением в единицах CRS
multi_res <- res(multi) # (x, y) пространственное разрешение растра с низким разрешением в единицах CRS
x_res_ratio <- round(multi_res[1]/pan_res[1])
y_res_ratio <- round(multi_res[2]/pan_res[2])
total <- x_res_ratio + y_res_ratio
filter <- matrix(1, nc = x_res_ratio, nr = y_res_ratio)
}
# Убедимся, что у скользящего окна нечётное количество столбцов и строк (требование функции focal() )
if (nrow(filter)%%2 == 0) {
filter <- rbind(filter, 0)
}
if (ncol(filter)%%2 == 0) {
filter <- cbind(filter, 0)
LPF <- focal(pan, w = filter, fun = fun) # получаем низкочастотную компоненту при помощи функции focal() пакета 'raster'
}
Обратите внимание, что мы оставили возможность задавать пользовательские значения для параметров filter и fun, что оставляет простор для возможных экспериментов.
Теперь создадим функцию, объединяющую две предыдущие и выдающую растр с улучшенным разрешением.
processingPansharp <- function(pan, multi, filter = 'auto', fun = mean){
' Улучшает разрешение мультиспектрального растра за счёт панхроматического растра '
# @param pan - растр с высоким разрешением, объект класса Raster
# @param multi - растр с низким разрешением, чьё разрешение необходимо улучшить, объект класса Raster
# @param filter - скользящее окно, объект класса матрица
# @param fun - функция, которая производит вычисления на скользящем окне (параметр функции focal() )
# @return pansharp - растер 'multi' с улучшенным разрешением, объект класса Raster
LPF <- extractLPF(pan, multi, filter, fun)
multi <- resample(multi, pan) # приводим экстент и разрешение мультиспектрального растра к панхроматическому
all <- stack(multi, pan, LPF)
bands <- nbands(multi)
pan_band <- bands + 1
lpf_band <- bands + 2
# Производим паншарпенинг каналов мультиспектрального растра по очереди
pansharp_bands <- list()
for (band in 1:bands) {
subset <- all[[c(band, pan_band, lpf_band)]]
raster <- calc(subset, pansharpFun)
pansharp_bands[[band]] <- raster
}
pansharp <- stack(pansharp_bands) # итоговый растр
}
Ну, и наконец, последняя функция, носящая чисто утилитарный характер (позволяет использовать минимум параметров при сохранении растров) - обёртка к функции сохранения растра из пакета 'raster'. Идея состоит в том, что мы почти всегда будем хотеть сохранить результат в формате GeoTIFF, и при этом иметь целочисленный тип данных. Дело в том, что в большинстве случаев значения пикселей мультиспектрального растра - целые числа, а после паншарпенинга они становятся числами с плавающей запятой. Десятичные значения пикселя не несут никакой полезной информации, а занимают лишние сотни мегабайт дискового пространства. Использование целых чисел в качестве типа данных растра экономит более 0,5 Гб дискового пространства при паншарпенинге сцен WorldView-2.
saveResult <- function(raster, path, format = 'GTiff', datatype = 'INT2S'){
' Сохраняет растр по указанному пути '
# @param raster - растр, который должен быть сохранён, объект класса Raser
# @param path - путь к файлу (без расширения) - string
# @param format - формат сохраняемого растра в соответствии с требованиями функции writeRaster() - string
# @param datatype - тип данных сохраняемого растра в соответствии с требованиями функции to writeRaster() - string
writeRaster(raster,
path,
format = format,
datatype = datatype,
overwrite = T)
}
Результаты и обсуждение
Посмотрим на результат работы скрипта.
Результат можно сравнить с результатом паншарпенинга в Orfeo TollBox:
Мы видим, что картинка, производимая нашим алгоритмом выглядит как-будто она обработана фильтром, увеличивающим резкость. Кроме того, на ней легче различить оттенки, чем на той, которая является результатом работы OTB. Если копать глубже, то выяснится, что OTB сохранил диапазон значений исходного (очевидно, происходит нормализация данных на одном из этапов обработки), тогда как после использования нашего скрипта диапазон значений пикселей мультиспектрального снимка изменился кардинально, см. рисунки ниже. После паншарпенинга в R очень большое количество пикселей получили значения более 1000. Это означает, что растр после паншарпенинга в OTB потенциально может быть использован для последующей радиометрической калибровки, а после паншарпенинга нашим скриптом - нет. Однако указанные различия в результатах работы нашего скрипта и OTB следует считать не недостатками, а особенностями, которые следует учитывать в работе.
К очевидным же недостаткам использования R относится низкая скорость обработки изображений. К сожалению, в 'raster' не реализована многопоточность, поэтому производительность операций по обработке больших растров оставляет желать лучшего.
Заключение
В данной статье было продемонстрировано создание элементарного скрипта для паншарпенинга в R. Отталкиваясь от приведённых здесь функций вы можете создавать собственные алгоритмы паншарпенинга или реализовывать чужие. К преимуществам использования R для паншарпенинга следует отнести широкий простор для кастомизации и творчества, а к недостаткам - низкую производительность, вызванную отсутствием многопоточности.
Ссылки по теме
Паншарпенинг в QGIS с использованием Orfeo ToolBox
Обработка и интерпретация данных Landsat 8 (OLI) средствами GRASS GIS 7 [раздел Паншарпенинг в GRASS]