Паншарпенинг при помощи R: различия между версиями

Материал из GIS-Lab
Перейти к навигации Перейти к поиску
Нет описания правки
Нет описания правки
 
(не показано 15 промежуточных версий 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 - объект типа Raster с тремя каналами: 1)с низким разрешением, 2) с высоким разрешением, 3) низкочастотная компонента растра с высоким разрешением
     # @param raster - объект класса Raster с тремя каналами: 1)с низким разрешением, 2) с высоким разрешением, 3) низкочастотная компонента растра с высоким разрешением
     # @return pansharpened_raster - подвергшийся паншарпенингу  объект типа 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 - растр с высоким разрешением, объект типа Raster
     # @param pan - растр с высоким разрешением, объект класса Raster
     # @param multi - растр с низким разрешением, который в последствии будет подвергнут паншарпенингу, объект типа Raster
     # @param multi - растр с низким разрешением, который в последствии будет подвергнут паншарпенингу, объект класса Raster
     # @param filter - скользящее окно, объект типа матрица
     # @param filter - скользящее окно, объект класса матрица
     # @param fun - функция, которая производит вычисления на скользящем окне (параметр функции focal() )
     # @param fun - функция, которая производит вычисления на скользящем окне (параметр функции focal() )
     # @return LPF - низкочатотная компонента растра с высоким разрешением, объект типа Raster
     # @return LPF - низкочатотная компонента растра с высоким разрешением, объект класса Raster
      
      
     # Расчитаем размер скользящего окна, если его параметры не заданы
     # Расчитаем размер скользящего окна, если его параметры не заданы
Строка 83: Строка 83:
processingPansharp <- function(pan, multi, filter = 'auto', fun = mean){
processingPansharp <- function(pan, multi, filter = 'auto', fun = mean){
     ' Улучшает разрешение мультиспектрального растра за счёт панхроматического растра '
     ' Улучшает разрешение мультиспектрального растра за счёт панхроматического растра '
     # @param pan - растр с высоким разрешением, объект типа Raster
     # @param pan - растр с высоким разрешением, объект класса Raster
     # @param multi - растр с низким разрешением, чьё разрешение необходимо улучшить, объект типа Raster
     # @param multi - растр с низким разрешением, чьё разрешение необходимо улучшить, объект класса Raster
     # @param filter - скользящее окно, объект типа матрица
     # @param filter - скользящее окно, объект класса матрица
     # @param fun - функция, которая производит вычисления на скользящем окне (параметр функции focal() )
     # @param fun - функция, которая производит вычисления на скользящем окне (параметр функции focal() )
     # @return pansharp - растер 'multi' с улучшенным разрешением, объект типа Raster
     # @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>
==Результаты и обсуждение==
==Результаты и обсуждение==
К сожалению, в raster не реализована многопоточность, поэтому производительность операций по обработке больших растров оставляет желать лучшего.
Посмотрим на результат работы скрипта.
==Скрипт для Processing Tollbox в QGIS==
[[Файл:Initial panchrome.png|thumb|center|x700px|Пахроматический растр с пространственным разрешением 0,5 м]]
[[Файл:Initial multi.png|thumb|center|x700px|Мультиспектральный растр с пространственным разрешением 2,0 м]]
[[Файл:R pansharp result.png|thumb|center|x700px|Мультиспектральный растр после паншарпенинга в R]]
Результат можно сравнить с [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''. Если копать глубже, то выяснится, что ''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 (панхроматический снимок, обработанный сглаживающим фильтром с окном, соответствующим размеру пикселя изображения с низким разрешением):

Formula OTB pansharpening.png

где 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)
}

Результаты и обсуждение

Посмотрим на результат работы скрипта.

Пахроматический растр с пространственным разрешением 0,5 м
Мультиспектральный растр с пространственным разрешением 2,0 м
Мультиспектральный растр после паншарпенинга в R

Результат можно сравнить с результатом паншарпенинга в Orfeo TollBox:

Мультиспектральный растр после паншарпенинга при помощи OTB

Мы видим, что картинка, производимая нашим алгоритмом выглядит как-будто она обработана фильтром, увеличивающим резкость. Кроме того, на ней легче различить оттенки, чем на той, которая является результатом работы OTB. Если копать глубже, то выяснится, что OTB сохранил диапазон значений исходного (очевидно, происходит нормализация данных на одном из этапов обработки), тогда как после использования нашего скрипта диапазон значений пикселей мультиспектрального снимка изменился кардинально, см. рисунки ниже. После паншарпенинга в R очень большое количество пикселей получили значения более 1000. Это означает, что растр после паншарпенинга в OTB потенциально может быть использован для последующей радиометрической калибровки, а после паншарпенинга нашим скриптом - нет. Однако указанные различия в результатах работы нашего скрипта и OTB следует считать не недостатками, а особенностями, которые следует учитывать в работе.

Гистограмма оригинального мультиспектрального растра
Гистограмма мультиспектрального растра после паншарпенинга в R
Гистограмма мультиспектрального растра послепаншарпенинга в OTB

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

Заключение

В данной статье было продемонстрировано создание элементарного скрипта для паншарпенинга в R. Отталкиваясь от приведённых здесь функций вы можете создавать собственные алгоритмы паншарпенинга или реализовывать чужие. К преимуществам использования R для паншарпенинга следует отнести широкий простор для кастомизации и творчества, а к недостаткам - низкую производительность, вызванную отсутствием многопоточности.

Ссылки по теме

Паншарпенинг в QGIS с использованием Orfeo ToolBox

Паншарпенинг в ERDAS

Обработка и интерпретация данных Landsat 8 (OLI) средствами GRASS GIS 7 [раздел Паншарпенинг в GRASS]

Геопроцессинг с SEXTANTE для QGIS